Class: Plugin::Thumbnailer::Service

Inherits:
Object
  • Object
show all
Extended by:
Stats
Includes:
ClassLogging
Defined in:
lib/httpthumbnailer/plugin/thumbnailer.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Service

Returns a new instance of Service.



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 232

def initialize(options = {})
	@processing_methods = {}
	@options = options
	@images_loaded = 0

	log.info "initializing thumbnailer: #{self.class.rmagick_version} #{self.class.magick_version}"

	set_limit(:area, options[:limit_area]) if options.member?(:limit_area)
	set_limit(:memory, options[:limit_memory]) if options.member?(:limit_memory)
	set_limit(:map, options[:limit_map]) if options.member?(:limit_map)
	set_limit(:disk, options[:limit_disk]) if options.member?(:limit_disk)

	Magick.trace_proc = lambda do |which, description, id, method|
		case which
		when :c
			Service.stats.incr_images_loaded
			@images_loaded += 1
			Service.stats.max_images_loaded = Service.stats.images_loaded if Service.stats.images_loaded > Service.stats.max_images_loaded
			Service.stats.max_images_loaded_worker = @images_loaded if @images_loaded > Service.stats.max_images_loaded_worker
			Service.stats.incr_total_images_created
			case method
			when :from_blob
				Service.stats.incr_total_images_created_from_blob
			when :initialize
				Service.stats.incr_total_images_created_initialize
			when :resize
				Service.stats.incr_total_images_created_resize
			when :resize!
				Service.stats.incr_total_images_created_resize
			when :crop
				Service.stats.incr_total_images_created_crop
			when :crop!
				Service.stats.incr_total_images_created_crop
			when :sample
				Service.stats.incr_total_images_created_sample
			else
				log.warn "uncounted image creation method: #{method}"
			end
		when :d
			Service.stats.decr_images_loaded
			@images_loaded -= 1
			Service.stats.incr_total_images_destroyed
		end
		log.debug{"image event: #{which}, #{description}, #{id}, #{method}: loaded images: #{Service.stats.images_loaded}"}
	end
end

Class Method Details

.input_formatsObject



212
213
214
215
216
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 212

def self.input_formats
	Magick.formats.select do |name, mode|
		mode.include? 'r'
	end.keys.map(&:downcase)
end

.magick_versionObject



228
229
230
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 228

def self.magick_version
	Magick::Magick_version
end

.output_formatsObject



218
219
220
221
222
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 218

def self.output_formats
	Magick.formats.select do |name, mode|
		mode.include? 'w'
	end.keys.map(&:downcase)
end

.rmagick_versionObject



224
225
226
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 224

def self.rmagick_version
	Magick::Version
end

Instance Method Details

#load(io, options = {}) ⇒ Object



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 279

def load(io, options = {})
	mw = options[:max_width]
	mh = options[:max_height]
	if mw and mh
		mw = mw.to_i
		mh = mh.to_i
		log.info "using max size hint of: #{mw}x#{mh}"
	end

	begin
		blob = io.read

		old_memory_limit = nil
		borrowed_memory_limit = nil
		if options.member?(:limit_memory)
			borrowed_memory_limit = options[:limit_memory].borrow(options[:limit_memory].limit, 'image magick')
			old_memory_limit = set_limit(:memory, borrowed_memory_limit)
		end

		images = Magick::Image.from_blob(blob) do |info|
			if mw and mh
				define('jpeg', 'size', "#{mw*2}x#{mh*2}")
				define('jbig', 'size', "#{mw*2}x#{mh*2}")
			end
		end

		image = images.first
		if image.columns > image.base_columns or image.rows > image.base_rows and not options[:no_reload]
			log.warn "input image got upscaled from: #{image.base_columns}x#{image.base_rows} to #{image.columns}x#{image.rows}: reloading without max size hint!"
			images.each do |other|
				other.destroy!
			end
			images = Magick::Image.from_blob(blob)
			Service.stats.incr_total_images_reloaded
		end
		blob = nil

		images.shift.replace do |image|
			images.each do |other|
				other.destroy!
			end
			log.info "loaded image: #{image.inspect}"
			Service.stats.incr_total_images_loaded

			# clean up the image
			image.strip!
			image.properties do |key, value|
				log.debug "deleting user propertie '#{key}'"
				image[key] = nil
			end

			image
		end.replace do |image|
			if mw and mh and not options[:no_downscale]
				f = image.find_downscale_factor(mw, mh)
				if f > 1
					image = image.downscale(f)
					log.info "downscaled image by factor of #{f}: #{image.inspect}"
					Service.stats.incr_total_images_downscaled
				end
			end
			InputImage.new(image, @processing_methods)
		end
	rescue Magick::ImageMagickError => error
		raise ImageTooLargeError, error if error.message =~ /cache resources exhausted/
		raise UnsupportedMediaTypeError, error
	ensure
		if old_memory_limit
			set_limit(:memory, old_memory_limit)
			options[:limit_memory].return(borrowed_memory_limit, 'image magick')
		end
	end
end

#processing_method(method, &impl) ⇒ Object



353
354
355
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 353

def processing_method(method, &impl)
	@processing_methods[method] = impl
end

#set_limit(limit, value) ⇒ Object



357
358
359
360
361
# File 'lib/httpthumbnailer/plugin/thumbnailer.rb', line 357

def set_limit(limit, value)
	old = Magick.limit_resource(limit, value)
	log.info "changed #{limit} limit from #{old} to #{value} bytes"
	old
end