more work on image reads
This commit is contained in:
parent
3aede05d1b
commit
6695575762
5
.autotest
Normal file
5
.autotest
Normal file
@ -0,0 +1,5 @@
|
||||
Autotest.add_hook :initialize do |at|
|
||||
at.add_mapping(%r{^spec/sample_files/([^/]+)/.*}, true) { |_, m|
|
||||
"spec/avm/#{m[1]}_spec.rb"
|
||||
}
|
||||
end
|
1
.rspec
1
.rspec
@ -3,4 +3,3 @@
|
||||
--format progress
|
||||
--format RSpec::Core::Formatters::QuickFixFormatter
|
||||
--out .quickfix.txt
|
||||
|
||||
|
@ -1,8 +1,13 @@
|
||||
require 'avm/creator'
|
||||
require 'avm/xmp'
|
||||
require 'avm/image_type'
|
||||
require 'avm/image_quality'
|
||||
|
||||
module AVM
|
||||
class Image
|
||||
DUBLIN_CORE_FIELDS = [ :title, :description ]
|
||||
AVM_SINGLE_FIELDS = [ 'Distance.Notes', 'ReferenceURL', 'Credit', 'Date', 'ID', 'Type', 'Image.ProductQuality' ]
|
||||
|
||||
attr_reader :creator
|
||||
|
||||
def initialize(options = {})
|
||||
@ -16,20 +21,25 @@ module AVM
|
||||
creator.add_to_document(document)
|
||||
|
||||
document.get_refs do |refs|
|
||||
[ :title, :description ].each do |field|
|
||||
DUBLIN_CORE_FIELDS.each do |field|
|
||||
refs[:dublin_core].add_child(%{<dc:#{field}>#{alt_li_tag(send(field))}</dc:#{field}>})
|
||||
end
|
||||
|
||||
refs[:photoshop].add_child(%{<photoshop:Headline>#{headline}</photoshop:Headline>})
|
||||
|
||||
{
|
||||
'Distance.Notes' => distance_notes,
|
||||
'ReferenceURL' => reference_url,
|
||||
'Credit' => credit,
|
||||
'Date' => string_date,
|
||||
'ID' => id,
|
||||
}.each do |tag, value|
|
||||
refs[:avm].add_child(%{<avm:#{tag}>#{value}</avm:#{tag}>}) if value
|
||||
AVM_SINGLE_FIELDS.zip([distance_notes, reference_url, credit, string_date, id, image_type, image_quality]).each do |tag, value|
|
||||
refs[:avm].add_child(%{<avm:#{tag}>#{value.to_s}</avm:#{tag}>}) if value
|
||||
end
|
||||
|
||||
distance_nodes = []
|
||||
distance_nodes << rdf_li(light_years) if light_years
|
||||
if redshift
|
||||
distance_nodes << rdf_li('-') if distance_nodes.empty?
|
||||
distance_nodes << rdf_li(redshift)
|
||||
end
|
||||
|
||||
if !distance_nodes.empty?
|
||||
refs[:avm].add_child(%{<avm:Distance><rdf:Seq>#{distance_nodes.join}</rdf:Seq></avm:Distance>})
|
||||
end
|
||||
end
|
||||
|
||||
@ -41,7 +51,11 @@ module AVM
|
||||
end
|
||||
|
||||
def image_type
|
||||
@options[:type]
|
||||
(AVM::ImageType.const_get(@options[:type].to_sym).new rescue nil)
|
||||
end
|
||||
|
||||
def image_quality
|
||||
(AVM::ImageQuality.const_get(@options[:quality].to_sym).new rescue nil)
|
||||
end
|
||||
|
||||
def date
|
||||
@ -60,7 +74,39 @@ module AVM
|
||||
def self.from_xml(string)
|
||||
document = AVM::XMP.from_string(string)
|
||||
|
||||
image = new
|
||||
options = {}
|
||||
|
||||
document.get_refs do |refs|
|
||||
DUBLIN_CORE_FIELDS.each do |field|
|
||||
if node = refs[:dublin_core].at_xpath(".//dc:#{field}//rdf:li[1]")
|
||||
options[field] = node.text
|
||||
end
|
||||
end
|
||||
|
||||
AVM_SINGLE_FIELDS.zip([ :distance_notes, :reference_url, :credit, :date, :id, :type, :quality ]).each do |tag, field|
|
||||
if node = refs[:avm].at_xpath("./avm:#{tag}")
|
||||
options[field] = node.text
|
||||
end
|
||||
end
|
||||
|
||||
if node = refs[:photoshop].at_xpath('./photoshop:Headline')
|
||||
options[:headline] = node.text
|
||||
end
|
||||
|
||||
if node = refs[:avm].at_xpath('./avm:Distance')
|
||||
list_values = node.search('.//ref:li').collect { |li| li.text }
|
||||
|
||||
case list_values.length
|
||||
when 1
|
||||
options[:light_years] = list_values.first
|
||||
when 2
|
||||
options[:light_years] = (list_values.first == '-') ? nil : list_values.first
|
||||
options[:redshift] = list_valueslast
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
image = new(options)
|
||||
image.creator.from_xml(self, document)
|
||||
image
|
||||
end
|
||||
@ -73,6 +119,10 @@ module AVM
|
||||
def alt_li_tag(text)
|
||||
%{<rdf:Alt><rdf:li xml:lang="x-default">#{text}</rdf:li></rdf:Alt>}
|
||||
end
|
||||
|
||||
def rdf_li(text)
|
||||
%{<rdf:li>#{text}</rdf:li>}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
14
lib/avm/image_quality.rb
Normal file
14
lib/avm/image_quality.rb
Normal file
@ -0,0 +1,14 @@
|
||||
module AVM
|
||||
module ImageQuality
|
||||
%w{Good Moderate Poor}.each do |type|
|
||||
klass = Class.new do
|
||||
def to_s
|
||||
self.class.to_s.split('::').last
|
||||
end
|
||||
end
|
||||
|
||||
AVM::ImageQuality.const_set(type.to_sym, klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
14
lib/avm/image_type.rb
Normal file
14
lib/avm/image_type.rb
Normal file
@ -0,0 +1,14 @@
|
||||
module AVM
|
||||
module ImageType
|
||||
%w{Observation Artwork Photographic Planetary Simulation Chart Collage}.each do |type|
|
||||
klass = Class.new do
|
||||
def to_s
|
||||
self.class.to_s.split('::').last
|
||||
end
|
||||
end
|
||||
|
||||
AVM::ImageType.const_set(type.to_sym, klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -5,7 +5,8 @@ module AVM
|
||||
PREFIXES = {
|
||||
'dc' => 'Dublin Core',
|
||||
'Iptc4xmpCore' => 'IPTC',
|
||||
'Photoshop' => 'Photoshop'
|
||||
'photoshop' => 'Photoshop',
|
||||
'avm' => 'AVM'
|
||||
}
|
||||
|
||||
attr_reader :doc
|
||||
@ -39,13 +40,24 @@ module AVM
|
||||
end
|
||||
|
||||
def ensure_descriptions_findable!
|
||||
added = []
|
||||
|
||||
doc.search('//rdf:Description').each do |description|
|
||||
if first_child = description.first_element_child
|
||||
if first_child.namespace
|
||||
description['about'] = PREFIXES[first_child.namespace.prefix]
|
||||
prefix = first_child.namespace.prefix
|
||||
|
||||
description['rdf:about'] = PREFIXES[prefix]
|
||||
added << prefix
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PREFIXES.each do |prefix, about|
|
||||
if !added.include?(prefix)
|
||||
doc.at_xpath('//rdf:RDF').add_child(%{<rdf:Description rdf:about="#{about}" />})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def dublin_core
|
||||
@ -65,17 +77,17 @@ module AVM
|
||||
end
|
||||
|
||||
def at_rdf_description(about)
|
||||
@doc.at_xpath(%{//rdf:Description[@about="#{about}"]})
|
||||
@doc.at_xpath(%{//rdf:Description[@rdf:about="#{about}"]})
|
||||
end
|
||||
|
||||
def empty_xml_doc
|
||||
Nokogiri::XML(<<-XML)
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:RDF>
|
||||
<rdf:Description about="Dublin Core" />
|
||||
<rdf:Description about="IPTC" />
|
||||
<rdf:Description about="Photoshop" />
|
||||
<rdf:Description about="AVM" />
|
||||
<rdf:Description rdf:about="Dublin Core" />
|
||||
<rdf:Description rdf:about="IPTC" />
|
||||
<rdf:Description rdf:about="Photoshop" />
|
||||
<rdf:Description rdf:about="AVM" />
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
XML
|
||||
|
@ -15,7 +15,7 @@ describe AVM::Image do
|
||||
let(:credit) { 'Credit' }
|
||||
let(:date) { '2010-01-01' }
|
||||
let(:id) { 'ID' }
|
||||
let(:type) { 'Obvservation' }
|
||||
let(:type) { 'Observation' }
|
||||
let(:image_quality) { 'Good' }
|
||||
let(:redshift) { 'Redshift' }
|
||||
let(:light_years) { 'Light years' }
|
||||
@ -31,17 +31,13 @@ describe AVM::Image do
|
||||
:date => date,
|
||||
:id => id,
|
||||
:type => type,
|
||||
:image_quality => image_quality,
|
||||
:quality => image_quality,
|
||||
:redshift => redshift,
|
||||
:light_years => light_years
|
||||
} }
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
with_all_options
|
||||
|
||||
it { should be_a_kind_of(AVM::Image) }
|
||||
|
||||
def self.has_most_options
|
||||
its(:creator) { should be_a_kind_of(AVM::Creator) }
|
||||
its(:title) { should == title }
|
||||
its(:headline) { should == headline }
|
||||
@ -51,20 +47,74 @@ describe AVM::Image do
|
||||
its(:credit) { should == credit }
|
||||
its(:date) { should == Time.parse(date) }
|
||||
its(:id) { should == id }
|
||||
its(:image_type) { should == type }
|
||||
its(:image_quality) { should == image_quality }
|
||||
its(:redshift) { should == redshift }
|
||||
its(:light_years) { should == light_years }
|
||||
its(:image_type) { should be_a_kind_of eval("AVM::ImageType::#{type}") }
|
||||
its(:image_quality) { should be_a_kind_of eval("AVM::ImageQuality::#{image_quality}") }
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
with_all_options
|
||||
|
||||
it { should be_a_kind_of(AVM::Image) }
|
||||
|
||||
has_most_options
|
||||
|
||||
its(:distance) { should == [ light_years, redshift ] }
|
||||
end
|
||||
|
||||
describe '.from_xml' do
|
||||
let(:image) { AVM::Image.from_xml(File.read(file_path)) }
|
||||
|
||||
subject { image }
|
||||
|
||||
context "nothing in it" do
|
||||
let(:file_path) { 'spec/sample_files/image/nothing.xmp' }
|
||||
|
||||
its(:title) { should be_nil }
|
||||
its(:headline) { should be_nil }
|
||||
its(:description) { should be_nil }
|
||||
its(:distance_notes) { should be_nil }
|
||||
its(:reference_url) { should be_nil }
|
||||
its(:credit) { should be_nil }
|
||||
its(:date) { should be_nil }
|
||||
its(:id) { should be_nil }
|
||||
its(:image_type) { should be_nil }
|
||||
its(:image_quality) { should be_nil }
|
||||
its(:redshift) { should be_nil }
|
||||
its(:light_years) { should be_nil }
|
||||
end
|
||||
|
||||
context "image in it" do
|
||||
context "distance in light years" do
|
||||
let(:file_path) { 'spec/sample_files/image/light_years.xmp' }
|
||||
|
||||
has_most_options
|
||||
|
||||
its(:redshift) { should be_nil }
|
||||
end
|
||||
|
||||
context "distaince in redshift" do
|
||||
|
||||
let(:file_path) { 'spec/sample_files/image/redshift.xmp' }
|
||||
end
|
||||
context "distance in both" do
|
||||
|
||||
let(:file_path) { 'spec/sample_files/image/both.xmp' }
|
||||
|
||||
end
|
||||
context "distance in neither" do
|
||||
|
||||
let(:file_path) { 'spec/sample_files/image/neither.xmp' }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '#to_xml' do
|
||||
let(:xml) { image.to_xml }
|
||||
|
||||
let(:dublin_core) { xml.at_xpath('//rdf:Description[@about="Dublin Core"]') }
|
||||
let(:photoshop) { xml.at_xpath('//rdf:Description[@about="Photoshop"]') }
|
||||
let(:avm) { xml.at_xpath('//rdf:Description[@about="AVM"]') }
|
||||
let(:dublin_core) { xml.at_xpath('//rdf:Description[@rdf:about="Dublin Core"]') }
|
||||
let(:photoshop) { xml.at_xpath('//rdf:Description[@rdf:about="Photoshop"]') }
|
||||
let(:avm) { xml.at_xpath('//rdf:Description[@rdf:about="AVM"]') }
|
||||
|
||||
context 'nothing in it' do
|
||||
it "should have basic tags" do
|
||||
@ -87,23 +137,35 @@ describe AVM::Image do
|
||||
avm.at_xpath('./avm:Credit').text.should == credit
|
||||
avm.at_xpath('./avm:Date').text.should == date
|
||||
avm.at_xpath('./avm:ID').text.should == id
|
||||
avm.at_xpath('./avm:Type').text.should == type
|
||||
avm.at_xpath('./avm:Image.ProductQuality').text.should == image_quality
|
||||
end
|
||||
|
||||
context "distance" do
|
||||
context "no distances" do
|
||||
let(:redshift) { nil }
|
||||
let(:light_years) { nil }
|
||||
|
||||
specify { avm.at_xpath('./avm:Distance').should be_nil }
|
||||
end
|
||||
|
||||
context "redshift only" do
|
||||
let(:light_years) { nil }
|
||||
|
||||
specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[1]').text.should == '-' }
|
||||
specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[2]').text.should == redshift }
|
||||
end
|
||||
|
||||
context "light years only" do
|
||||
let(:redshift) { nil }
|
||||
|
||||
specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[1]').text.should == light_years }
|
||||
specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[2]').should be_nil }
|
||||
end
|
||||
|
||||
context "redshift and light years" do
|
||||
|
||||
specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[1]').text.should == light_years }
|
||||
specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[2]').text.should == redshift }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -12,18 +12,21 @@ describe AVM::XMP do
|
||||
refs[:dublin_core] << "<rdf:addedToDublinCore />"
|
||||
refs[:iptc] << "<rdf:addedToIPTC />"
|
||||
refs[:photoshop] << '<rdf:addedToPhotoshop />'
|
||||
refs[:avm] << '<rdf:addedToAVM />'
|
||||
end
|
||||
}
|
||||
|
||||
it "should have gotten the refs correctly" do
|
||||
xmp.doc.at_xpath('//rdf:Description[@about="Dublin Core"]//rdf:addedToDublinCore').should_not be_nil
|
||||
xmp.doc.at_xpath('//rdf:Description[@about="IPTC"]//rdf:addedToIPTC').should_not be_nil
|
||||
xmp.doc.at_xpath('//rdf:Description[@rdf:about="Dublin Core"]//rdf:addedToDublinCore').should_not be_nil
|
||||
xmp.doc.at_xpath('//rdf:Description[@rdf:about="IPTC"]//rdf:addedToIPTC').should_not be_nil
|
||||
xmp.doc.at_xpath('//rdf:Description[@rdf:about="Photoshop"]//rdf:addedToPhotoshop').should_not be_nil
|
||||
xmp.doc.at_xpath('//rdf:Description[@rdf:about="AVM"]//rdf:addedToAVM').should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '.from_string' do
|
||||
let(:xmp) { self.class.describes.from_string(string) }
|
||||
let(:string) { '<xml><node /></xml>' }
|
||||
let(:string) { '<xml xmlns:rdf="cats"><rdf:RDF><node /></rdf:RDF></xml>' }
|
||||
|
||||
specify { xmp.doc.at_xpath('//node').should_not be_nil }
|
||||
end
|
||||
@ -42,8 +45,8 @@ describe AVM::XMP do
|
||||
context 'no nodes within' do
|
||||
let(:content) { '' }
|
||||
|
||||
[ 'Dublin Core', 'IPTC' ].each do |which|
|
||||
specify { xmp.doc.at_xpath(%{//rdf:Description[@about="#{which}"]}).should be_nil }
|
||||
[ 'Dublin Core', 'IPTC', 'Photoshop', 'AVM' ].each do |which|
|
||||
specify { xmp.doc.at_xpath(%{//rdf:Description[@rdf:about="#{which}"]}).children.should be_empty }
|
||||
end
|
||||
end
|
||||
|
||||
@ -54,11 +57,17 @@ describe AVM::XMP do
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about="" xmlns:Iptc4xmpCore="http://itpc.org/stf/Iptc4xmpCore/1.0/xmlns/">
|
||||
<Iptc4xmpCore:CreatorContactInfo rdf:parseType="Resource" />
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about="" xmlns:Photoshop="http://ns.adobe.com/photoshop/1.0/">
|
||||
<photoshop:Something />
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about="" xmlns:avm="http://www.communicatingastronomy.org/avm/1.0/">
|
||||
<avm:Something />
|
||||
</rdf:Description>
|
||||
XML
|
||||
|
||||
[ 'Dublin Core', 'IPTC' ].each do |which|
|
||||
specify { xmp.doc.at_xpath(%{//rdf:Description[@about="#{which}"]}).should_not be_nil }
|
||||
[ 'Dublin Core', 'IPTC', 'Photoshop', 'AVM' ].each do |which|
|
||||
specify { xmp.doc.at_xpath(%{//rdf:Description[@rdf:about="#{which}"]}).should_not be_nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
37
spec/sample_files/image/light_years.xmp
Normal file
37
spec/sample_files/image/light_years.xmp
Normal file
@ -0,0 +1,37 @@
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.352624, 2008/07/30-18:05:41 ">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<dc:title>:
|
||||
<rdf:Alt>
|
||||
<rdf:li xml:lang="x-default">My title</rdf:li>
|
||||
</rdf:Alt>
|
||||
</dc:title>
|
||||
<dc:description>
|
||||
<rdf:Alt>
|
||||
<rdf:li xml:lang="x-default">Description</rdf:li>
|
||||
</rdf:Alt>
|
||||
</dc:description>
|
||||
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/">
|
||||
<Iptc4xmpCore:CreatorContactInfo rdf:parseType="Resource">
|
||||
</Iptc4xmpCore:CreatorContactInfo>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
|
||||
<photoshop:Headline>Headline</photoshop:Headline>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:avm="http://www.communicatingastronomy.org/avm/1.0/">
|
||||
<avm:Distance.Notes>Distance Notes</avm:Distance.Notes>
|
||||
<avm:ReferenceURL>Reference URL</avm:ReferenceURL>
|
||||
<avm:Credit>Credit</avm:Credit>
|
||||
<avm:Date>2010-01-01</avm:Date>
|
||||
<avm:ID>ID</avm:ID>
|
||||
<avm:Type>Observation</avm:Type>
|
||||
<avm:Image.ProductQuality>Good</avm:Image.ProductQuality>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
18
spec/sample_files/image/nothing.xmp
Normal file
18
spec/sample_files/image/nothing.xmp
Normal file
@ -0,0 +1,18 @@
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.352624, 2008/07/30-18:05:41 ">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<dc:creator />
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/">
|
||||
<Iptc4xmpCore:CreatorContactInfo rdf:parseType="Resource">
|
||||
</Iptc4xmpCore:CreatorContactInfo>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
|
||||
<photoshop:ColorMode />
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
|
Loading…
Reference in New Issue
Block a user