Class: Configuration::Thumbnail

Inherits:
Object
  • Object
show all
Extended by:
Stats
Includes:
ClassLogging, ConditionalInclusion
Defined in:
lib/httpimagestore/configuration/thumbnailer.rb

Defined Under Namespace

Classes: ThumbnailSpec, ThumbnailingError

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ConditionalInclusion

#excluded?, #included?, #inclusion_matcher

Constructor Details

#initialize(global, source_image_name, specs, use_multipart_api, matcher) ⇒ Thumbnail

Returns a new instance of Thumbnail.



145
146
147
148
149
150
151
# File 'lib/httpimagestore/configuration/thumbnailer.rb', line 145

def initialize(global, source_image_name, specs, use_multipart_api, matcher)
	@global = global
	@source_image_name = source_image_name
	@specs = specs
	@use_multipart_api = use_multipart_api
	inclusion_matcher matcher
end

Class Method Details

.match(node) ⇒ Object



99
100
101
# File 'lib/httpimagestore/configuration/thumbnailer.rb', line 99

def self.match(node)
	node.name == 'thumbnail'
end

.parse(configuration, node) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/httpimagestore/configuration/thumbnailer.rb', line 103

def self.parse(configuration, node)
	use_multipart_api = node.values.length == 1 ? true : false

	nodes = use_multipart_api ?  node.children : [node]
	source_image_name = use_multipart_api ? node.grab_values('source image name').first : nil # parsed later

	nodes.empty? and raise NoValueError.new(node, 'thumbnail image name')
	matcher = nil

	specs = nodes.map do |node|
		if use_multipart_api
			image_name = node.grab_values('thumbnail image name').first
		else
			source_image_name, image_name = *node.grab_values('source image name', 'thumbnail image name')
		end

		operation, width, height, format, if_image_name_on, remaining = *node.grab_attributes_with_remaining('operation', 'width', 'height', 'format', 'if-image-name-on')

		matcher = InclusionMatcher.new(image_name, if_image_name_on) if if_image_name_on

		ThumbnailSpec.new(
			image_name,
			operation || 'fit',
			width || 'input',
			height || 'input',
			format || 'input',
			remaining || {},
			matcher
		)
	end

	matcher = InclusionMatcher.new(source_image_name, node.grab_attributes('if-image-name-on').first) if use_multipart_api

	configuration.processors << self.new(
		configuration.global, 
		source_image_name, 
		specs, 
		use_multipart_api,
		matcher
	)
end

Instance Method Details

#realize(request_state) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/httpimagestore/configuration/thumbnailer.rb', line 153

def realize(request_state)
	client = @global.thumbnailer or fail 'thumbnailer configuration'

	rendered_specs = {}
	@specs.select do |spec|
		spec.included?(request_state)
	end.each do |spec|
		rendered_specs.merge! spec.render(request_state)
	end
	source_image = request_state.images[@source_image_name]

	thumbnails = {}
	input_mime_type = nil
	input_width = nil
	input_height = nil

	Thumbnail.stats.incr_total_thumbnail_requests
	Thumbnail.stats.incr_total_thumbnail_requests_bytes source_image.data.bytesize

	if @use_multipart_api
		log.info "thumbnailing '#{@source_image_name}' to multiple specs: #{rendered_specs}"

		# need to reference to local so they are available within thumbnail() block context
		source_image_name = @source_image_name
		logger = log

		begin
			thumbnails = client.thumbnail(source_image.data) do
				rendered_specs.each_pair do |name, spec|
					begin
						thumbnail(*spec)
					rescue HTTPThumbnailerClient::HTTPThumbnailerClientError => error
						logger.warn 'got thumbnailer error while passing specs', error
						raise ThumbnailingError.new(source_image_name, name, error)
					end
				end
			end
		rescue HTTPThumbnailerClient::HTTPThumbnailerClientError => error
			logger.warn 'got thumbnailer error while sending input data', error
			raise ThumbnailingError.new(source_image_name, nil, error)
		end

		input_mime_type = thumbnails.input_mime_type
		input_width = thumbnails.input_width
		input_height = thumbnails.input_height

		# check each thumbnail for errors
		thumbnails = Hash[rendered_specs.keys.zip(thumbnails)]
		thumbnails.each do |name, thumbnail|
			if thumbnail.kind_of? HTTPThumbnailerClient::HTTPThumbnailerClientError
				error = thumbnail
				log.warn 'got single thumbnail error', error
				raise ThumbnailingError.new(@source_image_name, name, error) 
			end
		end

		# borrow from memory limit - note that we might have already used too much memory
		thumbnails.each do |name, thumbnail|
			request_state.memory_limit.borrow(thumbnail.data.bytesize, "thumbnail '#{name}'")
		end
	else
		name, rendered_spec = *rendered_specs.first
		log.info "thumbnailing '#{@source_image_name}' to '#{name}' with spec: #{rendered_spec}"

		begin
			thumbnail = client.thumbnail(source_image.data, *rendered_spec)
			request_state.memory_limit.borrow(thumbnail.data.bytesize, "thumbnail '#{name}'")

			input_mime_type = thumbnail.input_mime_type
			input_width = thumbnail.input_width
			input_height = thumbnail.input_height

			thumbnails[name] = thumbnail
		rescue HTTPThumbnailerClient::HTTPThumbnailerClientError => error
			log.warn 'got thumbnailer error', error
			raise ThumbnailingError.new(@source_image_name, name, error)
		end
	end

	# copy input source path and url
	thumbnails.each do |name, thumbnail|
		thumbnail.extend ImageMetaData
		thumbnail.source_path = source_image.source_path
		thumbnail.source_url = source_image.source_url

		Thumbnail.stats.incr_total_thumbnail_thumbnails
		Thumbnail.stats.incr_total_thumbnail_thumbnails_bytes thumbnail.data.bytesize
	end

	# use httpthumbnailer provided information on input image mime type and size
	source_image.mime_type = input_mime_type if input_mime_type
	source_image.width = input_width if input_width
	source_image.height = input_height if input_height

	request_state.images.merge! thumbnails
end