assembly-objectfile 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc.example +1 -0
  4. data/Gemfile +5 -0
  5. data/README.rdoc +94 -0
  6. data/Rakefile +4 -0
  7. data/assembly-objectfile.gemspec +29 -0
  8. data/bin/console +8 -0
  9. data/bin/run_all_tests +3 -0
  10. data/config/boot.rb +9 -0
  11. data/lib/assembly-objectfile.rb +35 -0
  12. data/lib/assembly-objectfile/content_metadata.rb +229 -0
  13. data/lib/assembly-objectfile/object_file.rb +30 -0
  14. data/lib/assembly-objectfile/object_fileable.rb +263 -0
  15. data/lib/assembly-objectfile/version.rb +9 -0
  16. data/profiles/AdobeRGB1998.icc +0 -0
  17. data/profiles/DotGain20.icc +0 -0
  18. data/profiles/sRGBIEC6196621.icc +0 -0
  19. data/spec/content_metadata_spec.rb +563 -0
  20. data/spec/object_file_spec.rb +115 -0
  21. data/spec/spec_helper.rb +46 -0
  22. data/spec/test_data/input/.empty +0 -0
  23. data/spec/test_data/input/file_with_no_exif.xml +83 -0
  24. data/spec/test_data/input/oo000oo0001/00/oo000oo0001_00_001.tif +0 -0
  25. data/spec/test_data/input/oo000oo0001/00/oo000oo0001_00_002.tif +0 -0
  26. data/spec/test_data/input/oo000oo0001/05/oo000oo0001_05_001.jp2 +0 -0
  27. data/spec/test_data/input/oo000oo0001/05/oo000oo0001_05_002.jp2 +0 -0
  28. data/spec/test_data/input/oo000oo0001/15/oo000oo0001_15_001.pdf +1 -0
  29. data/spec/test_data/input/oo000oo0001/15/oo000oo0001_15_002.pdf +1 -0
  30. data/spec/test_data/input/oo000oo0001/31/oo000oo0001_31_001.pdf +1 -0
  31. data/spec/test_data/input/oo000oo0001/50/oo000oo0001_50_001.tif +0 -0
  32. data/spec/test_data/input/oo000oo0001/oo000oo0001_book.pdf +1 -0
  33. data/spec/test_data/input/res1_image1.jp2 +0 -0
  34. data/spec/test_data/input/res1_image1.tif +0 -0
  35. data/spec/test_data/input/res1_image2.jp2 +0 -0
  36. data/spec/test_data/input/res1_image2.tif +0 -0
  37. data/spec/test_data/input/res1_teifile.txt +1 -0
  38. data/spec/test_data/input/res1_textfile.txt +1 -0
  39. data/spec/test_data/input/res1_transcript.pdf +1 -0
  40. data/spec/test_data/input/res2_image1.jp2 +0 -0
  41. data/spec/test_data/input/res2_image1.tif +0 -0
  42. data/spec/test_data/input/res2_image2.jp2 +0 -0
  43. data/spec/test_data/input/res2_image2.tif +0 -0
  44. data/spec/test_data/input/res2_teifile.txt +1 -0
  45. data/spec/test_data/input/res2_textfile.txt +1 -0
  46. data/spec/test_data/input/res3_image1.jp2 +0 -0
  47. data/spec/test_data/input/res3_image1.tif +0 -0
  48. data/spec/test_data/input/res3_teifile.txt +1 -0
  49. data/spec/test_data/input/test.jp2 +0 -0
  50. data/spec/test_data/input/test.pdf +1 -0
  51. data/spec/test_data/input/test.tif +0 -0
  52. data/spec/test_data/input/test2.jp2 +0 -0
  53. data/spec/test_data/input/test2.tif +0 -0
  54. metadata +260 -0
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ .rvmrc
2
+ *.gem
3
+ .DS_Store
4
+ .bundle
5
+ Gemfile.lock
6
+ config/certs/*
7
+ config/environments/*
8
+ doc/*
9
+ log/*
10
+ pkg/*
11
+ tags
12
+ tmp
13
+ .yardoc/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -r spec/spec_helper.rb
data/.rvmrc.example ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.8.7@assembly-objectfile --create
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+ source "http://sul-gems.stanford.edu"
3
+
4
+ # Specify your gem's dependencies in .gemspec
5
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,94 @@
1
+ = Assembly-ObjectFile Gem
2
+
3
+ ==Overview
4
+ This gem contains classes used by the Stanford University Digital Library to perform
5
+ file operations necessary for accessioning of content. It is also used by related gems to perform
6
+ content type specific operations (such as jp2 generation).
7
+
8
+ ==Releases
9
+
10
+ - 1.0.0 initial release
11
+ - 1.0.1 add in a valid_image? method
12
+ - 1.0.2 add new mimetype and encoding methods
13
+ - 1.0.3 add new object_type method
14
+ - 1.0.4 add additional configuration parameters that are used by assembly and other consumers of the gem
15
+ - 1.0.5 try and get mimetype from exif before resorting to unix level file command
16
+ - 1.1.0 add methods to compute sha1 and md5 for object using checksum-tools gem
17
+ - 1.1.1 change computation of mimetype and encoding to work in more situations
18
+ - 1.1.2 change jp2able? and image? methods so they return a file not found error if the file is not supplied, added a method to indicate if a file is found
19
+ - 1.1.3 prepare for release listing on DLSS release board
20
+ - 1.1.4 valid_image? will now return true for jp2 mimetypes
21
+ - 1.1.5 valid_image? should be false if mimetype is correct but profile is not found
22
+ - 1.1.6 add jp2able? method
23
+ - 1.1.7 change the behavior of jp2able? and valid_image?
24
+ - 1.1.8 update how the version number is set to allow users to see the gem version # more easily
25
+ - 1.1.9 switch jpeg mimetype temporarily to publish=no, preserve=yes
26
+ - 1.2.0 move content metadata generation method to this gem from assembly-image
27
+ - 1.2.1 allow content metadata to add user supplied checksums
28
+ - 1.2.2 allow content metadata to bundle files into resources by filename or DPG filename specification, add book_as_image and file style content metadata generation
29
+ - 1.2.3 small change to a parameter passed to content metadata generation
30
+ - 1.2.4 allow user to control how file ID paths are generated in content metadata by using a 'relative_path' attribute
31
+ - 1.2.5 add a class method to find the common directory between an array of filenames passed in
32
+ - 1.2.6 bug fix in content metadata generation, and allow book types to have single <file> resource nodes if they do not contain any images
33
+ - 1.2.8 remove dependency on ChecksumTools gem to make it Ruby 1.9 compatible
34
+ - 1.2.9 automatically strip druid: prefix in content metadata generation method
35
+ - 1.2.10 bug fix
36
+ - 1.2.11 add ability to suppress <xml> tag from generated contentMetadata
37
+ - 1.3.0 continued refinement of content metadata generation for objects with download
38
+ - 1.3.1 allow the user specify a label with the ObjectFile object that is picked up when generating content metadata (in specifying resource labels)
39
+ - 1.3.2 allow the user to set the label on object creation
40
+ - 1.3.3 update tests to avoid dependency on kakadu; contentMetadata will now generate new resources of type=object when files are present in special DPG folders
41
+ - 1.3.4 fix rspec test to have it run on CI server
42
+ - 1.3.5 add a parameter to flatten folder structure when creating file IDs; increment resource labels by object type
43
+ - 1.3.6 allow user to supply default file attributes as well as by mimetype --- useful if file attributes should be added and are the same regardless of mimetype
44
+ - 1.3.7 add a new bundle style called "prebundled" which allows users to pass in an array of arrays
45
+ - 1.3.8 update to latest lyberteam devel gems
46
+ - 1.3.9 compute md5 and sha1 separately when needed
47
+ - 1.4.0 compute mimetype correctly even if exif information in a file is damaged
48
+ - 1.4.1 fix errors that could error if there was a space in the filename
49
+ - 1.4.2 Support map style content metadata; don't compute mimetype when generating content metadata unless its needed
50
+ - 1.4.3 object_type method should return :other if it is an unknown mimetype
51
+ - 1.4.4 produce blank content metadata if no objects are passed in
52
+ - 1.4.5 allow the user to supply optional file specific attributes for publish, preserve, shelve for creating content metadata
53
+ - 1.4.6 add dirname attribute to objectfile class
54
+ - 1.4.7 add an additional default mimetype for file perservation attributes
55
+ - 1.4.8 compute mimetype with file unix command by default, and then check for existence of mimetype in exif unless we have a "trusted" mimetype
56
+ - 1.4.9 update list of trusted mimetypes
57
+ - 1.5.0 add the ability to skip auto label generation for resources if no labels are supplied
58
+
59
+ ==Usage
60
+
61
+ The gem currently has methods for:
62
+ - filesize
63
+ - exif
64
+ - generate content metadata
65
+
66
+ ==Running tests
67
+
68
+ bundle exec rspec spec
69
+
70
+ ==Generate documentation
71
+ To generate documentation into the "doc" folder:
72
+
73
+ yard
74
+
75
+ To keep a local server running with up to date code documentation that you can view in your browser:
76
+
77
+ yard server --reload
78
+
79
+ ==Prerequisites
80
+
81
+ 1. Exiftool
82
+
83
+ RHEL: (RPM to install comming soon)
84
+ Download latest version from: http://www.sno.phy.queensu.ca/~phil/exiftool
85
+
86
+ tar -xf Image-ExifTool-#.##.tar.gz
87
+ cd Image-ExifTool-#.##
88
+ perl Makefile.PL
89
+ make test
90
+ sudo make install
91
+
92
+ Mac users:
93
+ brew install exiftool
94
+
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'dlss/rake/dlss_release'
4
+ Dlss::Release.new
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
2
+ require 'assembly-objectfile/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'assembly-objectfile'
6
+ s.version = Assembly::ObjectFile::VERSION
7
+ s.authors = ["Peter Mangiafico", "Renzo Sanchez-Silva","Monty Hindman","Tony Calavano"]
8
+ s.email = ["pmangiafico@stanford.edu"]
9
+ s.homepage = ""
10
+ s.summary = %q{Ruby immplementation of file services needed to prepare objects to be accessioned in SULAIR digital library}
11
+ s.description = %q{Get exif data, file sizes and more.}
12
+
13
+ s.rubyforge_project = 'assembly-objectfile'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_dependency 'mini_exiftool'
21
+ s.add_dependency 'mime-types'
22
+ s.add_dependency 'nokogiri'
23
+
24
+ s.add_development_dependency "rspec", "~> 2.6"
25
+ s.add_development_dependency "lyberteam-devel", '>= 1.0.1'
26
+ s.add_development_dependency "lyberteam-gems-devel", "> 1.0.0"
27
+ s.add_development_dependency "yard"
28
+
29
+ end
data/bin/console ADDED
@@ -0,0 +1,8 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'irb'
5
+
6
+ require File.expand_path(File.dirname(__FILE__) + '/../config/boot')
7
+
8
+ IRB.start
data/bin/run_all_tests ADDED
@@ -0,0 +1,3 @@
1
+ #! /bin/bash
2
+
3
+ bundle exec rspec spec
data/config/boot.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+
3
+ environment = ENV['ENVIRONMENT'] ||= 'development'
4
+ project_root = File.expand_path(File.dirname(__FILE__) + '/..')
5
+
6
+ # Load config for current environment.
7
+ $LOAD_PATH.unshift(project_root + '/lib')
8
+
9
+ require 'assembly-objectfile'
@@ -0,0 +1,35 @@
1
+ module Assembly
2
+
3
+ # the path to the gem, used to access profiles stored with the gem
4
+ PATH_TO_GEM = File.expand_path(File.dirname(__FILE__) + '/..')
5
+
6
+ # if input image is not one of these mime types, it will not be regarded as a valid image
7
+ VALID_IMAGE_MIMETYPES=["image/jpeg","image/tiff","image/jp2","image/tif"]
8
+
9
+ # the list of mimetypes that will be "trusted" by the unix file command; if a mimetype other than one of these is returned
10
+ # by the file command, then a check will be made to see if exif data exists...if so, the mimetype returned by the exif data will be used
11
+ # if no exif data exists, then the mimetype returned by the unix file command will be used
12
+ TRUSTED_MIMETYPES=["text/plain","plain/text","application/pdf","text/html","application/xml"]
13
+
14
+ # default publish/preserve/shelve attributes used in content metadata
15
+ FILE_ATTRIBUTES=Hash.new
16
+ # if no mimetype specific attributes are specified for a given file, define some defaults, and override for specific mimetypes below
17
+ FILE_ATTRIBUTES['default']={:preserve=>'yes',:shelve=>'no',:publish=>'no'}
18
+ FILE_ATTRIBUTES['image/tif']={:preserve=>'yes',:shelve=>'no',:publish=>'no'}
19
+ FILE_ATTRIBUTES['image/tiff']={:preserve=>'yes',:shelve=>'no',:publish=>'no'}
20
+ FILE_ATTRIBUTES['image/jp2']={:preserve=>'no',:shelve=>'yes',:publish=>'yes'}
21
+ FILE_ATTRIBUTES['image/jpeg']={:preserve=>'yes',:shelve=>'no',:publish=>'no'}
22
+ FILE_ATTRIBUTES['audio/wav']={:preserve=>'yes',:shelve=>'no',:publish=>'no'}
23
+ FILE_ATTRIBUTES['audio/x-wav']={:preserve=>'yes',:shelve=>'no',:publish=>'no'}
24
+ FILE_ATTRIBUTES['audio/mp3']={:preserve=>'no',:shelve=>'yes',:publish=>'yes'}
25
+ FILE_ATTRIBUTES['audio/mpeg']={:preserve=>'no',:shelve=>'yes',:publish=>'yes'}
26
+ FILE_ATTRIBUTES['application/pdf']={:preserve=>'yes',:shelve=>'yes',:publish=>'yes'}
27
+ FILE_ATTRIBUTES['plain/text']={:preserve=>'yes',:shelve=>'yes',:publish=>'yes'}
28
+ FILE_ATTRIBUTES['text/plain']={:preserve=>'yes',:shelve=>'yes',:publish=>'yes'}
29
+
30
+ end
31
+
32
+ require 'assembly-objectfile/content_metadata'
33
+ require 'assembly-objectfile/object_fileable'
34
+ require 'assembly-objectfile/object_file'
35
+ require 'assembly-objectfile/version'
@@ -0,0 +1,229 @@
1
+ require 'nokogiri'
2
+
3
+ module Assembly
4
+
5
+ SPECIAL_DPG_FOLDERS=['31','50'] # these special dpg folders will force any files contained in them into their own resources, regardless of filenaming convention
6
+ # these are used when :bundle=>:dpg only
7
+
8
+ # This class generates content metadata for image files
9
+ class ContentMetadata
10
+
11
+ # Generates image content XML metadata for a repository object.
12
+ # This method only produces content metadata for images
13
+ # and does not depend on a specific folder structure. Note that it is class level method.
14
+ #
15
+ # @param [Hash] params a hash containg parameters needed to produce content metadata
16
+ # :druid = required - a string of druid of the repository object's druid id (with or without 'druid:' prefix)
17
+ # :objects = required - an array of Assembly::ObjectFile objects containing the list of files to add to content metadata
18
+ # NOTE: if you set the :bundle option to "prebundlded", you will need to pass in an array of arrays, and not a flat array, as noted below
19
+ # :style = optional - a symbol containing the style of metadata to create, allowed values are
20
+ # :simple_image (default), contentMetadata type="image", resource type="image"
21
+ # :file, contentMetadata type="file", resource type="file"
22
+ # :simple_book, contentMetadata type="book", resource type="page", but any resource which has file(s) other than an image, and also contains no images at all, will be resource type="object"
23
+ # :book_with_pdf, contentMetadata type="book", resource type="page", but any resource which has any file(s) other than an image will be resource type="object"
24
+ # :book_as_image, as simple_book, but with contentMetadata type="book", resource type="image" (same rule applies for resources with non images)
25
+ # :map, like simple_image, but with contentMetadata type="map", resoruce type="image"
26
+ # :bundle = optional - a symbol containing the method of bundling files into resources, allowed values are
27
+ # :default = all files get their own resources (default)
28
+ # :filename = files with the same filename but different extensions get bundled together in a single resource
29
+ # :dpg = files representing the same image but of different mimetype that use the SULAIR DPG filenaming standard (00 vs 05) get bundled together in a single resource
30
+ # :prebundlded = this option requires you to prebundled the files passed in as an array of arrays, indicating how files are bundlded into resources; this is the most flexible option since it gives you full control
31
+ # :add_exif = optional - a boolean to indicate if exif data should be added (mimetype, filesize, image height/width, etc.) to each file, defaults to false and is not required if project goes through assembly
32
+ # :add_file_attributes = optional - a boolean to indicate if publish/preserve/shelve attributes should be added using defaults or by supplied override by mime/type, defaults to false and is not required if project goes through assembly
33
+ # :file_attributes = optional - a hash of file attributes by mimetype to use instead of defaults, only used if add_file_attributes is also true,
34
+ # If a mimetype match is not found in your hash, the default is used (either your supplied default or the gems).
35
+ # e.g. {'default'=>{:preserve=>'yes',:shelve=>'yes',:publish=>'yes'},'image/tif'=>{:preserve=>'yes',:shelve=>'no',:publish=>'no'},'application/pdf'=>{:preserve=>'yes',:shelve=>'yes',:publish=>'yes'}}
36
+ # :include_root_xml = optional - a boolean to indicate if the contentMetadata returned includes a root <?xml version="1.0"?> tag, defaults to true
37
+ # :preserve_common_paths = optional - When creating the file "id" attribute, content metadata uses the "relative_path" attribute of the ObjectFile objects passed in. If the "relative_path" attribute is not set, the "path" attribute is used instead,
38
+ # which includes a full path to the file. If the "preserve_common_paths" parameter is set to false or left off, then the common paths of all of the ObjectFile's passed in are removed from any "path" attributes. This should turn full paths into
39
+ # the relative paths that are required in content metadata file id nodes. If you do not want this behavior, set "preserve_common_paths" to true. The default it false.
40
+ # :flatten_folder_structure = optional - Will remove *all* folder structure when genearting file IDs (e.g. DPG subfolders like '00','05' will be removed) when generating file IDs. This is useful if the folder structure is flattened when staging files (like for DPG).
41
+ # The default is false. If set to true, will override the "preserve_common_paths" parameter.
42
+ # :auto_labels = optional - Will add automated resource labels (e.g. "File 1") when labels are not provided by the user. The default is true.
43
+ # Example:
44
+ # Assembly::Image.create_content_metadata(:druid=>'druid:nx288wh8889',:style=>:simple_image,:objects=>object_files,:add_file_attributes=>false)
45
+ def self.create_content_metadata(params={})
46
+
47
+ druid=params[:druid]
48
+ objects=params[:objects]
49
+
50
+ raise "No objects and/or druid supplied" if druid.nil? || objects.nil?
51
+
52
+ pid=druid.gsub('druid:','') # remove druid prefix when creating IDs
53
+
54
+ style=params[:style] || :simple_image
55
+ bundle=params[:bundle] || :default
56
+ add_exif=params[:add_exif] || false
57
+ auto_labels=(params[:auto_labels].nil? ? true : params[:auto_labels])
58
+ add_file_attributes=params[:add_file_attributes] || false
59
+ file_attributes=params[:file_attributes] || {}
60
+ preserve_common_paths=params[:preserve_common_paths] || false
61
+ flatten_folder_structure=params[:flatten_folder_structure] || false
62
+ include_root_xml=params[:include_root_xml]
63
+
64
+ all_paths=[]
65
+ objects.flatten.each do |obj|
66
+ raise "File '#{obj.path}' not found" unless obj.file_exists?
67
+ all_paths << obj.path unless preserve_common_paths # collect all of the filenames into an array
68
+ end
69
+
70
+ common_path=Assembly::ObjectFile.common_path(all_paths) unless preserve_common_paths # find common paths to all files provided if needed
71
+
72
+ # these are the valid strings for each type of document to be use contentMetadata type and resourceType
73
+ content_type_descriptions={:file=>'file',:image=>'image',:book=>'book',:map=>'map'}
74
+ resource_type_descriptions={:object=>'object',:file=>'file',:image=>'image',:book=>'page',:map=>'image'}
75
+
76
+ # global sequence for resource IDs
77
+ sequence = 0
78
+
79
+ # a counter to use when creating auto-labels for resources, with incremenets for each type
80
+ resource_type_counters=Hash.new(0)
81
+
82
+ # set the content type id
83
+ case style
84
+ when :simple_image
85
+ content_type_description = content_type_descriptions[:image]
86
+ when :file
87
+ content_type_description = content_type_descriptions[:file]
88
+ when :simple_book,:book_with_pdf
89
+ content_type_description = content_type_descriptions[:book]
90
+ when :book_as_image
91
+ content_type_description = content_type_descriptions[:book]
92
+ when :map
93
+ content_type_description = content_type_descriptions[:map]
94
+ else
95
+ raise "Supplied style not valid"
96
+ end
97
+
98
+
99
+ # determine how many resources to create
100
+ # setup an array of arrays, where the first array is the number of resources, and the second array is the object files containined in that resource
101
+ case bundle
102
+ when :default # one resource per object
103
+ resources=objects.collect {|obj| [obj]}
104
+ when :filename # one resource per distinct filename (excluding extension)
105
+ # loop over distinct filenames, this determines how many resources we will have and
106
+ # create one resource node per distinct filename, collecting the relevant objects with the distinct filename into that resource
107
+ resources=[]
108
+ distinct_filenames=objects.collect {|obj| obj.filename_without_ext}.uniq # find all the unique filenames in the set of objects, leaving off extensions and base paths
109
+ distinct_filenames.each {|distinct_filename| resources << objects.collect {|obj| obj if obj.filename_without_ext == distinct_filename}.compact }
110
+ when :dpg # group by DPG filename
111
+ # loop over distinct dpg base names, this determines how many resources we will have and
112
+ # create one resource node per distinct dpg base name, collecting the relevant objects with the distinct names into that resource
113
+ resources=[]
114
+ distinct_filenames=objects.collect {|obj| obj.dpg_basename}.uniq # find all the unique DPG filenames in the set of objects
115
+ distinct_filenames.each do |distinct_filename|
116
+ resources << objects.collect {|obj| obj if obj.dpg_basename == distinct_filename && !self.is_special_dpg_folder?(obj.dpg_folder)}.compact
117
+ end
118
+ objects.each {|obj| resources << [obj] if self.is_special_dpg_folder?(obj.dpg_folder)} # certain subfolders require individual resources for files within them regardless of file-naming convention
119
+ when :prebundled
120
+ # if the user specifies this method, they will pass in an array of arrays, indicating resources, so we don't need to bundle in the gem
121
+ resources=objects
122
+ else
123
+ raise "Invalid bundle method"
124
+ end
125
+
126
+ resources.delete([]) # delete any empty elements
127
+
128
+ builder = Nokogiri::XML::Builder.new do |xml|
129
+ xml.contentMetadata(:objectId => "#{pid}",:type => content_type_description) {
130
+ resources.each do |resource_files| # iterate over all the resources
131
+
132
+ # start a new resource element
133
+ sequence += 1
134
+ resource_id = "#{pid}_#{sequence}"
135
+
136
+ # grab all of the file types within a resource into an array so we can decide what the resource type should be
137
+ resource_file_types=resource_files.collect {|obj| obj.object_type}
138
+ resource_has_non_images=((resource_file_types-[:image]).size > 0)
139
+ resource_from_special_dpg_folder=resource_files.collect {|obj| self.is_special_dpg_folder?(obj.dpg_folder)}.uniq
140
+
141
+ if bundle == :dpg && resource_from_special_dpg_folder.include?(true) # objects in the special DPG folders are always type=object when we using :bundle=>:dpg
142
+ resource_type_description = resource_type_descriptions[:object]
143
+ else # otherwise look at the style to determine the resource_type_description
144
+ case style
145
+ when :simple_image
146
+ resource_type_description = resource_type_descriptions[:image]
147
+ when :file
148
+ resource_type_description = resource_type_descriptions[:file]
149
+ when :simple_book # in a simple book project, all resources are pages unless they are *all* non-images -- if so, switch the type to object
150
+ resource_type_description = (resource_has_non_images && resource_file_types.include?(:image) == false) ? resource_type_descriptions[:object] : resource_type_descriptions[:book]
151
+ when :book_as_image # same as simple book, but all resources are images instead of pages, unless we need to switch them to object type
152
+ resource_type_description = (resource_has_non_images && resource_file_types.include?(:image) == false) ? resource_type_descriptions[:object] : resource_type_descriptions[:image]
153
+ when :book_with_pdf # in book with PDF type, if we find a resource with *any* non images, switch it's type from book to object
154
+ resource_type_description = resource_has_non_images ? resource_type_descriptions[:object] : resource_type_descriptions[:book]
155
+ when :map #
156
+ resource_type_description = resource_type_descriptions[:map]
157
+ end
158
+ end
159
+
160
+ resource_type_counters[resource_type_description.to_sym]+=1 # each resource type description gets its own incrementing counter
161
+
162
+ xml.resource(:id => resource_id,:sequence => sequence,:type => resource_type_description) {
163
+
164
+ # create a generic resource label if needed
165
+ resource_label = (auto_labels == true ? "#{resource_type_description.capitalize} #{resource_type_counters[resource_type_description.to_sym]}" : "")
166
+
167
+ # but if one of the files has a label, use it instead
168
+ resource_files.each {|obj| resource_label = obj.label unless obj.label.nil? || obj.label.empty? }
169
+
170
+ xml.label(resource_label) unless resource_label.empty?
171
+
172
+ resource_files.each do |obj| # iterate over all the files in a resource
173
+
174
+ mimetype = obj.mimetype if (add_file_attributes || add_exif) # we only need to compute the mimetype if we are adding file attributes or exif info, otherwise skip it for performance reasons
175
+
176
+ # set file id attribute, first check the relative_path parameter on the object, and if it is set, just use that
177
+ if obj.relative_path
178
+ file_id=obj.relative_path
179
+ else
180
+ # if the relative_path attribute is not set, then use the path attribute and check to see if we need to remove the common part of the path
181
+ file_id=preserve_common_paths ? obj.path : obj.path.gsub(common_path,'')
182
+ file_id=File.basename(file_id) if flatten_folder_structure
183
+ end
184
+
185
+ xml_file_params = {:id=> file_id}
186
+
187
+ if add_file_attributes
188
+ file_attributes_hash=obj.file_attributes || file_attributes[mimetype] || file_attributes['default'] || Assembly::FILE_ATTRIBUTES[mimetype] || Assembly::FILE_ATTRIBUTES['default']
189
+ xml_file_params.merge!({
190
+ :preserve => file_attributes_hash[:preserve],
191
+ :publish => file_attributes_hash[:publish],
192
+ :shelve => file_attributes_hash[:shelve],
193
+ })
194
+ end
195
+
196
+ xml_file_params.merge!({:mimetype => mimetype,:size => obj.filesize}) if add_exif
197
+ xml.file(xml_file_params) {
198
+ if add_exif # add exif info if the user requested it
199
+ xml.checksum(obj.sha1, :type => 'sha1')
200
+ xml.checksum(obj.md5, :type => 'md5')
201
+ xml.imageData(:height => obj.exif.imageheight, :width => obj.exif.imagewidth) if obj.image? # add image data for an image
202
+ elsif obj.provider_md5 || obj.provider_sha1 # if we did not add exif info, see if there are user supplied checksums to add
203
+ xml.checksum(obj.provider_sha1, :type => 'sha1') if obj.provider_sha1
204
+ xml.checksum(obj.provider_md5, :type => 'md5') if obj.provider_md5
205
+ end #add_exif
206
+ }
207
+ end # end resource_files.each
208
+ }
209
+ end # resources.each
210
+ }
211
+ end
212
+
213
+ if include_root_xml == false
214
+ result = builder.doc.root.to_xml
215
+ else
216
+ result = builder.to_xml
217
+ end
218
+
219
+ return result
220
+
221
+ end # create_content_metadata
222
+
223
+ def self.is_special_dpg_folder?(folder)
224
+ SPECIAL_DPG_FOLDERS.include?(folder)
225
+ end
226
+
227
+ end # class
228
+
229
+ end # module