talia_core 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. data/README.rdoc +41 -0
  2. data/bin/talia +33 -0
  3. data/lib/JXslt/jxslt.rb +60 -0
  4. data/lib/acts_as_roled.rb +11 -0
  5. data/lib/core_ext/platform.rb +9 -0
  6. data/lib/core_ext/string.rb +6 -0
  7. data/lib/core_ext.rb +1 -0
  8. data/lib/custom_template.rb +4 -0
  9. data/lib/loader_helper.rb +62 -0
  10. data/lib/mysql.rb +1214 -0
  11. data/lib/progressbar.rb +236 -0
  12. data/lib/role.rb +12 -0
  13. data/lib/talia_cl/command_line.rb +39 -0
  14. data/lib/talia_cl/commands/standalone/cl_options.rb +9 -0
  15. data/lib/talia_cl/commands/standalone/standalone_generate.rb +75 -0
  16. data/lib/talia_cl/commands/standalone.rb +25 -0
  17. data/lib/talia_cl/commands/talia_console/cl_options.rb +55 -0
  18. data/lib/talia_cl/commands/talia_console/console_commands.rb +37 -0
  19. data/lib/talia_cl/commands/talia_console/talia_commands.rb +131 -0
  20. data/lib/talia_cl/commands/talia_console.rb +47 -0
  21. data/lib/talia_cl/core_commands.rb +11 -0
  22. data/lib/talia_cl.rb +47 -0
  23. data/lib/talia_core/active_source.rb +372 -0
  24. data/lib/talia_core/active_source_parts/class_methods.rb +378 -0
  25. data/lib/talia_core/active_source_parts/predicate_handler.rb +89 -0
  26. data/lib/talia_core/active_source_parts/rdf.rb +131 -0
  27. data/lib/talia_core/active_source_parts/sql_helper.rb +36 -0
  28. data/lib/talia_core/active_source_parts/xml/base_builder.rb +47 -0
  29. data/lib/talia_core/active_source_parts/xml/generic_reader.rb +363 -0
  30. data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +88 -0
  31. data/lib/talia_core/active_source_parts/xml/source_builder.rb +73 -0
  32. data/lib/talia_core/active_source_parts/xml/source_reader.rb +20 -0
  33. data/lib/talia_core/agent.rb +14 -0
  34. data/lib/talia_core/background_jobs/job.rb +82 -0
  35. data/lib/talia_core/background_jobs/progress_job.rb +68 -0
  36. data/lib/talia_core/collection.rb +13 -0
  37. data/lib/talia_core/data_types/data_loader.rb +92 -0
  38. data/lib/talia_core/data_types/data_record.rb +105 -0
  39. data/lib/talia_core/data_types/delayed_copier.rb +76 -0
  40. data/lib/talia_core/data_types/file_record.rb +59 -0
  41. data/lib/talia_core/data_types/file_store.rb +306 -0
  42. data/lib/talia_core/data_types/iip_data.rb +153 -0
  43. data/lib/talia_core/data_types/iip_loader.rb +127 -0
  44. data/lib/talia_core/data_types/image_data.rb +32 -0
  45. data/lib/talia_core/data_types/media_link.rb +19 -0
  46. data/lib/talia_core/data_types/mime_mapping.rb +45 -0
  47. data/lib/talia_core/data_types/path_helpers.rb +77 -0
  48. data/lib/talia_core/data_types/pdf_data.rb +42 -0
  49. data/lib/talia_core/data_types/simple_text.rb +36 -0
  50. data/lib/talia_core/data_types/temp_file_handling.rb +85 -0
  51. data/lib/talia_core/data_types/xml_data.rb +169 -0
  52. data/lib/talia_core/dc_resource.rb +20 -0
  53. data/lib/talia_core/dummy_handler.rb +34 -0
  54. data/lib/talia_core/dummy_source.rb +20 -0
  55. data/lib/talia_core/errors.rb +25 -0
  56. data/lib/talia_core/initializer.rb +427 -0
  57. data/lib/talia_core/ordered_source.rb +228 -0
  58. data/lib/talia_core/rails_ext/actionpack/action_controller/record_identifier.rb +13 -0
  59. data/lib/talia_core/rails_ext/actionpack/action_controller.rb +1 -0
  60. data/lib/talia_core/rails_ext/actionpack.rb +1 -0
  61. data/lib/talia_core/rails_ext.rb +1 -0
  62. data/lib/talia_core/rdf_import.rb +90 -0
  63. data/lib/talia_core/rdf_resource.rb +159 -0
  64. data/lib/talia_core/semantic_collection_item.rb +93 -0
  65. data/lib/talia_core/semantic_collection_wrapper.rb +324 -0
  66. data/lib/talia_core/semantic_property.rb +7 -0
  67. data/lib/talia_core/semantic_relation.rb +67 -0
  68. data/lib/talia_core/source.rb +323 -0
  69. data/lib/talia_core/source_transfer_object.rb +38 -0
  70. data/lib/talia_core/workflow/base.rb +15 -0
  71. data/lib/talia_core/workflow/publication_workflow.rb +62 -0
  72. data/lib/talia_core/workflow.rb +300 -0
  73. data/lib/talia_core.rb +9 -0
  74. data/lib/talia_dependencies.rb +12 -0
  75. data/lib/talia_util/bar_progressor.rb +15 -0
  76. data/lib/talia_util/configuration/config_file.rb +48 -0
  77. data/lib/talia_util/configuration/database_config.rb +40 -0
  78. data/lib/talia_util/configuration/mysql_database_setup.rb +104 -0
  79. data/lib/talia_util/data_import.rb +91 -0
  80. data/lib/talia_util/image_conversions.rb +82 -0
  81. data/lib/talia_util/import_job_helper.rb +132 -0
  82. data/lib/talia_util/io_helper.rb +54 -0
  83. data/lib/talia_util/progressable.rb +38 -0
  84. data/lib/talia_util/progressbar.rb +236 -0
  85. data/lib/talia_util/rdf_update.rb +80 -0
  86. data/lib/talia_util/some_sigla.xml +1960 -0
  87. data/lib/talia_util/test_helpers.rb +151 -0
  88. data/lib/talia_util/util.rb +226 -0
  89. data/lib/talia_util/yaml_import.rb +80 -0
  90. data/lib/talia_util.rb +13 -0
  91. data/lib/user.rb +116 -0
  92. data/lib/version.rb +15 -0
  93. data/test/core_ext/string_test.rb +11 -0
  94. data/test/custom_template_test.rb +8 -0
  95. data/test/talia_core/active_source_predicate_test.rb +54 -0
  96. data/test/talia_core/active_source_rdf_test.rb +89 -0
  97. data/test/talia_core/active_source_test.rb +631 -0
  98. data/test/talia_core/data_types/data_loader_test.rb +123 -0
  99. data/test/talia_core/data_types/data_record_test.rb +40 -0
  100. data/test/talia_core/data_types/file_record_test.rb +171 -0
  101. data/test/talia_core/data_types/iip_data_test.rb +130 -0
  102. data/test/talia_core/data_types/image_data_test.rb +88 -0
  103. data/test/talia_core/data_types/pdf_data_test.rb +68 -0
  104. data/test/talia_core/data_types/xml_data_test.rb +134 -0
  105. data/test/talia_core/generic_xml_test.rb +83 -0
  106. data/test/talia_core/initializer_test.rb +36 -0
  107. data/test/talia_core/ordered_source_test.rb +398 -0
  108. data/test/talia_core/rdf_resource_test.rb +115 -0
  109. data/test/talia_core/semantic_collection_item_test.rb +129 -0
  110. data/test/talia_core/source_reader_test.rb +33 -0
  111. data/test/talia_core/source_test.rb +484 -0
  112. data/test/talia_core/source_transfer_object_test.rb +24 -0
  113. data/test/talia_core/workflow/publication_workflow_test.rb +242 -0
  114. data/test/talia_core/workflow/user_class_for_workflow.rb +35 -0
  115. data/test/talia_core/workflow/workflow_base_test.rb +21 -0
  116. data/test/talia_core/workflow_test.rb +19 -0
  117. data/test/talia_util/import_job_helper_test.rb +46 -0
  118. data/test/test_helper.rb +68 -0
  119. metadata +262 -0
@@ -0,0 +1,306 @@
1
+ require 'fileutils'
2
+
3
+ module TaliaCore
4
+ module DataTypes
5
+ module FileStore
6
+
7
+ # the handle for the file
8
+ @file_handle = nil
9
+ # position of the reading cursors
10
+ @position = 0
11
+
12
+ # Class for data paths
13
+ class DataPath < String ; end
14
+
15
+ module ClassMethods
16
+
17
+ # Find or create a record for the given location and source_id, then it saves the given file.
18
+ def find_or_create_and_assign_file(params)
19
+ data_record = self.find_or_create_by_location_and_source_id(extract_filename(params[:file]), params[:source_id])
20
+ data_record.file = params[:file]
21
+ data_record.save # force attachment save and it also saves type attribute.
22
+ end
23
+
24
+ end
25
+
26
+ # This will create the data object from a given file. This will simply move the
27
+ # given file to the correct location upon save. This will avoid multiple
28
+ # read/write operations during import.
29
+ #
30
+ # The original file must not be touched by external processes until the
31
+ # record is saved.
32
+ #
33
+ # If the delete_original flag is set, the original file will be removed
34
+ # on save
35
+ def create_from_file(location, file_path, delete_original = false)
36
+ close_file
37
+ self.location = location
38
+ @file_data_to_write = DataPath.new(file_path)
39
+ @delete_original_file = delete_original
40
+ end
41
+
42
+ # Add data as string into file
43
+ def create_from_data(file_location, data, options = {})
44
+ # close file if opened
45
+ close_file
46
+
47
+ # Set the location for the record
48
+ self.location = file_location
49
+
50
+ if(data.respond_to?(:read))
51
+ @file_data_to_write = data.read
52
+ else
53
+ @file_data_to_write = data
54
+ end
55
+
56
+ end
57
+
58
+ # returns the complete text
59
+ def all_text
60
+ if(!is_file_open?)
61
+ open_file
62
+ end
63
+ @file_handle.read(self.size)
64
+ end
65
+
66
+ # This is a placeholder in case file is used in a form.
67
+ def file() nil; end
68
+
69
+ # Assign the file data (<tt>StringIO</tt> or <tt>File</tt>).
70
+ def file=(file_data)
71
+ return nil if file_data.nil? || file_data.size == 0
72
+ self.assign_type file_data.content_type
73
+ self.location = file_data.original_filename
74
+ if file_data.is_a?(StringIO)
75
+ file_data.rewind
76
+ self.temp_data = file_data.read
77
+ else
78
+ self.temp_path = file_data.path
79
+ end
80
+ @save_attachment = true
81
+ end
82
+
83
+ def write_file_after_save
84
+ # check if there are data to write
85
+ return unless(@file_data_to_write)
86
+
87
+ # check if file already exists
88
+ # raise(RuntimeError, "File already exists: #{file_path}") if(File.exists?(file_path))
89
+
90
+ begin
91
+ self.class.benchmark("\033[36m\033[1m\033[4mFileStore\033[0m Saving file for #{self.id}") do
92
+ # create data directory path
93
+ FileUtils.mkdir_p(data_directory)
94
+
95
+ if(@file_data_to_write.is_a?(DataPath))
96
+ copy_data_file
97
+ else
98
+ save_cached_data
99
+ end
100
+
101
+ @file_data_to_write = nil
102
+ end
103
+ rescue Exception => e
104
+ assit_fail("Exception on writing file #{self.location}: #{e}")
105
+ end
106
+
107
+ end
108
+
109
+ # Return true if the specified data file is open, false otherwise
110
+ def is_file_open?
111
+ (@file_handle != nil)
112
+ end
113
+
114
+
115
+ # Assign the STI subclass, perfoming a mime-type lookup.
116
+ def assign_type(content_type)
117
+ self.type = self.class.class_type_from(content_type).name
118
+ end
119
+
120
+
121
+ # private methods ==================================================================
122
+ private
123
+
124
+ # This saves the cached data from the file creation
125
+ def save_cached_data
126
+ # open file for writing
127
+ @file_handle = File.open(file_path, 'w')
128
+
129
+ # write data string into file
130
+ @file_handle << (@file_data_to_write.respond_to?(:read) ? @file_data_to_write.read : @file_data_to_write)
131
+
132
+ # close file
133
+ close_file
134
+
135
+ end
136
+
137
+ # This copies the data file with which this object was created to the
138
+ # actual storage lcoation
139
+ def copy_data_file
140
+ copy_or_move(@file_data_to_write, file_path)
141
+ end
142
+
143
+ # Open a specified file name and return a file handle.
144
+ # If the file is already opened, return the file handle
145
+ def open_file(file_name = file_path, options = 'rb')
146
+ # chek if the file name really exists, otherwise raise an exception
147
+ if !File.exists?(file_name)
148
+ raise(IOError, "File #{file_name} could not be opened.", caller)
149
+ end
150
+
151
+ # try to open the specified file if is not already open
152
+ if @file_handle == nil
153
+ @file_handle = File.open(file_name, options)
154
+
155
+ # check and set the initial position of the reading cursors.
156
+ # It's necessary to do this thing because we don't know if the user
157
+ # has specified the initial reading cursors befort starting working on file
158
+ @position ||= @file_handle.pos
159
+
160
+ @file_handle.pos = @position
161
+ end
162
+ end
163
+
164
+ # Close an already opened file
165
+ def close_file
166
+ if is_file_open?
167
+ @file_handle.close
168
+
169
+ # reset 'flags' variables and position
170
+ @file_handle = nil
171
+ @position = 0
172
+ end
173
+ end
174
+
175
+ # Read all bytes from a file
176
+ def read_all_bytes
177
+ # 1. Open file with option "r" (reading) and "b" (binary, useful for window system)
178
+ open_file
179
+
180
+ # 2. Read all bytes
181
+ begin
182
+ bytes = @file_handle.read(self.size).unpack("C*")
183
+ return bytes
184
+ rescue
185
+ # re-raise system the excepiton
186
+ raise
187
+ return nil
188
+ ensure
189
+ # 3. Close the file
190
+ close_file
191
+ end
192
+ end
193
+
194
+ # return the next_byte
195
+ def next_byte(close)
196
+ if !is_file_open?
197
+ open_file
198
+ end
199
+
200
+ begin
201
+ current_byte = @file_handle.getc
202
+
203
+ if current_byte == nil or close
204
+ close_file
205
+ else
206
+ @position += 1
207
+ end
208
+
209
+ return current_byte
210
+ rescue
211
+ # re-raise system the excepiton
212
+ raise
213
+ close_file
214
+ return nil
215
+ end
216
+
217
+ end
218
+
219
+ # Copy or move the source file to the target. Working around all the
220
+ # things that suck in JRuby. This will honour two environment settings:
221
+ #
222
+ # * delay_file_copies - will not copy the files, but create a batch file
223
+ # so that the copy can be done later. Uses the DelayedCopier class.
224
+ # * fast_copies - will use the "normal" copy method from FileUtils that
225
+ # is faster. Since it crashed the system for us, the default is to
226
+ # use a "safe" workaround. The workaround is probably necessary for
227
+ # JRuby only.
228
+ def copy_or_move(original, target)
229
+ if(@delete_original_file)
230
+ FileUtils.move(original, target)
231
+ else
232
+ # Delay can be enabled through enviroment
233
+ if(delay_copies)
234
+ DelayedCopier.cp(original, target)
235
+ elsif(fast_copies)
236
+ FileUtils.copy(original, target)
237
+ else
238
+ # Call the copy as an external command. This is to work around the
239
+ # crashes that occurred using the builtin copy
240
+ from_file = File.expand_path(original)
241
+ to_file = File.expand_path(target)
242
+ system_success = system("cp '#{from_file}' '#{to_file}'")
243
+ raise(IOError, "copy error '#{from_file}' '#{to_file}'") unless system_success
244
+ end
245
+ end
246
+ end
247
+
248
+
249
+ # Returns true if the 'delayed write' is enabled in the environment
250
+ def delay_copies
251
+ ENV['delay_file_copies'] == 'true' || ENV['delay_file_copies'] == 'yes'
252
+ end
253
+
254
+ # Returns true if the 'fast copy' is enabled in the environment.
255
+ # Otherwise the class will use a workaround that is less likely to
256
+ # crash the whole system using JRuby.
257
+ def fast_copies
258
+ ENV['fast_copies'] == 'true' || ENV['fast_copies'] == 'yes'
259
+ end
260
+
261
+ # Return the data size
262
+ def data_size
263
+ File.size(file_path)
264
+ end
265
+
266
+ # set the position of the reading cursor
267
+ def set_position(position)
268
+ if (position != nil and position =~ /\A\d+\Z/)
269
+ if (position < size)
270
+ set_position(position)
271
+ else
272
+ raise(IOError, 'Position out of range', caller)
273
+ end
274
+ else
275
+ raise(IOError, 'Position not valid. It must be an integer')
276
+ end
277
+ end
278
+
279
+ # Check if the attachment should be saved.
280
+ def save_attachment?
281
+ @save_attachment
282
+ end
283
+
284
+ # Save the attachment, copying the file from the temp_path to the data_path.
285
+ def save_attachment
286
+ return unless save_attachment?
287
+ save_file
288
+ @save_attachment = false
289
+ true
290
+ end
291
+
292
+ # Destroy the attachment
293
+ def destroy_attachment
294
+ FileUtils.rm(full_filename) if File.exists?(full_filename)
295
+ end
296
+
297
+ # Save the attachment on the data_path directory.
298
+ def save_file
299
+ FileUtils.mkdir_p(File.dirname(full_filename))
300
+ FileUtils.cp(temp_path, full_filename)
301
+ FileUtils.chmod(0644, full_filename)
302
+ end
303
+
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,153 @@
1
+ module TaliaCore
2
+ module DataTypes
3
+
4
+ # Class to manage IIP Image data type
5
+ class IipData < FileRecord
6
+
7
+ # Returns the IIP server configured for the application
8
+ def self.iip_server_uri
9
+ TaliaCore::CONFIG['iip_server_uri'] ||= 'http://localhost/fcgi-bin/iipsrv.fcgi'
10
+ end
11
+
12
+ # This is the mime type for the thumbnail - always tiff
13
+ def set_mime_type
14
+ self.mime = 'image/gif'
15
+ end
16
+
17
+ alias :get_thumbnail :all_bytes
18
+
19
+ # Create from existing thumb and pyramid images
20
+ def create_from_existing(thumb, pyramid, delete_originals = false)
21
+ @file_data_to_write = [thumb, pyramid]
22
+ @delete_original_file = delete_originals
23
+ self.location = ''
24
+ end
25
+
26
+ # return IIP Server Path
27
+ def iip_server_path
28
+ self.location
29
+ end
30
+
31
+ def write_file_after_save
32
+ return unless(@file_data_to_write)
33
+
34
+ # Check if we have the images already given, in this case we prepare
35
+ # them and call the super method
36
+ return super if(direct_write!)
37
+
38
+ # create name for orginal temp file and destination temp file
39
+ original_file_path, orig_is_temp = prepare_original_file
40
+ will_delete_source = orig_is_temp || @delete_original_file
41
+ destination_thumbnail_file_path = File.join(Dir.tmpdir, "thumbnail_#{random_tempfile_filename}.gif")
42
+
43
+ begin # Begin the file creation operation
44
+ self.class.benchmark("\033[36mIipData\033[0m Making thumb and pyramid for #{self.id}", Logger::INFO) do
45
+
46
+ TaliaUtil::ImageConversions::create_thumb(original_file_path, destination_thumbnail_file_path)
47
+ create_pyramid(original_file_path)
48
+
49
+ # Run the super implementation for the thumbnail
50
+ # We will simply tell the system that we have to move the newly create
51
+ # thumb file
52
+ @file_data_to_write = DataPath.new(destination_thumbnail_file_path)
53
+ @delete_original_file = true
54
+
55
+ end # end benchmarking
56
+ super
57
+
58
+ ensure
59
+ # delete teƒmp files
60
+ File.delete original_file_path if(File.exists?(original_file_path) && will_delete_source)
61
+ end
62
+ end
63
+
64
+
65
+ # Checks if we have file paths given to directly copy thum and image file.
66
+ # Will always return true if such paths were given.
67
+ def direct_write!
68
+ return false unless(@file_data_to_write.kind_of?(Array))
69
+
70
+ thumb, pyramid = @file_data_to_write
71
+ self.class.benchmark("\033[36mIipData\033[0m Direct write for #{self.id}", Logger::INFO) do
72
+ prepare_for_pyramid
73
+
74
+ copy_or_move(pyramid, get_iip_root_file_path)
75
+
76
+ end # end benchmark
77
+
78
+ @file_data_to_write = DataPath.new(thumb)
79
+
80
+ true
81
+ end
82
+
83
+ # This prepares the original file that needs to be converted. This will
84
+ # see if the data to be written is binary data or a file path. If this
85
+ # is binary data, it will create a temporary file on the disk.
86
+ #
87
+ # This returns an array with two elements: The name of the file to
88
+ # be used (a file system path) and a flag indicating if the file is
89
+ # a temporary file or not.
90
+ def prepare_original_file
91
+ if(@file_data_to_write.is_a?(DataPath))
92
+ [@file_data_to_write, false]
93
+ else
94
+ temp_file = File.join(Dir.tmpdir, "original_#{random_tempfile_filename}")
95
+ # write the original file
96
+ File.open(temp_file, 'w') do |original_file|
97
+ if(@file_data_to_write.respond_to?(:read))
98
+ original_file << @file_data_to_write.read
99
+ else
100
+ original_file << @file_data_to_write
101
+ end
102
+ end
103
+
104
+ [temp_file, true]
105
+ end
106
+ end
107
+
108
+ # Prepare for copying or creating the pyramid image
109
+ def prepare_for_pyramid
110
+ # set location
111
+ self.location = get_iip_root_file_path(true)
112
+
113
+ # create data directory path
114
+ FileUtils.mkdir_p(iip_root_directory)
115
+ end
116
+
117
+ # Creates the pyramid image for IIP by running the configured system
118
+ # command. This automatically creates the file in the correct location
119
+ # (IIP root)
120
+ def create_pyramid(source)
121
+ # check if file already exists
122
+ raise(IOError, "File already exists: #{get_iip_root_file_path}") if(File.exists?(get_iip_root_file_path))
123
+
124
+ prepare_for_pyramid
125
+
126
+ TaliaUtil::ImageConversions::create_pyramid(source, get_iip_root_file_path)
127
+ end
128
+
129
+ # Return the iip root directory for a specific iip image file
130
+ def iip_root_directory(relative = false)
131
+ if relative == false
132
+ File.join(TaliaCore::CONFIG["iip_root_directory_location"], ("00" + self.id.to_s)[-3..-1])
133
+ else
134
+ File.join(("00" + self.id.to_s)[-3..-1])
135
+ end
136
+ end
137
+
138
+ # Return the full file path related to the data directory
139
+ def get_iip_root_file_path(relative = false)
140
+ File.join(iip_root_directory(relative), self.id.to_s + '.tif')
141
+ end
142
+
143
+ private
144
+
145
+ # Generates a unique filename for a Tempfile.
146
+ def random_tempfile_filename
147
+ "#{rand 10E16}"
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+ end
@@ -0,0 +1,127 @@
1
+ module TaliaCore
2
+ module DataTypes
3
+
4
+ # Special module that contains the DataLoader methods to create IIP image data
5
+ module IipLoader
6
+
7
+
8
+ # Loads an image for the given file. This is a tad more complex than loading
9
+ # the data into a data record: It will create both an IIP data object and
10
+ # an Image data object.
11
+ def create_iip(mime_type, location, source, is_file)
12
+ iip_record = TaliaCore::DataTypes::IipData.new
13
+ image_record = TaliaCore::DataTypes::ImageData.new
14
+ records = [iip_record, image_record]
15
+ return records if(is_file && prepare_image_from_existing!(iip_record, image_record, source, location))
16
+
17
+ if(convert_original?(mime_type))
18
+ # We have an image that needs to be converted
19
+ open_original_image(source, is_file, mime_type) do |io|
20
+ create_from_stream(location, io, records)
21
+ image_record.location = orig_location(location)
22
+ end
23
+ else
24
+ if(is_file)
25
+ create_from_files(location, source, records)
26
+ else
27
+ create_from_stream(location, source, records)
28
+ end
29
+ end
30
+ # IipRecord is always a (multi-leve) tiff
31
+ iip_record.mime = 'image/tiff'
32
+
33
+ records
34
+ end
35
+
36
+ # Rewrite the file location for original image files (to .png)
37
+ def orig_location(location)
38
+ File.basename(location, File.extname(location)) + '.png'
39
+ end
40
+
41
+ # Indicates if the given mime type requires a conversion for the
42
+ # original image
43
+ def convert_original?(mime_type)
44
+ !([:jpeg, :png].include?(mime_type.to_sym))
45
+ end
46
+
47
+ # Create the elements from a file
48
+ def create_from_files(location, file, records)
49
+ records.each { |rec| rec.create_from_file(location, file) }
50
+ end
51
+
52
+ # Create the elements from a stream
53
+ def create_from_stream(location, io, records)
54
+ data = io.read
55
+ records.each { |rec| rec.create_from_data(location, data)}
56
+ end
57
+
58
+ # Attempts to create an IipData object with pre-prepared images if possible
59
+ # Returns true if (and only if) the object has been created with existing
60
+ # data. Always fals if the data_record is not an IipData object or the
61
+ # :prepared_images option is not set.
62
+ def prepare_image_from_existing!(iip_record, image_record, url, location)
63
+ return false unless(iip_record.is_a?(TaliaCore::DataTypes::IipData) && image_record.is_a?(TaliaCore::DataTypes::ImageData))
64
+ return false unless((prep = ENV['prepared_images']) && prep.to_s.downcase != 'no' && prep.to_s.downcase != 'false')
65
+
66
+ file_ext = File.extname(url)
67
+ file_base = File.basename(url, file_ext)
68
+
69
+ thumb_file = File.join( ENV['prepared_images'], 'thumbs', "#{file_base}.gif")
70
+ pyramid_file = File.join( ENV['prepared_images'], 'pyramids', "#{file_base}.tif")
71
+ orig_file_pattern = File.join(ENV['prepared_images'], 'originals', "#{file_base}.*")
72
+ # We need to fix the pattern, also the Dir[] doesn't like unescaped brackets
73
+ orig_file_pattern.gsub!(/\[/, '\\[')
74
+ orig_file_pattern.gsub!(/\]/, '\\]')
75
+ orig_file_l = Dir[orig_file_pattern]
76
+ raise(ArgumentError, 'Original find not found for ' + url) unless(orig_file_l.size > 0)
77
+ orig_file = orig_file_l.first
78
+ assit_block { %w(.jpg .jpeg .png).include?(File.extname(orig_file).downcase) }
79
+
80
+ iip_record.create_from_existing(thumb_file, pyramid_file)
81
+ image_record.create_from_file(location, orig_file)
82
+
83
+ true
84
+ end
85
+
86
+ # Little helper to decide how to open the original image
87
+ def open_original_image(thing, is_file, current_type, &block)
88
+ if(is_file)
89
+ open_original_image_file(thing, &block)
90
+ else
91
+ open_original_image_stream(thing, current_type, &block)
92
+ end
93
+ end
94
+
95
+ # Same as open_original_image_file, but getting the data from a stream.
96
+ def open_original_image_stream(io, type, &block)
97
+ # First load this from the web to a temp file
98
+ tempfile = File.join(Dir.tmpdir, "talia_down_#{rand 10E16}.#{type.to_sym}")
99
+ begin
100
+ File.open(tempfile, 'w') do |fio|
101
+ fio << io.read # Download the file
102
+ end
103
+ assit(File.exist?(tempfile))
104
+ open_original_image_file(tempfile, &block)
105
+ ensure
106
+ FileUtils.rm(tempfile) if(File.exist?(tempfile))
107
+ end
108
+ end
109
+
110
+ # Opens the "original" image for the given file. This will convert the
111
+ # image to PNG image and the yield the io object for the PNG.
112
+ def open_original_image_file(filename)
113
+ converted_file = File.join(Dir.tmpdir, "talia_convert_#{rand 10E16}.png")
114
+ begin
115
+ TaliaUtil::ImageConversions.to_png(filename, converted_file)
116
+ File.open(converted_file) do |io|
117
+ yield(io)
118
+ end
119
+ ensure
120
+ FileUtils.rm(converted_file) if(File.exist?(converted_file))
121
+ end
122
+ end
123
+
124
+
125
+ end # Ending modules and such
126
+ end
127
+ end
@@ -0,0 +1,32 @@
1
+ module TaliaCore
2
+ module DataTypes
3
+
4
+ # Class to manage image data type
5
+ class ImageData < FileRecord
6
+
7
+ # return the mime_type for a file
8
+ def extract_mime_type(location)
9
+ case File.extname(location).downcase
10
+ when '.bmp'
11
+ 'image/bmp'
12
+ when '.cgm'
13
+ 'image/cgm'
14
+ when '.fit', '.fits'
15
+ 'image/fits'
16
+ when '.g3'
17
+ 'image/g3fax'
18
+ when '.gif'
19
+ 'image/gif'
20
+ when '.jpg', '.jpeg', '.jpe'
21
+ 'image/jpeg'
22
+ when '.png'
23
+ 'image/png'
24
+ when '.tif', '.tiff'
25
+ 'image/tiff'
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ module TaliaCore
2
+ module DataTypes
3
+
4
+ # Data class that contains just a link to a remote data element (and no
5
+ # locally stored data at all). The uri for the link is stored in the location
6
+ # field
7
+ class MediaLink < DataRecord
8
+
9
+ def all_bytes
10
+ raise(RuntimeError, "Media Links have no data")
11
+ end
12
+
13
+ def get_byte(close_after_single_read=false)
14
+ raise(RuntimeRror, "Media Links have no data")
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ module TaliaCore
2
+ module DataTypes
3
+
4
+ # Mapping from Mime types to data classes and importing methods. Currently uses a fixed
5
+ # default mapping
6
+ module MimeMapping
7
+
8
+ def mapping_for(mime_type)
9
+ mime_type = Mime::Type.lookup(mime_type) if(mime_type.is_a?(String))
10
+ mapping = mapping_hash[mime_type.to_sym]
11
+ raise(ArgumentError, "No data class registered for type #{mime_type.inspect}") unless(mapping)
12
+ mapping
13
+ end
14
+
15
+ # Gets the data class for the given mime type
16
+ def class_type_from(mime_type)
17
+ mapping_for(mime_type)[:type]
18
+ end
19
+
20
+ def loader_type_from(mime_type)
21
+ map = mapping_for(mime_type)
22
+ map[:loader] || map[:type]
23
+ end
24
+
25
+ # Currently this is only the default mapping
26
+ def mapping_hash
27
+ @mapping ||= {
28
+ :xml => { :type => XmlData },
29
+ :html =>{ :type => XmlData },
30
+ :tei => { :type => XmlData },
31
+ :hnml => { :type => XmlData },
32
+ :jpeg => { :type => ImageData, :loader => :create_iip },
33
+ :tiff => { :type => ImageData, :loader => :create_iip },
34
+ :png => { :type => ImageData, :loader => :create_iip },
35
+ :gif => { :type => ImageData, :loader => :create_iip },
36
+ :pdf => { :type => PdfData },
37
+ :text => { :type => SimpleText }
38
+ }
39
+ end
40
+
41
+
42
+ end
43
+
44
+ end
45
+ end