Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge

  • Loading branch information...
commit 4ceca5340124d96f6e7bb8f3558f983d2f47d780 2 parents 25f2df6 + 114a2e9
Paul Nicholson paulnicholson authored
BIN  generators/.DS_Store
View
Binary file not shown
BIN  generators/beach.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  generators/church.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
454 generators/courtyard.rb
View
@@ -0,0 +1,454 @@
+require '../acrylic'
+class Courtyard < ImageGenerator
+ color :lighter, [0.29, 0.9, 0.9]
+ color :light, [0.29, 0.9, 0.8]
+ color :dark, [0.29, 0.9, 0.63]
+
+ color :orange, [0.1, 1, 0.6]
+ color :lighter_orange, [0.1, 1, 0.75]
+
+ image :map do
+ dimensions 400, 300
+ margin 4
+ curl = 6
+ cr.move_to 0, 0
+ cr.line_to width, 0
+ cr.line_to width + 1, height
+ curve = Curve.new(cr)
+ curve.point(width + 1, height, 150.deg, 0)
+ curve.point(width/2, height - curl, 180.deg, 50)
+ curve.point(-1, height, 210.deg, 0)
+ curve.draw_control_points(curve)
+ cr.line_to 0, 0
+ black! 0.4
+ cr.fill
+
+ @surface.blur 10
+
+ cr.rectangle(0, 0, width, height - curl)
+ white!
+ cr.fill
+
+ load_image 'map.png'
+ cr.rectangle(4, 4, width - 8, height - curl - 8)
+ # cr.rectangle(0, 0, width, height - curl)
+ cr.fill
+ end
+
+ shape :gate, 130, 90 do
+ def draw_bar(x, y)
+ cr.move_to x, y
+ cr.line_to x - 3, y + 5
+ cr.line_to x - 1, y + 7
+ cr.line_to x - 1, height
+ cr.line_to x + 1, height
+ cr.line_to x + 1, y + 7
+ cr.line_to x + 3, y + 5
+ cr.close_path
+ cr.fill
+ end
+
+ def draw_side
+ curve_height = 30
+ gate_top = 10
+ cr.line_width = 2
+
+ curve = Curve.new(cr)
+ curve.point(3, curve_height, 0.deg, 20)
+ curve.point(width/2 - 1, gate_top, 0.deg, 30)
+ curve.draw_control_points(curve)
+ cr.stroke
+
+ curve.each { |p| p.y += 30 }
+ curve.draw_control_points(curve)
+ cr.stroke
+
+ cr.move_to width/2 - 4, gate_top - 0.5
+ cr.line_to width/2 - 4, height
+ cr.line_width = 6
+ cr.stroke
+
+ cr.move_to width/2 - 1, height
+ cr.line_to 2, height
+ cr.line_width = 4
+ cr.stroke
+
+ draw_bar(3, 19)
+ draw_bar(11, 18)
+ draw_bar(19, 15)
+ draw_bar(27, 11)
+ draw_bar(35, 7)
+ draw_bar(43, 4)
+ draw_bar(52, 1.5)
+ draw_bar(61, 0)
+ end
+
+ draw_side
+ transform cr.matrix.translate(width, 0).scale(-1, 1) do
+ draw_side
+ end
+ end
+
+ image :header do
+ dimensions 900, 120
+ margin 4
+ linear_gradient 0, 0, 0, height + bottom_margin, light, dark
+ rounded_rectangle 0, 0, width, height * 2, 40
+ cr.fill_preserve
+ cr.clip
+
+ linear_gradient 0, height/3, 0, height + bottom_margin + 10, dark, light
+ # rounded_rectangle 0, height/2 - 10, width, height, 70
+ curve = Curve.new(cr)
+ curve.point -80, height + bottom_margin, 45.deg, 5
+ curve.point width/2, height/3, 0.deg, 500
+ curve.point width + 80, height + bottom_margin, -45.deg, 5
+ curve.draw_control_points(curve)
+ cr.close_path
+ cr.fill
+
+ # @surface.blur 2
+ # rounded_rectangle 0, 0, width, height * 2, 40
+ # clip!
+
+
+ white!
+ draw_gate 16, 8
+
+ draw_text_box 160, 16 do |tb|
+ tb.line("Courtyard", :face => "Georgia", :size => 80)
+ end
+
+ shadow 5, 0.5
+ end
+
+ image :organizations_bar do
+ dimensions 900, 40
+ margin 0, 4
+ cr.rectangle 0, 0, width, height
+ linear_gradient 0, 0, 0, height, orange, lighter_orange
+ cr.fill
+
+ cr.rectangle 0, 0, width, 3
+ linear_gradient 0, 0, 0, 3, black.a(0.15), black.a(0.1), black.a(0)
+ cr.fill
+
+ cr.rectangle 0, height-1, width, 1
+ white! 0.4
+ # linear_gradient 0, height-1, 0, height, white.a(0), white.a(0.3), white.a(0.5)
+ cr.fill
+
+ shadow 5, 0.5
+ end
+
+ image :page do
+ dimensions 920, 200
+ margin 10
+ draw_image :header, 0, 0
+ draw_image :organizations_bar, 0, 120
+ end
+
+ color :frame_light, [0, 0, 0.3]
+ color :frame_dark, [0, 0, 0.2]
+ image :frame do
+ dimensions 400, 300
+ margin 8
+
+ border = 40
+
+ # bottom
+ draw_frame_side 0, height - border, 0, height, frame_light, frame_dark do
+ cr.move_to 0, height
+ cr.line_to width, height
+ cr.line_to width - border, height - border
+ cr.line_to border, height - border
+ cr.close_path
+ end
+
+ # left
+ draw_frame_side 0, 0, border, 0, frame_dark, frame_light do
+ cr.move_to 0, 0
+ cr.line_to 0, height
+ cr.line_to border, height - border
+ cr.line_to border, border
+ cr.close_path
+ end
+
+ # right
+ draw_frame_side width - border, 0, width, 0, frame_light, frame_dark do
+ cr.move_to width, 0
+ cr.line_to width, height
+ cr.line_to width - border, height - border
+ cr.line_to width - border, border
+ cr.close_path
+ end
+
+ # top
+ draw_frame_side 0, 0, 0, border, frame_light, frame_dark do
+ cr.move_to 0, 0
+ cr.line_to width, 0
+ cr.line_to width - border + 1, border
+ cr.line_to border, border
+ cr.close_path
+ end
+
+ 2.times {shadow 10, 0.7}
+
+ frame = layer!
+ load_image_and_scale 'church.jpg', width - border*2, height - border*2
+ cr.source.matrix = Cairo::Matrix.identity.translate(-border, -border)
+ cr.rectangle(border, border, width - border*2, height - border*2)
+ cr.fill
+ cr.paint
+
+ linear_gradient 0, 0, 0, 180, white.a(0.6), white.a(0)
+ cr.move_to 0, 0
+ cr.line_to 0, 120
+ cr.line_to width, 160
+ cr.line_to width, 0
+ cr.close_path
+ cr.fill
+
+ margin 0
+ cr.set_source(Cairo::SurfacePattern.new(frame))
+ cr.paint
+ end
+
+ def draw_frame_side(*gradient_args, &block)
+ original = layer!
+ original_margins = [@top_margin, @right_margin, @bottom_margin, @left_margin]
+ yield
+ path = cr.copy_path
+ black!
+ cr.fill
+ mask = layer!
+ cr.append_path path
+ black!
+ cr.fill
+ @surface.blur 10
+ height_map = layer!
+ @surface.bump_map(height_map, width.to_i/2 + @left_margin, -80, 800, 10, 5)
+ bump = layer!
+ margin 0
+ cr.set_source(Cairo::SurfacePattern.new(original))
+ cr.paint
+
+ margin *original_margins
+ cr.append_path path
+ linear_gradient *gradient_args
+ cr.fill
+ margin 0
+ cr.set_source(Cairo::SurfacePattern.new(bump))
+ cr.mask(Cairo::SurfacePattern.new(mask))
+ margin *original_margins
+ end
+
+ def draw_cork_board_side(side, *gradient_args, &block)
+ original = layer!
+ yield
+ path = cr.copy_path
+ black!
+ cr.fill
+ mask = layer!
+ cr.append_path path
+ black!
+ cr.fill
+ @surface.blur 4
+ height_map = layer!
+ @surface.bump_map(height_map, width.to_i/2 + @left_margin, -320, 3200, 1, 3)
+ bump = layer!
+
+ cr.append_path path
+ grain! 0.4
+ fill_with_noise
+ if [:top, :bottom].include?(side)
+ @surface.horizontal_blur 10
+ @surface.horizontal_blur 10
+ @surface.horizontal_blur 10
+ else
+ @surface.vertical_blur 10
+ @surface.vertical_blur 10
+ @surface.vertical_blur 10
+ end
+ grain = layer!
+
+ paint_layer original
+
+ cr.append_path path
+ linear_gradient *gradient_args
+ cr.fill
+
+ transform Cairo::Matrix.identity do
+ cr.set_source(Cairo::SurfacePattern.new(grain))
+ cr.mask(Cairo::SurfacePattern.new(mask))
+ cr.set_source(Cairo::SurfacePattern.new(bump))
+ cr.mask(Cairo::SurfacePattern.new(mask))
+ end
+ end
+
+ def load_image_and_scale(path, width, height)
+ image = Gdk::Pixbuf.new(File.join(File.dirname($0), path))
+ tmp_surface = Cairo::ImageSurface.new(image.width, image.height)
+ tmp_cr = Cairo::Context.new(tmp_surface)
+ tmp_cr.set_source_pixbuf(image)
+ tmp_cr.paint
+ smaller = tmp_surface.downsample((image.width/width).ceil)
+ cr.set_source(Cairo::SurfacePattern.new(smaller))
+ end
+
+ def layer!
+ surface = @surface
+ dimensions @canvas_width, @canvas_height
+ margin @top_margin, @right_margin, @bottom_margin, @left_margin
+ surface
+ end
+
+ color :cork_board_light, [0.11, 0.5, 0.8]
+ color :cork_board_dark, [0.11, 0.5, 0.7]
+ color :cork, [0.08, 0.5, 0.4]
+ color :grain, [0.08, 0.5, 0.2]
+ image :cork_board do
+ dimensions 400, 300
+ margin 8
+ border = 20
+
+ draw_cork_board_side :bottom, 0, height - border, 0, height, cork_board_light, cork_board_dark do
+ cr.move_to 0, height
+ cr.line_to width, height
+ cr.line_to width - border, height - border
+ cr.line_to border, height - border
+ cr.close_path
+ end
+
+ draw_cork_board_side :left, 0, 0, border, 0, cork_board_dark, cork_board_light do
+ cr.move_to 0, 0
+ cr.line_to 0, height
+ cr.line_to border, height - border
+ cr.line_to border, border
+ cr.close_path
+ end
+
+ draw_cork_board_side :right, width - border, 0, width, 0, cork_board_light, cork_board_dark do
+ cr.move_to width, 0
+ cr.line_to width, height
+ cr.line_to width - border, height - border
+ cr.line_to width - border, border
+ cr.close_path
+ end
+
+ draw_cork_board_side :top, 0, 0, 0, border, cork_board_light, cork_board_dark do
+ cr.move_to 0, 0
+ cr.line_to width, 0
+ cr.line_to width - border + 1, border
+ cr.line_to border, border
+ cr.close_path
+ end
+
+ 2.times {shadow 10, 0.7}
+
+ frame = layer!
+
+ cork!
+ cr.rectangle border, border, width - border*2, height - border*2
+ cr.fill_preserve
+ black!(0.2)
+ fill_with_noise
+
+ paint_layer frame
+
+ draw_photo 'beach.jpg', 120, 160, 0.deg, :right
+ draw_photo 'party.jpg', 205, 195, 5.deg, :left
+ draw_photo 'game.jpg', 250, 70, -4.deg, :right
+ draw_photo 'restaurant.jpg', -10, 160, 8.deg, :right
+ draw_photo 'picnic.jpg', 20, 10, -8.deg, :left
+ draw_photo 'park.jpg', 100, 90, 10.deg, :left
+ draw_photo 'outside_church.jpg', 210, 10, -2.deg, :left
+ end
+
+ def draw_photo(path, x, y, theta, curl_side = :right)
+ background = layer!
+ load_image_and_scale(path, 130, 130)
+ cr.source.matrix = Cairo::Matrix.identity.translate(-x, -y)
+ w, h = cr.source.surface.width, cr.source.surface.height
+ transform cr.matrix.rotate(-theta) do
+ curl = 6
+ cr.move_to x, y
+ cr.line_to x + w, y
+ if curl_side == :right
+ cr.line_to x + w + 2, y + h + curl
+ cr.line_to x - 2, y + h + 2
+ else
+ cr.line_to x + w + 2, y + h + 2
+ cr.line_to x - 2, y + h + curl
+ end
+ cr.close_path
+ picture = cr.source
+ black! 0.6
+ cr.fill
+ @surface.blur 10
+
+ cr.move_to x, y
+ cr.line_to x + w, y
+ cr.line_to x + w, y + h
+ cr.line_to x, y + h
+ cr.close_path
+
+ cr.set_source(picture)
+ cr.fill_preserve
+
+ white!
+ cr.stroke
+ end
+ photo = layer!
+
+ transform cr.matrix.rotate(-theta) do
+ black!
+ cr.circle x + w/2 + 3, y + 13, 5
+ cr.fill
+ @surface.blur 10
+
+
+ white! 0.1
+ cr.circle x + w/2 + 0.5, y + 10.5, 5
+ cr.fill
+
+ linear_gradient 0, y, 0, y + 15, hsl(0, 0, 0.2), hsl(0, 0, 0.0)
+ cr.circle x + w/2, y + 10, 5
+ cr.fill
+
+ white! 0.1
+ cr.circle x + w/2 - 2.5, y + 8.5, 4
+ cr.fill
+
+ linear_gradient 0, y, 0, y + 15, hsl(0, 0, 0.2), hsl(0, 0, 0.0)
+ cr.circle x + w/2 - 3, y + 8, 4
+ cr.fill
+ end
+ thumbtack = layer!
+
+ paint_layer background
+ paint_layer photo
+ paint_layer thumbtack
+ end
+
+ def paint_layer(layer)
+ transform Cairo::Matrix.identity do
+ cr.set_source(Cairo::SurfacePattern.new(layer))
+ cr.paint
+ end
+ end
+
+ def fill_with_noise
+ cr.clip
+ noise = Cairo::ImageSurface.new(Cairo::FORMAT_A8, @canvas_width, @canvas_height)
+ noise.render_noise
+ cr.mask(Cairo::SurfacePattern.new(noise))
+ cr.reset_clip
+ end
+end
+# Courtyard.preview(:page)
+# Courtyard.preview(:organizations_bar)
+# Courtyard.preview(:header)
+# Courtyard.preview(:map)
+# Courtyard.preview(:frame)
+Courtyard.preview(:cork_board)
BIN  generators/game.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  generators/map.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  generators/outside_church.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  generators/park.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  generators/party.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  generators/picnic.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  generators/restaurant.jpg
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
109 lib/cairo_tools.rb
View
@@ -8,20 +8,9 @@
module CairoTools
include Color
- attr_reader :surface, :cr, :height, :width
+ attr_reader :surface, :cr, :canvas_height, :canvas_width, :top_margin, :right_margin, :bottom_margin, :left_margin
attr_accessor :preview
- def self.color(name, color)
- color = Color::HSL.new(color)
- define_method(name) {color}
- define_method(name.bang) {set_color(color)}
- @colors ||= {}
- @colors[name] = color
- end
-
- color :black, '000'
- color :white, 'FFF'
-
def generate_image(path, options)
# dummy context is useful sometimes
@surface = Cairo::ImageSurface.new(1, 1)
@@ -31,19 +20,35 @@ def generate_image(path, options)
end
def dimensions(width, height)
- @width, @height = width, height
+ @canvas_width, @canvas_height = width, height
@surface = Cairo::ImageSurface.new(width, height)
@cr = Cairo::Context.new(surface)
end
-
- def outline(width=nil)
- cr.line_width = width if width
+
+ def margin(*rect)
+ rect = rect + rect if rect.length == 1
+ rect = rect + rect if rect.length == 2
+ @top_margin, @right_margin, @bottom_margin, @left_margin = rect
+ cr.matrix = Cairo::Matrix.identity.translate(left_margin, top_margin)
+ end
+
+ def width
+ canvas_width - right_margin - left_margin
+ end
+
+ def height
+ canvas_height - top_margin - bottom_margin
+ end
+
+ def transform(matrix, &block)
+ old_matrix = cr.matrix
+ cr.matrix = matrix
yield
- cr.stroke
+ cr.matrix = old_matrix
end
# http://www.cairographics.org/cookbook/roundedrectangles/
- def rounded_rectangle(x, y, w, h, radius_x=5, radius_y=5)
+ def rounded_rectangle(x, y, w, h, radius_x=5, radius_y=radius_x)
arc_to_bezier = 0.55228475
radius_x = w / 2 if radius_x > w - radius_x
radius_y = h / 2 if radius_y > h - radius_y
@@ -108,12 +113,12 @@ def gradient(gradient, *colors)
cr.set_source(gradient)
end
- def shadow
- shadow_surface = Cairo::ImageSurface.new(width, height)
+ def shadow(radius=3, alpha=1)
+ shadow_surface = Cairo::ImageSurface.new(@canvas_width, @canvas_height)
shadow_cr = Cairo::Context.new(shadow_surface)
- shadow_cr.set_source_rgba(0, 0, 0, 1)
+ shadow_cr.set_source_rgba(0, 0, 0, alpha)
shadow_cr.mask(Cairo::SurfacePattern.new(surface))
- shadow_surface.blur
+ shadow_surface.blur(radius)
shadow_cr.set_source(Cairo::SurfacePattern.new(surface))
shadow_cr.paint
@surface = shadow_surface
@@ -125,12 +130,70 @@ def get_pixel(x, y)
end
def load_image(path, x=0, y=0)
- image = Gdk::Pixbuf.new(File.join(File.dirname(__FILE__), path))
+ image = Gdk::Pixbuf.new(File.join(File.dirname($0), path))
cr.set_source_pixbuf(image)
cr.source.matrix = Cairo::Matrix.identity.translate(x, y)
end
+ def clip!
+ i = self.class.new
+ w, h = @canvas_width, @canvas_height
+ pattern = Cairo::SurfacePattern.new(@surface)
+ clip = cr.copy_path
+ i.instance_eval do
+ dimensions w, h
+ cr.append_path clip
+ cr.clip
+ cr.set_source(pattern)
+ cr.paint
+ end
+ dimensions w, h
+ cr.set_source(Cairo::SurfacePattern.new(i.surface))
+ cr.paint
+ end
+
+ def transparent!(alpha)
+ i = self.class.new
+ w, h = @canvas_width, @canvas_height
+ pattern = Cairo::SurfacePattern.new(@surface)
+ i.instance_eval do
+ dimensions w, h
+ cr.set_source(pattern)
+ cr.paint_with_alpha(alpha)
+ end
+ @surface = i.surface
+ @cr = i.cr
+ end
+
+ def draw_image(image, x=0, y=0, a=1)
+ i = self.class.new
+ i.instance_eval do
+ draw(image)
+ end
+ cr.set_source(Cairo::SurfacePattern.new(i.surface))
+ cr.source.matrix = Cairo::Matrix.identity.translate(-x, -y)
+ cr.paint_with_alpha(a)
+ end
+
def clouds
Cairo::ImageSurface.new(129, 129)
end
+end
+
+class Cairo::Context
+ inline(:C) do |builder|
+ builder.include '<stdlib.h>'
+ builder.include '<cairo.h>'
+ builder.include '<rb_cairo.h>'
+ builder.include '<intern.h>'
+ builder.add_compile_flags '`/opt/local/bin/pkg-config --cflags cairo`'
+ builder.add_compile_flags '-I/opt/local/lib/ruby/site_ruby/1.8/i686-darwin9/'
+ builder.add_compile_flags '-I/opt/local/lib/ruby/gems/1.8/gems/cairo-1.6.2/src'
+ builder.c %{
+ void paint_with_alpha(double alpha) {
+ cairo_t *cr = RVAL2CRCONTEXT(self);
+ cairo_paint_with_alpha(cr, alpha);
+ }
+ }
+ end
end
40 lib/image_generator.rb
View
@@ -1,7 +1,39 @@
require 'cairo_tools'
+require 'shape'
class ImageGenerator
include CairoTools
+ def self.colors
+ @@colors ||= {}
+ end
+
+ def self.color(name, color)
+ color = Color::HSL.new(color)
+ colors[name] = color
+ self.class_eval <<-"end;"
+ def #{name}
+ self.class.colors[:#{name}]
+ end
+ def #{name}!(a=nil)
+ set_color(a ? #{name}.a(a) : #{name})
+ end
+ end;
+ end
+
+ color :black, '000'
+ color :white, 'FFF'
+
+ def self.shapes
+ @@shapes ||= {}
+ end
+
+ def self.shape(name, width, height, &block)
+ shapes[name] = shape = Shape.new(name, width, height, block)
+ define_method("draw_#{name}") do |x, y|
+ shape.draw(cr, x, y)
+ end
+ end
+
def self.generate_image(path, *options)
new.generate_image(path, options)
end
@@ -24,11 +56,11 @@ def self.preview(*options)
def self.image(name, options={:suite => true}, &block)
images[name] = block
- suite << name if options[:suite]
+ suite_images << name if options[:suite]
end
- def self.suite
- @suite ||= []
+ def self.suite_images
+ @suite_images ||= []
end
def self.images
@@ -36,7 +68,7 @@ def self.images
end
def self.suite(prefix, *args)
- suite.each do |name|
+ suite_images.each do |name|
generate("#{prefix}_#{name}.png", name, *args)
end
end
240 lib/image_surface_extensions.rb
View
@@ -1,7 +1,245 @@
-require 'native_image_surface_extensions'
+# require 'native_image_surface_extensions'
require 'color'
class Cairo::ImageSurface
+ inline(:C) do |builder|
+ builder.include '<stdlib.h>'
+ builder.include '<math.h>'
+ builder.include '<cairo.h>'
+ builder.include '<rb_cairo.h>'
+ builder.include '<intern.h>'
+ builder.add_compile_flags '`pkg-config --cflags cairo`'
+ builder.add_compile_flags '-I/opt/local/lib/ruby/site_ruby/1.8/i686-darwin9/'
+ builder.add_compile_flags '-I/opt/local/lib/ruby/gems/1.8/gems/cairo-1.6.2/src'
+ builder.c %{
+ void vertical_blur(int radius) {
+ cairo_surface_t *surface = RVAL2CRSURFACE(self);
+ unsigned char *data = cairo_image_surface_get_data(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ int stride = cairo_image_surface_get_stride(surface);
+ int length = height*stride;
+
+ cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ unsigned char *tmp_data = cairo_image_surface_get_data(tmp_surface);
+
+ unsigned char *color;
+ unsigned char *color2;
+ double sumr, sumg, sumb, suma;
+ int gauss_w = radius*2 + 1;
+ int *mask = triangle[radius];
+ int gauss_sum = sums[radius];
+ int i, j, k, x, y;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ color = data + i*stride + j*4;
+ if (color < data || color > data + length) continue;
+ color2 = tmp_data + i*stride + j*4;
+ color2[0] = color[0];
+ color2[1] = color[1];
+ color2[2] = color[2];
+ color2[3] = color[3];
+ }
+ }
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ sumr = sumg = sumb = suma = 0;
+ for (k = 0; k < gauss_w; k++) {
+ y = i-radius+k;
+ if (y > height || y < 0) continue;
+ color = data + y*stride + j*4;
+ if (color < data || color > data + length) continue;
+ suma += color[0]*mask[k];
+ sumr += color[1]*mask[k];
+ sumg += color[2]*mask[k];
+ sumb += color[3]*mask[k];
+ }
+ color = data + i*stride + j*4;
+ color[0] = suma/gauss_sum;
+ color[1] = sumr/gauss_sum;
+ color[2] = sumg/gauss_sum;
+ color[3] = sumb/gauss_sum;
+ }
+ }
+ }
+ }
+ builder.c %{
+ void horizontal_blur(int radius) {
+ cairo_surface_t *surface = RVAL2CRSURFACE(self);
+ unsigned char *data = cairo_image_surface_get_data(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ int stride = cairo_image_surface_get_stride(surface);
+ int length = height*stride;
+
+ cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ unsigned char *tmp_data = cairo_image_surface_get_data(tmp_surface);
+
+ unsigned char *color;
+ unsigned char *color2;
+ double sumr, sumg, sumb, suma;
+ int gauss_w = radius*2 + 1;
+ int *mask = triangle[radius];
+ int gauss_sum = sums[radius];
+ int i, j, k, x, y;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ color = data + i*stride + j*4;
+ if (color < data || color > data + length) continue;
+ color2 = tmp_data + i*stride + j*4;
+ color2[0] = color[0];
+ color2[1] = color[1];
+ color2[2] = color[2];
+ color2[3] = color[3];
+ }
+ }
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ sumr = sumg = sumb = suma = 0;
+ for (k = 0; k < gauss_w; k++) {
+ int x = j-radius+k;
+ if (x > width || x < 0) continue;
+ color = tmp_data + i*stride + x*4;
+ if (color < tmp_data || color > tmp_data + length) continue;
+ suma += color[0]*mask[k];
+ sumr += color[1]*mask[k];
+ sumg += color[2]*mask[k];
+ sumb += color[3]*mask[k];
+ }
+ color = data + i*stride + j*4;
+ color[0] = suma/gauss_sum;
+ color[1] = sumr/gauss_sum;
+ color[2] = sumg/gauss_sum;
+ color[3] = sumb/gauss_sum;
+ }
+ }
+ }
+ }
+ builder.prefix %{
+ int abs(int x) {
+ return x < 0 ? -x : x;
+ }
+ }
+ builder.c %{
+ void render_bump_map(VALUE height_map, int light_x, int light_y, int light_radius, int specular_radius, double normal_coefficient) {
+ cairo_surface_t *surface = RVAL2CRSURFACE(self);
+ unsigned int *data = (unsigned int *) cairo_image_surface_get_data(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ int stride = cairo_image_surface_get_stride(surface);
+ int length = height * stride;
+
+ cairo_surface_t *height_surface = RVAL2CRSURFACE(height_map);
+ unsigned char *height_data = cairo_image_surface_get_data(height_surface);
+
+ int x, y;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int xnext = y * stride + (x + 1) * 4 - 1;
+ int xprev = y * stride + (x - 1) * 4 - 1;
+ int xn = (xnext > length || xprev < 0) ? 0 : (height_data[xnext] - height_data[xprev]);
+ int ynext = (y + 1) * stride + x * 4 - 1;
+ int yprev = (y - 1) * stride + x * 4 - 1;
+ int yn = (ynext > length || yprev < 0) ? 0 : (height_data[ynext] - height_data[yprev]);
+ int ex = abs(xn*normal_coefficient - x + light_x);
+ int ey = abs(yn*normal_coefficient - y + light_y);
+
+ if (ex > light_radius - 1) ex = light_radius - 1;
+ if (ey > light_radius - 1) ey = light_radius - 1;
+
+ unsigned int color;
+ int magnitude = (int) sqrtf((float)ex*ex+ey*ey);
+ if (magnitude < specular_radius) {
+ int alpha = 255 - magnitude*255/specular_radius;
+ if (alpha > 255) alpha = 255;
+ if (alpha < 0) alpha = 0;
+ color = (alpha << 24) + (alpha << 16) + (alpha << 8) + alpha;
+ //printf("specular %x\\n", color);
+ } else {
+ int alpha = (magnitude - specular_radius)*255/(light_radius - specular_radius);
+ if (alpha > 255) alpha = 255;
+ if (alpha < 0) alpha = 0;
+ color = 0xFF000000 & (alpha << 24);
+ //printf("diffuse %i\\n", xn);
+ }
+ data[y * width + x] = color;
+ }
+ }
+ }
+ }
+ builder.c %{
+ VALUE downsample(int scale) {
+ cairo_surface_t *surface = RVAL2CRSURFACE(self);
+ unsigned int *data = (unsigned int *) cairo_image_surface_get_data(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+
+ int w = width / scale;
+ int h = height / scale;
+ cairo_surface_t *output_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
+ unsigned int *output_data = (unsigned int *) cairo_image_surface_get_data(output_surface);
+ int denominator = scale * scale;
+
+ unsigned char * pixel;
+ int i, j, k, l;
+ int r, g, b, a;
+
+ for (i=0; i<w+1; i++) {
+ for (j=0; j<h+1; j++) {
+ r = g = b = a = 0;
+ for (k=0; k<scale; k++) {
+ for (l=0; l<scale; l++) {
+ pixel = (unsigned char *) (data + (j*scale + l)*width + i*scale + k);
+ if (pixel < (unsigned char *) data || pixel > (unsigned char *) (data + width * height)) continue;
+ r += pixel[0];
+ g += pixel[1];
+ b += pixel[2];
+ a += pixel[3];
+ }
+ }
+ pixel = (unsigned char *) (output_data + j*w + i);
+ if (pixel < (unsigned char *) output_data || pixel > (unsigned char *) (output_data + h*w)) continue;
+ pixel[0] = r/denominator;
+ pixel[1] = g/denominator;
+ pixel[2] = b/denominator;
+ pixel[3] = a/denominator;
+ }
+ }
+ return CRSURFACE2RVAL(output_surface);
+ }
+ }
+ builder.c %{
+ void render_noise() {
+ cairo_surface_t *surface = RVAL2CRSURFACE(self);
+ unsigned char *data = cairo_image_surface_get_data(surface);
+ int height = cairo_image_surface_get_height(surface);
+ int stride = cairo_image_surface_get_stride(surface);
+ int length = height * stride;
+
+ unsigned char * pixel;
+ unsigned char x;
+ for (pixel = data; pixel < data + length; pixel++) {
+ pixel[0] = (unsigned char) rand() % 255;
+ }
+ }
+ }
+ builder.c %{
+ unsigned int get_values(int x, int y) {
+ cairo_surface_t *surface = RVAL2CRSURFACE(self);
+ unsigned char *data = cairo_image_surface_get_data(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ if (x > width || y > height || x < 0 || y < 0) return Qnil;
+ unsigned int *pixel = (unsigned int *) (data + (y*width + x)*4);
+ return *pixel;
+ }
+ }
+ end
+
+ def bump_map(height_map, light_x, light_y, light_radius, specular_radius, normal_coefficient=1.0)
+ 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)
+ end
+
def get_pixel(x, y)
integer = get_values(x, y)
a = integer >> 24 & 0xFF
14 lib/shape.rb
View
@@ -0,0 +1,14 @@
+class Shape
+ include CairoTools
+ attr_reader :name, :width, :height, :cr, :proc
+ def initialize(name, width, height, proc)
+ @name, @width, @height, @proc = name, width, height, proc
+ end
+
+ def draw(cr, x, y)
+ @cr = cr
+ transform cr.matrix.translate(x, y) do
+ instance_eval(&proc)
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.