talia_core 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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