Class: Magick::Image

Inherits:
Object
  • Object
show all
Includes:
ClassLogging, Ownership, PerfStats
Defined in:
lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb

Overview

WARNING: ‘raise’ is overwritten with an image operation method; use Kernel::raise instead!

Constant Summary

Constants included from Ownership

Ownership::BorrowingDestoryedError, Ownership::BorrowingNotOwnedError, Ownership::UseDestroyedError

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Ownership

#borrow, #borrowed?, #get, #owned?

Class Method Details

.new_8bit(width, height, background_color = "none") ⇒ Object



21
22
23
24
25
26
27
28
29
30
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 21

def self.new_8bit(width, height, background_color = "none")
	Magick::Image.new(width, height) {
		self.depth = 8
		begin
			self.background_color = background_color
		rescue ArgumentError
			Kernel::raise Plugin::Thumbnailer::InvalidColorNameError.new(background_color)
		end
	}
end

Instance Method Details

#blur_region(x, y, w, h, radius, sigma) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 123

def blur_region(x, y, w, h, radius, sigma)
	# NOTE: we need to have bigger region to blure then the final regios to prevent edge artifacts
	# TODO: how do I calculate margin better? See: https://github.com/trevor/ImageMagick/blob/82d683349c7a6adc977f6f638f1b340e01bf0ea9/branches/ImageMagick-6.5.9/magick/gem.c#L787
	margin = [3, radius, sigma].max.ceil

	mx = x - margin
	my = y - margin
	mw = w + margin
	mh = h + margin

	# limit the box with margin to available image size
	mx = 0 if mx < 0
	my = 0 if my < 0
	mw = width - mx if mw + mx > width
	mh = height - my if mh + my > height

	crop(mx, my, mw, mh, true).get do |work_space|
		work_space.blur_image(radius, sigma)
	end.get do |blur|
		blur.crop(x - mx, y - my, w, h, true)
	end.get do |blur|
		get_for_inplace do |orig|
			orig.composite!(blur, x, y, Magick::OverCompositeOp)
		end
	end
end

#diagonalObject



204
205
206
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 204

def diagonal
	@_diag ||= Math.sqrt(width ** 2 + height ** 2).ceil
end

#downsample(f) ⇒ Object



71
72
73
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 71

def downsample(f)
	sample(columns / f, rows / f)
end

#find_downsample_factor(max_width, max_height, factor = 1) ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 75

def find_downsample_factor(max_width, max_height, factor = 1)
	new_factor = factor * 2
	if columns / new_factor > max_width * 2 and rows / new_factor > max_height * 2
		find_downsample_factor(max_width, max_height, factor * 2)
	else
		factor
	end
end

#float_to_offset(float_width, float_height, float_x = 0.5, float_y = 0.5) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 84

def float_to_offset(float_width, float_height, float_x = 0.5, float_y = 0.5)
	base_width = self.columns
	base_height = self.rows

	x = ((base_width - float_width) * float_x).ceil
	y = ((base_height - float_height) * float_y).ceil

	x = 0 if x < 0
	x = (base_width - float_width) if x > (base_width - float_width)

	y = 0 if y < 0
	y = (base_height - float_height) if y > (base_height - float_height)

	[x, y]
end

#get_for_inplaceObject

use this on image before doing in-place (like composite!) edit so borrowed images are not changed



11
12
13
14
15
16
17
18
19
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 11

def get_for_inplace
	get do |image|
		if image.borrowed?
			yield image.copy
		else
			yield image
		end
	end
end

#heightObject



200
201
202
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 200

def height
	rows
end

#pixelate_region(x, y, w, h, size) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 100

def pixelate_region(x, y, w, h, size)
	factor = 1.0 / size

	# what happens here
	# 1. get an required box cut form the image
	# 2. resize it down by fracto
	# 3. resize it back up by factor
	# 4. since we may end up with bigger image (due to size of the pixelate pixel) crop it to required size again
	# 5. composite over the original image in required position

	crop(x, y, w, h, true).get do |work_space|
		work_space.sample((factor * w).ceil, (factor * h).ceil)
	end.get do |image|
		image.sample(size)
	end.get do |image|
		image.crop(0, 0 , w, h, true)
	end.get do |image|
		get_for_inplace do |orig|
			orig.composite!(image, x, y, Magick::OverCompositeOp)
		end
	end
end

#rel_to_diagonal(v) ⇒ Object



192
193
194
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 192

def rel_to_diagonal(v)
	(v * diagonal).ceil
end

#rel_to_px_box(x, y, width, height) ⇒ Object



188
189
190
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 188

def rel_to_px_box(x, y, width, height)
	[*rel_to_px_pos(x, y), *rel_to_px_dim(width, height)]
end

#rel_to_px_dim(width, height) ⇒ Object



184
185
186
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 184

def rel_to_px_dim(width, height)
	[(width * columns).ceil, (height * rows).ceil]
end

#rel_to_px_pos(x, y) ⇒ Object



180
181
182
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 180

def rel_to_px_pos(x, y)
	[(x * columns).floor, (y * rows).floor]
end

#render_on_background(background_color, width = nil, height = nil, float_x = 0.5, float_y = 0.5) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 32

def render_on_background(background_color, width = nil, height = nil, float_x = 0.5, float_y = 0.5)
	# default to image size
	width ||= self.columns
	height ||= self.rows

	# make sure we have enough background to fit image on top of it
	width = self.columns if width < self.columns
	height = self.rows if height < self.rows

	self.class.new_8bit(width, height, background_color).get do |background|
		background.composite!(self, *background.float_to_offset(self.columns, self.rows, float_x, float_y), Magick::OverCompositeOp)
	end
end

#render_rectangle(x, y, w, h, color) ⇒ Object



150
151
152
153
154
155
156
157
158
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 150

def render_rectangle(x, y, w, h, color)
		get_for_inplace do |orig|
			gc = Magick::Draw.new
			gc.fill = color
			gc.rectangle(x, y, x + w - 1, y + h - 1)
			gc.draw(orig)
			orig
		end
end

#resize_to_fill(width, height = nil, float_x = 0.5, float_y = 0.5) ⇒ Object

non coping version



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 47

def resize_to_fill(width, height = nil, float_x = 0.5, float_y = 0.5)
	# default to square
	height ||= width

	return if width == columns and height == rows

	scale = [width / columns.to_f, height / rows.to_f].max

	get do |image| # this will comsume (destory) self just after resize
		image.resize((scale * columns).ceil, (scale * rows).ceil)
	end.get do |image|
		next if width == image.width and height == image.height
		image.crop(*image.float_to_offset(width, height, float_x, float_y), width, height, true)
	end
end

#rotate(*args) ⇒ Object



65
66
67
68
69
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 65

def rotate(*args)
	out = rotate_orig(*args)
	out.page = Magick::Rectangle.new(out.columns, out.rows, 0, 0)
	out
end

#rotate_origObject

make rotate not to change image.page to avoid WTF moments



64
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 64

alias :rotate_orig :rotate

#widthObject



196
197
198
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 196

def width
	columns
end

#with_background_color(color) ⇒ Object

helpers



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb', line 162

def with_background_color(color)
	if color
		was = self.background_color
		begin
			begin
				self.background_color = color
			rescue ArgumentError
				Kernel::raise Plugin::Thumbnailer::InvalidColorNameError.new(color)
			end
			yield
		ensure
			self.background_color = was
		end
	else
		yield
	end
end