Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge

  • Loading branch information...
commit 4ceca5340124d96f6e7bb8f3558f983d2f47d780 2 parents 25f2df6 + 114a2e9
Paul Nicholson paulnicholson authored
BIN  generators/.DS_Store
Binary file not shown
BIN  generators/beach.jpg
BIN  generators/church.jpg
454 generators/courtyard.rb
... ... @@ -0,0 +1,454 @@
  1 +require '../acrylic'
  2 +class Courtyard < ImageGenerator
  3 + color :lighter, [0.29, 0.9, 0.9]
  4 + color :light, [0.29, 0.9, 0.8]
  5 + color :dark, [0.29, 0.9, 0.63]
  6 +
  7 + color :orange, [0.1, 1, 0.6]
  8 + color :lighter_orange, [0.1, 1, 0.75]
  9 +
  10 + image :map do
  11 + dimensions 400, 300
  12 + margin 4
  13 + curl = 6
  14 + cr.move_to 0, 0
  15 + cr.line_to width, 0
  16 + cr.line_to width + 1, height
  17 + curve = Curve.new(cr)
  18 + curve.point(width + 1, height, 150.deg, 0)
  19 + curve.point(width/2, height - curl, 180.deg, 50)
  20 + curve.point(-1, height, 210.deg, 0)
  21 + curve.draw_control_points(curve)
  22 + cr.line_to 0, 0
  23 + black! 0.4
  24 + cr.fill
  25 +
  26 + @surface.blur 10
  27 +
  28 + cr.rectangle(0, 0, width, height - curl)
  29 + white!
  30 + cr.fill
  31 +
  32 + load_image 'map.png'
  33 + cr.rectangle(4, 4, width - 8, height - curl - 8)
  34 + # cr.rectangle(0, 0, width, height - curl)
  35 + cr.fill
  36 + end
  37 +
  38 + shape :gate, 130, 90 do
  39 + def draw_bar(x, y)
  40 + cr.move_to x, y
  41 + cr.line_to x - 3, y + 5
  42 + cr.line_to x - 1, y + 7
  43 + cr.line_to x - 1, height
  44 + cr.line_to x + 1, height
  45 + cr.line_to x + 1, y + 7
  46 + cr.line_to x + 3, y + 5
  47 + cr.close_path
  48 + cr.fill
  49 + end
  50 +
  51 + def draw_side
  52 + curve_height = 30
  53 + gate_top = 10
  54 + cr.line_width = 2
  55 +
  56 + curve = Curve.new(cr)
  57 + curve.point(3, curve_height, 0.deg, 20)
  58 + curve.point(width/2 - 1, gate_top, 0.deg, 30)
  59 + curve.draw_control_points(curve)
  60 + cr.stroke
  61 +
  62 + curve.each { |p| p.y += 30 }
  63 + curve.draw_control_points(curve)
  64 + cr.stroke
  65 +
  66 + cr.move_to width/2 - 4, gate_top - 0.5
  67 + cr.line_to width/2 - 4, height
  68 + cr.line_width = 6
  69 + cr.stroke
  70 +
  71 + cr.move_to width/2 - 1, height
  72 + cr.line_to 2, height
  73 + cr.line_width = 4
  74 + cr.stroke
  75 +
  76 + draw_bar(3, 19)
  77 + draw_bar(11, 18)
  78 + draw_bar(19, 15)
  79 + draw_bar(27, 11)
  80 + draw_bar(35, 7)
  81 + draw_bar(43, 4)
  82 + draw_bar(52, 1.5)
  83 + draw_bar(61, 0)
  84 + end
  85 +
  86 + draw_side
  87 + transform cr.matrix.translate(width, 0).scale(-1, 1) do
  88 + draw_side
  89 + end
  90 + end
  91 +
  92 + image :header do
  93 + dimensions 900, 120
  94 + margin 4
  95 + linear_gradient 0, 0, 0, height + bottom_margin, light, dark
  96 + rounded_rectangle 0, 0, width, height * 2, 40
  97 + cr.fill_preserve
  98 + cr.clip
  99 +
  100 + linear_gradient 0, height/3, 0, height + bottom_margin + 10, dark, light
  101 + # rounded_rectangle 0, height/2 - 10, width, height, 70
  102 + curve = Curve.new(cr)
  103 + curve.point -80, height + bottom_margin, 45.deg, 5
  104 + curve.point width/2, height/3, 0.deg, 500
  105 + curve.point width + 80, height + bottom_margin, -45.deg, 5
  106 + curve.draw_control_points(curve)
  107 + cr.close_path
  108 + cr.fill
  109 +
  110 + # @surface.blur 2
  111 + # rounded_rectangle 0, 0, width, height * 2, 40
  112 + # clip!
  113 +
  114 +
  115 + white!
  116 + draw_gate 16, 8
  117 +
  118 + draw_text_box 160, 16 do |tb|
  119 + tb.line("Courtyard", :face => "Georgia", :size => 80)
  120 + end
  121 +
  122 + shadow 5, 0.5
  123 + end
  124 +
  125 + image :organizations_bar do
  126 + dimensions 900, 40
  127 + margin 0, 4
  128 + cr.rectangle 0, 0, width, height
  129 + linear_gradient 0, 0, 0, height, orange, lighter_orange
  130 + cr.fill
  131 +
  132 + cr.rectangle 0, 0, width, 3
  133 + linear_gradient 0, 0, 0, 3, black.a(0.15), black.a(0.1), black.a(0)
  134 + cr.fill
  135 +
  136 + cr.rectangle 0, height-1, width, 1
  137 + white! 0.4
  138 + # linear_gradient 0, height-1, 0, height, white.a(0), white.a(0.3), white.a(0.5)
  139 + cr.fill
  140 +
  141 + shadow 5, 0.5
  142 + end
  143 +
  144 + image :page do
  145 + dimensions 920, 200
  146 + margin 10
  147 + draw_image :header, 0, 0
  148 + draw_image :organizations_bar, 0, 120
  149 + end
  150 +
  151 + color :frame_light, [0, 0, 0.3]
  152 + color :frame_dark, [0, 0, 0.2]
  153 + image :frame do
  154 + dimensions 400, 300
  155 + margin 8
  156 +
  157 + border = 40
  158 +
  159 + # bottom
  160 + draw_frame_side 0, height - border, 0, height, frame_light, frame_dark do
  161 + cr.move_to 0, height
  162 + cr.line_to width, height
  163 + cr.line_to width - border, height - border
  164 + cr.line_to border, height - border
  165 + cr.close_path
  166 + end
  167 +
  168 + # left
  169 + draw_frame_side 0, 0, border, 0, frame_dark, frame_light do
  170 + cr.move_to 0, 0
  171 + cr.line_to 0, height
  172 + cr.line_to border, height - border
  173 + cr.line_to border, border
  174 + cr.close_path
  175 + end
  176 +
  177 + # right
  178 + draw_frame_side width - border, 0, width, 0, frame_light, frame_dark do
  179 + cr.move_to width, 0
  180 + cr.line_to width, height
  181 + cr.line_to width - border, height - border
  182 + cr.line_to width - border, border
  183 + cr.close_path
  184 + end
  185 +
  186 + # top
  187 + draw_frame_side 0, 0, 0, border, frame_light, frame_dark do
  188 + cr.move_to 0, 0
  189 + cr.line_to width, 0
  190 + cr.line_to width - border + 1, border
  191 + cr.line_to border, border
  192 + cr.close_path
  193 + end
  194 +
  195 + 2.times {shadow 10, 0.7}
  196 +
  197 + frame = layer!
  198 + load_image_and_scale 'church.jpg', width - border*2, height - border*2
  199 + cr.source.matrix = Cairo::Matrix.identity.translate(-border, -border)
  200 + cr.rectangle(border, border, width - border*2, height - border*2)
  201 + cr.fill
  202 + cr.paint
  203 +
  204 + linear_gradient 0, 0, 0, 180, white.a(0.6), white.a(0)
  205 + cr.move_to 0, 0
  206 + cr.line_to 0, 120
  207 + cr.line_to width, 160
  208 + cr.line_to width, 0
  209 + cr.close_path
  210 + cr.fill
  211 +
  212 + margin 0
  213 + cr.set_source(Cairo::SurfacePattern.new(frame))
  214 + cr.paint
  215 + end
  216 +
  217 + def draw_frame_side(*gradient_args, &block)
  218 + original = layer!
  219 + original_margins = [@top_margin, @right_margin, @bottom_margin, @left_margin]
  220 + yield
  221 + path = cr.copy_path
  222 + black!
  223 + cr.fill
  224 + mask = layer!
  225 + cr.append_path path
  226 + black!
  227 + cr.fill
  228 + @surface.blur 10
  229 + height_map = layer!
  230 + @surface.bump_map(height_map, width.to_i/2 + @left_margin, -80, 800, 10, 5)
  231 + bump = layer!
  232 + margin 0
  233 + cr.set_source(Cairo::SurfacePattern.new(original))
  234 + cr.paint
  235 +
  236 + margin *original_margins
  237 + cr.append_path path
  238 + linear_gradient *gradient_args
  239 + cr.fill
  240 + margin 0
  241 + cr.set_source(Cairo::SurfacePattern.new(bump))
  242 + cr.mask(Cairo::SurfacePattern.new(mask))
  243 + margin *original_margins
  244 + end
  245 +
  246 + def draw_cork_board_side(side, *gradient_args, &block)
  247 + original = layer!
  248 + yield
  249 + path = cr.copy_path
  250 + black!
  251 + cr.fill
  252 + mask = layer!
  253 + cr.append_path path
  254 + black!
  255 + cr.fill
  256 + @surface.blur 4
  257 + height_map = layer!
  258 + @surface.bump_map(height_map, width.to_i/2 + @left_margin, -320, 3200, 1, 3)
  259 + bump = layer!
  260 +
  261 + cr.append_path path
  262 + grain! 0.4
  263 + fill_with_noise
  264 + if [:top, :bottom].include?(side)
  265 + @surface.horizontal_blur 10
  266 + @surface.horizontal_blur 10
  267 + @surface.horizontal_blur 10
  268 + else
  269 + @surface.vertical_blur 10
  270 + @surface.vertical_blur 10
  271 + @surface.vertical_blur 10
  272 + end
  273 + grain = layer!
  274 +
  275 + paint_layer original
  276 +
  277 + cr.append_path path
  278 + linear_gradient *gradient_args
  279 + cr.fill
  280 +
  281 + transform Cairo::Matrix.identity do
  282 + cr.set_source(Cairo::SurfacePattern.new(grain))
  283 + cr.mask(Cairo::SurfacePattern.new(mask))
  284 + cr.set_source(Cairo::SurfacePattern.new(bump))
  285 + cr.mask(Cairo::SurfacePattern.new(mask))
  286 + end
  287 + end
  288 +
  289 + def load_image_and_scale(path, width, height)
  290 + image = Gdk::Pixbuf.new(File.join(File.dirname($0), path))
  291 + tmp_surface = Cairo::ImageSurface.new(image.width, image.height)
  292 + tmp_cr = Cairo::Context.new(tmp_surface)
  293 + tmp_cr.set_source_pixbuf(image)
  294 + tmp_cr.paint
  295 + smaller = tmp_surface.downsample((image.width/width).ceil)
  296 + cr.set_source(Cairo::SurfacePattern.new(smaller))
  297 + end
  298 +
  299 + def layer!
  300 + surface = @surface
  301 + dimensions @canvas_width, @canvas_height
  302 + margin @top_margin, @right_margin, @bottom_margin, @left_margin
  303 + surface
  304 + end
  305 +
  306 + color :cork_board_light, [0.11, 0.5, 0.8]
  307 + color :cork_board_dark, [0.11, 0.5, 0.7]
  308 + color :cork, [0.08, 0.5, 0.4]
  309 + color :grain, [0.08, 0.5, 0.2]
  310 + image :cork_board do
  311 + dimensions 400, 300
  312 + margin 8
  313 + border = 20
  314 +
  315 + draw_cork_board_side :bottom, 0, height - border, 0, height, cork_board_light, cork_board_dark do
  316 + cr.move_to 0, height
  317 + cr.line_to width, height
  318 + cr.line_to width - border, height - border
  319 + cr.line_to border, height - border
  320 + cr.close_path
  321 + end
  322 +
  323 + draw_cork_board_side :left, 0, 0, border, 0, cork_board_dark, cork_board_light do
  324 + cr.move_to 0, 0
  325 + cr.line_to 0, height
  326 + cr.line_to border, height - border
  327 + cr.line_to border, border
  328 + cr.close_path
  329 + end
  330 +
  331 + draw_cork_board_side :right, width - border, 0, width, 0, cork_board_light, cork_board_dark do
  332 + cr.move_to width, 0
  333 + cr.line_to width, height
  334 + cr.line_to width - border, height - border
  335 + cr.line_to width - border, border
  336 + cr.close_path
  337 + end
  338 +
  339 + draw_cork_board_side :top, 0, 0, 0, border, cork_board_light, cork_board_dark do
  340 + cr.move_to 0, 0
  341 + cr.line_to width, 0
  342 + cr.line_to width - border + 1, border
  343 + cr.line_to border, border
  344 + cr.close_path
  345 + end
  346 +
  347 + 2.times {shadow 10, 0.7}
  348 +
  349 + frame = layer!
  350 +
  351 + cork!
  352 + cr.rectangle border, border, width - border*2, height - border*2
  353 + cr.fill_preserve
  354 + black!(0.2)
  355 + fill_with_noise
  356 +
  357 + paint_layer frame
  358 +
  359 + draw_photo 'beach.jpg', 120, 160, 0.deg, :right
  360 + draw_photo 'party.jpg', 205, 195, 5.deg, :left
  361 + draw_photo 'game.jpg', 250, 70, -4.deg, :right
  362 + draw_photo 'restaurant.jpg', -10, 160, 8.deg, :right
  363 + draw_photo 'picnic.jpg', 20, 10, -8.deg, :left
  364 + draw_photo 'park.jpg', 100, 90, 10.deg, :left
  365 + draw_photo 'outside_church.jpg', 210, 10, -2.deg, :left
  366 + end
  367 +
  368 + def draw_photo(path, x, y, theta, curl_side = :right)
  369 + background = layer!
  370 + load_image_and_scale(path, 130, 130)
  371 + cr.source.matrix = Cairo::Matrix.identity.translate(-x, -y)
  372 + w, h = cr.source.surface.width, cr.source.surface.height
  373 + transform cr.matrix.rotate(-theta) do
  374 + curl = 6
  375 + cr.move_to x, y
  376 + cr.line_to x + w, y
  377 + if curl_side == :right
  378 + cr.line_to x + w + 2, y + h + curl
  379 + cr.line_to x - 2, y + h + 2
  380 + else
  381 + cr.line_to x + w + 2, y + h + 2
  382 + cr.line_to x - 2, y + h + curl
  383 + end
  384 + cr.close_path
  385 + picture = cr.source
  386 + black! 0.6
  387 + cr.fill
  388 + @surface.blur 10
  389 +
  390 + cr.move_to x, y
  391 + cr.line_to x + w, y
  392 + cr.line_to x + w, y + h
  393 + cr.line_to x, y + h
  394 + cr.close_path
  395 +
  396 + cr.set_source(picture)
  397 + cr.fill_preserve
  398 +
  399 + white!
  400 + cr.stroke
  401 + end
  402 + photo = layer!
  403 +
  404 + transform cr.matrix.rotate(-theta) do
  405 + black!
  406 + cr.circle x + w/2 + 3, y + 13, 5
  407 + cr.fill
  408 + @surface.blur 10
  409 +
  410 +
  411 + white! 0.1
  412 + cr.circle x + w/2 + 0.5, y + 10.5, 5
  413 + cr.fill
  414 +
  415 + linear_gradient 0, y, 0, y + 15, hsl(0, 0, 0.2), hsl(0, 0, 0.0)
  416 + cr.circle x + w/2, y + 10, 5
  417 + cr.fill
  418 +
  419 + white! 0.1
  420 + cr.circle x + w/2 - 2.5, y + 8.5, 4
  421 + cr.fill
  422 +
  423 + linear_gradient 0, y, 0, y + 15, hsl(0, 0, 0.2), hsl(0, 0, 0.0)
  424 + cr.circle x + w/2 - 3, y + 8, 4
  425 + cr.fill
  426 + end
  427 + thumbtack = layer!
  428 +
  429 + paint_layer background
  430 + paint_layer photo
  431 + paint_layer thumbtack
  432 + end
  433 +
  434 + def paint_layer(layer)
  435 + transform Cairo::Matrix.identity do
  436 + cr.set_source(Cairo::SurfacePattern.new(layer))
  437 + cr.paint
  438 + end
  439 + end
  440 +
  441 + def fill_with_noise
  442 + cr.clip
  443 + noise = Cairo::ImageSurface.new(Cairo::FORMAT_A8, @canvas_width, @canvas_height)
  444 + noise.render_noise
  445 + cr.mask(Cairo::SurfacePattern.new(noise))
  446 + cr.reset_clip
  447 + end
  448 +end
  449 +# Courtyard.preview(:page)
  450 +# Courtyard.preview(:organizations_bar)
  451 +# Courtyard.preview(:header)
  452 +# Courtyard.preview(:map)
  453 +# Courtyard.preview(:frame)
  454 +Courtyard.preview(:cork_board)
BIN  generators/game.jpg
BIN  generators/map.png
BIN  generators/outside_church.jpg
BIN  generators/park.jpg
BIN  generators/party.jpg
BIN  generators/picnic.jpg
BIN  generators/restaurant.jpg
109 lib/cairo_tools.rb
@@ -8,20 +8,9 @@
8 8
9 9 module CairoTools
10 10 include Color
11   - attr_reader :surface, :cr, :height, :width
  11 + attr_reader :surface, :cr, :canvas_height, :canvas_width, :top_margin, :right_margin, :bottom_margin, :left_margin
12 12 attr_accessor :preview
13 13
14   - def self.color(name, color)
15   - color = Color::HSL.new(color)
16   - define_method(name) {color}
17   - define_method(name.bang) {set_color(color)}
18   - @colors ||= {}
19   - @colors[name] = color
20   - end
21   -
22   - color :black, '000'
23   - color :white, 'FFF'
24   -
25 14 def generate_image(path, options)
26 15 # dummy context is useful sometimes
27 16 @surface = Cairo::ImageSurface.new(1, 1)
@@ -31,19 +20,35 @@ def generate_image(path, options)
31 20 end
32 21
33 22 def dimensions(width, height)
34   - @width, @height = width, height
  23 + @canvas_width, @canvas_height = width, height
35 24 @surface = Cairo::ImageSurface.new(width, height)
36 25 @cr = Cairo::Context.new(surface)
37 26 end
38   -
39   - def outline(width=nil)
40   - cr.line_width = width if width
  27 +
  28 + def margin(*rect)
  29 + rect = rect + rect if rect.length == 1
  30 + rect = rect + rect if rect.length == 2
  31 + @top_margin, @right_margin, @bottom_margin, @left_margin = rect
  32 + cr.matrix = Cairo::Matrix.identity.translate(left_margin, top_margin)
  33 + end
  34 +
  35 + def width
  36 + canvas_width - right_margin - left_margin
  37 + end
  38 +
  39 + def height
  40 + canvas_height - top_margin - bottom_margin
  41 + end
  42 +
  43 + def transform(matrix, &block)
  44 + old_matrix = cr.matrix
  45 + cr.matrix = matrix
41 46 yield
42   - cr.stroke
  47 + cr.matrix = old_matrix
43 48 end
44 49
45 50 # http://www.cairographics.org/cookbook/roundedrectangles/
46   - def rounded_rectangle(x, y, w, h, radius_x=5, radius_y=5)
  51 + def rounded_rectangle(x, y, w, h, radius_x=5, radius_y=radius_x)
47 52 arc_to_bezier = 0.55228475
48 53 radius_x = w / 2 if radius_x > w - radius_x
49 54 radius_y = h / 2 if radius_y > h - radius_y
@@ -108,12 +113,12 @@ def gradient(gradient, *colors)
108 113 cr.set_source(gradient)
109 114 end
110 115
111   - def shadow
112   - shadow_surface = Cairo::ImageSurface.new(width, height)
  116 + def shadow(radius=3, alpha=1)
  117 + shadow_surface = Cairo::ImageSurface.new(@canvas_width, @canvas_height)
113 118 shadow_cr = Cairo::Context.new(shadow_surface)
114   - shadow_cr.set_source_rgba(0, 0, 0, 1)
  119 + shadow_cr.set_source_rgba(0, 0, 0, alpha)
115 120 shadow_cr.mask(Cairo::SurfacePattern.new(surface))
116   - shadow_surface.blur
  121 + shadow_surface.blur(radius)
117 122 shadow_cr.set_source(Cairo::SurfacePattern.new(surface))
118 123 shadow_cr.paint
119 124 @surface = shadow_surface
@@ -125,12 +130,70 @@ def get_pixel(x, y)
125 130 end
126 131
127 132 def load_image(path, x=0, y=0)
128   - image = Gdk::Pixbuf.new(File.join(File.dirname(__FILE__), path))
  133 + image = Gdk::Pixbuf.new(File.join(File.dirname($0), path))
129 134 cr.set_source_pixbuf(image)
130 135 cr.source.matrix = Cairo::Matrix.identity.translate(x, y)
131 136 end
132 137
  138 + def clip!
  139 + i = self.class.new
  140 + w, h = @canvas_width, @canvas_height
  141 + pattern = Cairo::SurfacePattern.new(@surface)
  142 + clip = cr.copy_path
  143 + i.instance_eval do
  144 + dimensions w, h
  145 + cr.append_path clip
  146 + cr.clip
  147 + cr.set_source(pattern)
  148 + cr.paint
  149 + end
  150 + dimensions w, h
  151 + cr.set_source(Cairo::SurfacePattern.new(i.surface))
  152 + cr.paint
  153 + end
  154 +
  155 + def transparent!(alpha)
  156 + i = self.class.new
  157 + w, h = @canvas_width, @canvas_height
  158 + pattern = Cairo::SurfacePattern.new(@surface)
  159 + i.instance_eval do
  160 + dimensions w, h
  161 + cr.set_source(pattern)
  162 + cr.paint_with_alpha(alpha)
  163 + end
  164 + @surface = i.surface
  165 + @cr = i.cr
  166 + end
  167 +
  168 + def draw_image(image, x=0, y=0, a=1)
  169 + i = self.class.new
  170 + i.instance_eval do
  171 + draw(image)
  172 + end
  173 + cr.set_source(Cairo::SurfacePattern.new(i.surface))
  174 + cr.source.matrix = Cairo::Matrix.identity.translate(-x, -y)
  175 + cr.paint_with_alpha(a)
  176 + end
  177 +
133 178 def clouds
134 179 Cairo::ImageSurface.new(129, 129)
135 180 end
  181 +end
  182 +
  183 +class Cairo::Context
  184 + inline(:C) do |builder|
  185 + builder.include '<stdlib.h>'
  186 + builder.include '<cairo.h>'
  187 + builder.include '<rb_cairo.h>'
  188 + builder.include '<intern.h>'
  189 + builder.add_compile_flags '`/opt/local/bin/pkg-config --cflags cairo`'
  190 + builder.add_compile_flags '-I/opt/local/lib/ruby/site_ruby/1.8/i686-darwin9/'
  191 + builder.add_compile_flags '-I/opt/local/lib/ruby/gems/1.8/gems/cairo-1.6.2/src'
  192 + builder.c %{
  193 + void paint_with_alpha(double alpha) {
  194 + cairo_t *cr = RVAL2CRCONTEXT(self);
  195 + cairo_paint_with_alpha(cr, alpha);
  196 + }
  197 + }
  198 + end
136 199 end
40 lib/image_generator.rb
... ... @@ -1,7 +1,39 @@
1 1 require 'cairo_tools'
  2 +require 'shape'
2 3 class ImageGenerator
3 4 include CairoTools
4 5
  6 + def self.colors
  7 + @@colors ||= {}
  8 + end
  9 +
  10 + def self.color(name, color)
  11 + color = Color::HSL.new(color)
  12 + colors[name] = color
  13 + self.class_eval <<-"end;"
  14 + def #{name}
  15 + self.class.colors[:#{name}]
  16 + end
  17 + def #{name}!(a=nil)
  18 + set_color(a ? #{name}.a(a) : #{name})
  19 + end
  20 + end;
  21 + end
  22 +
  23 + color :black, '000'
  24 + color :white, 'FFF'
  25 +
  26 + def self.shapes
  27 + @@shapes ||= {}
  28 + end
  29 +
  30 + def self.shape(name, width, height, &block)
  31 + shapes[name] = shape = Shape.new(name, width, height, block)
  32 + define_method("draw_#{name}") do |x, y|
  33 + shape.draw(cr, x, y)
  34 + end
  35 + end
  36 +
5 37 def self.generate_image(path, *options)
6 38 new.generate_image(path, options)
7 39 end
@@ -24,11 +56,11 @@ def self.preview(*options)
24 56
25 57 def self.image(name, options={:suite => true}, &block)
26 58 images[name] = block
27   - suite << name if options[:suite]
  59 + suite_images << name if options[:suite]
28 60 end
29 61
30   - def self.suite
31   - @suite ||= []
  62 + def self.suite_images
  63 + @suite_images ||= []
32 64 end
33 65
34 66 def self.images
@@ -36,7 +68,7 @@ def self.images
36 68 end
37 69
38 70 def self.suite(prefix, *args)
39   - suite.each do |name|
  71 + suite_images.each do |name|
40 72 generate("#{prefix}_#{name}.png", name, *args)
41 73 end
42 74 end
240 lib/image_surface_extensions.rb
... ... @@ -1,7 +1,245 @@
1   -require 'native_image_surface_extensions'
  1 +# require 'native_image_surface_extensions'
2 2 require 'color'
3 3
4 4 class Cairo::ImageSurface
  5 + inline(:C) do |builder|
  6 + builder.include '<stdlib.h>'
  7 + builder.include '<math.h>'
  8 + builder.include '<cairo.h>'
  9 + builder.include '<rb_cairo.h>'
  10 + builder.include '<intern.h>'
  11 + builder.add_compile_flags '`pkg-config --cflags cairo`'
  12 + builder.add_compile_flags '-I/opt/local/lib/ruby/site_ruby/1.8/i686-darwin9/'
  13 + builder.add_compile_flags '-I/opt/local/lib/ruby/gems/1.8/gems/cairo-1.6.2/src'
  14 + builder.c %{
  15 + void vertical_blur(int radius) {
  16 + cairo_surface_t *surface = RVAL2CRSURFACE(self);
  17 + unsigned char *data = cairo_image_surface_get_data(surface);
  18 + int width = cairo_image_surface_get_width(surface);
  19 + int height = cairo_image_surface_get_height(surface);
  20 + int stride = cairo_image_surface_get_stride(surface);
  21 + int length = height*stride;
  22 +
  23 + cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  24 + unsigned char *tmp_data = cairo_image_surface_get_data(tmp_surface);
  25 +
  26 + unsigned char *color;
  27 + unsigned char *color2;
  28 + double sumr, sumg, sumb, suma;
  29 + int gauss_w = radius*2 + 1;
  30 + int *mask = triangle[radius];
  31 + int gauss_sum = sums[radius];
  32 + int i, j, k, x, y;
  33 + for (i = 0; i < height; i++) {
  34 + for (j = 0; j < width; j++) {
  35 + color = data + i*stride + j*4;
  36 + if (color < data || color > data + length) continue;
  37 + color2 = tmp_data + i*stride + j*4;
  38 + color2[0] = color[0];
  39 + color2[1] = color[1];
  40 + color2[2] = color[2];
  41 + color2[3] = color[3];
  42 + }
  43 + }
  44 + for (i = 0; i < height; i++) {
  45 + for (j = 0; j < width; j++) {
  46 + sumr = sumg = sumb = suma = 0;
  47 + for (k = 0; k < gauss_w; k++) {
  48 + y = i-radius+k;
  49 + if (y > height || y < 0) continue;
  50 + color = data + y*stride + j*4;
  51 + if (color < data || color > data + length) continue;
  52 + suma += color[0]*mask[k];
  53 + sumr += color[1]*mask[k];
  54 + sumg += color[2]*mask[k];
  55 + sumb += color[3]*mask[k];
  56 + }
  57 + color = data + i*stride + j*4;
  58 + color[0] = suma/gauss_sum;
  59 + color[1] = sumr/gauss_sum;
  60 + color[2] = sumg/gauss_sum;
  61 + color[3] = sumb/gauss_sum;
  62 + }
  63 + }
  64 + }
  65 + }
  66 + builder.c %{
  67 + void horizontal_blur(int radius) {
  68 + cairo_surface_t *surface = RVAL2CRSURFACE(self);
  69 + unsigned char *data = cairo_image_surface_get_data(surface);
  70 + int width = cairo_image_surface_get_width(surface);
  71 + int height = cairo_image_surface_get_height(surface);
  72 + int stride = cairo_image_surface_get_stride(surface);
  73 + int length = height*stride;
  74 +
  75 + cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  76 + unsigned char *tmp_data = cairo_image_surface_get_data(tmp_surface);
  77 +
  78 + unsigned char *color;
  79 + unsigned char *color2;
  80 + double sumr, sumg, sumb, suma;
  81 + int gauss_w = radius*2 + 1;
  82 + int *mask = triangle[radius];
  83 + int gauss_sum = sums[radius];
  84 + int i, j, k, x, y;
  85 + for (i = 0; i < height; i++) {
  86 + for (j = 0; j < width; j++) {
  87 + color = data + i*stride + j*4;
  88 + if (color < data || color > data + length) continue;
  89 + color2 = tmp_data + i*stride + j*4;
  90 + color2[0] = color[0];
  91 + color2[1] = color[1];
  92 + color2[2] = color[2];
  93 + color2[3] = color[3];
  94 + }
  95 + }
  96 + for (i = 0; i < height; i++) {
  97 + for (j = 0; j < width; j++) {
  98 + sumr = sumg = sumb = suma = 0;
  99 + for (k = 0; k < gauss_w; k++) {
  100 + int x = j-radius+k;
  101 + if (x > width || x < 0) continue;
  102 + color = tmp_data + i*stride + x*4;
  103 + if (color < tmp_data || color > tmp_data + length) continue;
  104 + suma += color[0]*mask[k];
  105 + sumr += color[1]*mask[k];
  106 + sumg += color[2]*mask[k];
  107 + sumb += color[3]*mask[k];
  108 + }
  109 + color = data + i*stride + j*4;
  110 + color[0] = suma/gauss_sum;
  111 + color[1] = sumr/gauss_sum;
  112 + color[2] = sumg/gauss_sum;
  113 + color[3] = sumb/gauss_sum;
  114 + }
  115 + }
  116 + }
  117 + }
  118 + builder.prefix %{
  119 + int abs(int x) {
  120 + return x < 0 ? -x : x;
  121 + }
  122 + }
  123 + builder.c %{
  124 + void render_bump_map(VALUE height_map, int light_x, int light_y, int light_radius, int specular_radius, double normal_coefficient) {
  125 + cairo_surface_t *surface = RVAL2CRSURFACE(self);
  126 + unsigned int *data = (unsigned int *) cairo_image_surface_get_data(surface);
  127 + int width = cairo_image_surface_get_width(surface);
  128 + int height = cairo_image_surface_get_height(surface);
  129 + int stride = cairo_image_surface_get_stride(surface);
  130 + int length = height * stride;
  131 +
  132 + cairo_surface_t *height_surface = RVAL2CRSURFACE(height_map);
  133 + unsigned char *height_data = cairo_image_surface_get_data(height_surface);
  134 +
  135 + int x, y;
  136 + for (y = 0; y < height; y++) {
  137 + for (x = 0; x < width; x++) {
  138 + int xnext = y * stride + (x + 1) * 4 - 1;
  139 + int xprev = y * stride + (x - 1) * 4 - 1;
  140 + int xn = (xnext > length || xprev < 0) ? 0 : (height_data[xnext] - height_data[xprev]);
  141 + int ynext = (y + 1) * stride + x * 4 - 1;
  142 + int yprev = (y - 1) * stride + x * 4 - 1;
  143 + int yn = (ynext > length || yprev < 0) ? 0 : (height_data[ynext] - height_data[yprev]);
  144 + int ex = abs(xn*normal_coefficient - x + light_x);
  145 + int ey = abs(yn*normal_coefficient - y + light_y);
  146 +
  147 + if (ex > light_radius - 1) ex = light_radius - 1;
  148 + if (ey > light_radius - 1) ey = light_radius - 1;
  149 +
  150 + unsigned int color;
  151 + int magnitude = (int) sqrtf((float)ex*ex+ey*ey);
  152 + if (magnitude < specular_radius) {
  153 + int alpha = 255 - magnitude*255/specular_radius;
  154 + if (alpha > 255) alpha = 255;
  155 + if (alpha < 0) alpha = 0;
  156 + color = (alpha << 24) + (alpha << 16) + (alpha << 8) + alpha;
  157 + //printf("specular %x\\n", color);
  158 + } else {
  159 + int alpha = (magnitude - specular_radius)*255/(light_radius - specular_radius);
  160 + if (alpha > 255) alpha = 255;
  161 + if (alpha < 0) alpha = 0;
  162 + color = 0xFF000000 & (alpha << 24);
  163 + //printf("diffuse %i\\n", xn);
  164 + }
  165 + data[y * width + x] = color;
  166 + }
  167 + }
  168 + }
  169 + }
  170 + builder.c %{
  171 + VALUE downsample(int scale) {
  172 + cairo_surface_t *surface = RVAL2CRSURFACE(self);
  173 + unsigned int *data = (unsigned int *) cairo_image_surface_get_data(surface);
  174 + int width = cairo_image_surface_get_width(surface);
  175 + int height = cairo_image_surface_get_height(surface);
  176 +
  177 + int w = width / scale;
  178 + int h = height / scale;
  179 + cairo_surface_t *output_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
  180 + unsigned int *output_data = (unsigned int *) cairo_image_surface_get_data(output_surface);
  181 + int denominator = scale * scale;
  182 +
  183 + unsigned char * pixel;
  184 + int i, j, k, l;
  185 + int r, g, b, a;
  186 +
  187 + for (i=0; i<w+1; i++) {
  188 + for (j=0; j<h+1; j++) {
  189 + r = g = b = a = 0;
  190 + for (k=0; k<scale; k++) {
  191 + for (l=0; l<scale; l++) {
  192 + pixel = (unsigned char *) (data + (j*scale + l)*width + i*scale + k);
  193 + if (pixel < (unsigned char *) data || pixel > (unsigned char *) (data + width * height)) continue;
  194 + r += pixel[0];
  195 + g += pixel[1];
  196 + b += pixel[2];
  197 + a += pixel[3];
  198 + }
  199 + }
  200 + pixel = (unsigned char *) (output_data + j*w + i);
  201 + if (pixel < (unsigned char *) output_data || pixel > (unsigned char *) (output_data + h*w)) continue;
  202 + pixel[0] = r/denominator;
  203 + pixel[1] = g/denominator;
  204 + pixel[2] = b/denominator;
  205 + pixel[3] = a/denominator;
  206 + }
  207 + }
  208 + return CRSURFACE2RVAL(output_surface);
  209 + }
  210 + }
  211 + builder.c %{
  212 + void render_noise() {
  213 + cairo_surface_t *surface = RVAL2CRSURFACE(self);
  214 + unsigned char *data = cairo_image_surface_get_data(surface);
  215 + int height = cairo_image_surface_get_height(surface);
  216 + int stride = cairo_image_surface_get_stride(surface);
  217 + int length = height * stride;
  218 +
  219 + unsigned char * pixel;
  220 + unsigned char x;
  221 + for (pixel = data; pixel < data + length; pixel++) {
  222 + pixel[0] = (unsigned char) rand() % 255;
  223 + }
  224 + }
  225 + }
  226 + builder.c %{
  227 + unsigned int get_values(int x, int y) {
  228 + cairo_surface_t *surface = RVAL2CRSURFACE(self);
  229 + unsigned char *data = cairo_image_surface_get_data(surface);
  230 + int width = cairo_image_surface_get_width(surface);
  231 + int height = cairo_image_surface_get_height(surface);
  232 + if (x > width || y > height || x < 0 || y < 0) return Qnil;
  233 + unsigned int *pixel = (unsigned int *) (data + (y*width + x)*4);
  234 + return *pixel;
  235 + }
  236 + }
  237 + end
  238 +
  239 + def bump_map(height_map, light_x, light_y, light_radius, specular_radius, normal_coefficient=1.0)
  240 + render_bump_map(height_map, light_x.to_i, light_y.to_i, light_radius.to_i, specular_radius.to_i, normal_coefficient.to_f)
  241 + end
  242 +
5 243 def get_pixel(x, y)
6 244 integer = get_values(x, y)
7 245 a = integer >> 24 & 0xFF
14 lib/shape.rb
... ... @@ -0,0 +1,14 @@
  1 +class Shape
  2 + include CairoTools
  3 + attr_reader :name, :width, :height, :cr, :proc
  4 + def initialize(name, width, height, proc)
  5 + @name, @width, @height, @proc = name, width, height, proc
  6 + end
  7 +
  8 + def draw(cr, x, y)
  9 + @cr = cr
  10 + transform cr.matrix.translate(x, y) do
  11 + instance_eval(&proc)
  12 + end
  13 + end
  14 +end

0 comments on commit 4ceca53

Please sign in to comment.
Something went wrong with that request. Please try again.