<   2011年 05月 ( 32 )   > この月の画像一覧

読み込んだ画像のアルファチャンネルを何とかできないものかなと、
からかってみた。
SDL::Surface#set_alpha(SDL::SRCALPHA,alpha)
を使うしか方法がないのか。
そうすると、SDL::Surfaceから Cairo::ImageSurfaceに持って行き方がわからない。
Cairoで1枚の画像を作って全面表示するのではなく、
SDL::Screen#putを使ってCairoで作った画像を部品にして、配置するしかないのか?
また、振り出しに戻ちゃった。
convert のコマンドでアルファチャンネルを変える方法をを調べたけど、わからなかった。
その時convertを使ってみたついでに、背景ぼかしをやってみた。

<後日>
Cairo::Context#paint(alpha)でアルファチャンネルを指定できた。
しょうもない迷子でした。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(cr)
cr.set_source_color(:white)
cr.rectangle(0, 0, @w, @h)
cr.fill
end
end

class Text
def initialize(w, h)
@text = "Cairo"
@x, @y = w / 2, h / 2
@font_size = 100
@image = Cairo::ImageSurface.new(w, h)
cr = Cairo::Context.new(@image)
cr.set_source_color(:red)
cr.font_size = @font_size
@ext = cr.text_extents(@text)
x = -@ext.x_bearing
y = -@ext.y_bearing
cr.move_to(x, y)
cr.show_text(@text)
end

def update(cr)
cr.matrix = Cairo::Matrix.translate(@x, @y)
cr.set_source(@image, -@ext.width / 2, -@ext.height / 2)
cr.paint
end
end

class Blur < Text
def initialize(w, h)
super
@image = Cairo::ImageSurface.new(w, h)
cr = Cairo::Context.new(@image)
cr.set_source_color(:white)
cr.rectangle(0, 0, w, h)
cr.fill
cr.set_source_color(:black)
cr.font_size = @font_size
@ext = cr.text_extents(@text)
x = -@ext.x_bearing
y = -@ext.y_bearing
cr.move_to(x, y)
cr.show_text(@text)
@x += 5
@y += 5
IO.popen("convert -blur 3x3 -transparent white - -","r+") do |io|
@image.write_to_png(io)
io.close_write
@image = Cairo::ImageSurface.from_png(io)
end
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@items = []
@items << BackGround.new(@w, @h)
@items << Blur.new(@w, @h)
@items << Text.new(@w, @h)
end

def update
cr = Cairo::Context.new(@image)
@items.each do |obj|
obj.update(cr)
end
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(300, 200, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-22 11:36
Cairo::Context#set_source_rgba(red, green, blue, alpha=1.0)
で、アルファを設定できるが、
color = Cairo::Color.parse(:teal) または、color = Cairo::Color.parse(Cairo::Color::TEAL)
color.alpha = 0.5
c.set_source_color(color)
でも、できる。
[PR]
by gaziya | 2011-05-21 16:34
コンテキストが持っているpathの上にテキストを配置することがで きるみたい。
cairoは、色々な事ができる。
説明しづらいので、挙動とプログラムをみてください。
Context#move_toは数字が大きいほど描写時間が、かかる感じ。

<後日記>
ruby1.87では動くが、ruby1.91では、動かない。
どうも、Cairo::Context#map_path_ontoが引っかかるみたい。
こうなると、お手上げです。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(:snow)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Moji
def initialize(w, h)
@x, @y = w / 2, h / 2
@text = 'Cairo'
@d = 300
end

def update(c)
@d -= 2
@d = 300 if @d < -100
c.matrix = Cairo::Matrix.translate(@x, @y)
c.circle(0, 0, 50)
c.set_source_color(:teal)
c.stroke_preserve
path = c.copy_path_flat
c.new_path
c.move_to(@d, -3)
c.font_size = 25
c.text_path(@text)
c.map_path_onto(path)
c.set_source_color(:red)
c.fill
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@moji = Moji.new(@w, @h)
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@moji.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(10)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(250, 250, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-21 15:41
よくよく考えたら、
バウンドに関しては行列なんて、いらなかった。
ちょっと、テクニックに走りすぎたぜ。反省。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(:black)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Ball
def initialize(w, h)
@x, @y = w / 2, h / 2
@r = 10
@erx = @r .. w - @r
@ery = @r .. h - @r
@vx, @vy = rand(5) + 2, rand(5) + 2
@vx *= -1 if rand(9) < 5
@vy *= -1 if rand(9) < 5
end

def update(c)
@vx *= -1 if !@erx.include?(@x + @vx)
@vy *= -1 if !@ery.include?(@y + @vy)
@x += @vx
@y += @vy
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(:orange)
c.circle(0, 0, @r)
c.fill
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@ball = Ball.new(@w, @h)
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@ball.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(350, 250, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-20 22:49
反転(鏡映)の行列は
y軸での反転 Cairo::Matrix.scale(-1, 1)
x軸での反転 Cairo::Matrix.scale(1, -1)
で、できる。
ネットをみていたら、見つけた。いける!!
思いつきもしなかった。
さっそく、試した。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::BLACK)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Ball
def initialize(w, h)
@x, @y = w / 2, h / 2
@r = 10
@color = Cairo::Color::ORANGE
@erx = @r .. w - @r
@ery = @r .. h - @r
@vx, @vy = rand(5) + 2, rand(5) + 2
@vx *= -1 if rand(9) < 5
@vy *= -1 if rand(9) < 5
end

def update(c)
@vx, @vy = Cairo::Matrix.scale(-1, 1).transform_point(@vx, @vy) if !@erx.include?(@x + @vx)
@vx, @vy = Cairo::Matrix.scale(1, -1).transform_point(@vx, @vy) if !@ery.include?(@y + @vy)
@x += @vx
@y += @vy
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(@color)
c.circle(0, 0, @r)
c.fill
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@ball = Ball.new(@w, @h)
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@ball.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(350, 250, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-20 17:21
今回は
http://www.youtube.com/watch?v=83P8xRIG3eI
のイメージです。
これを作りたかったから、
無理やりなので位置関係が判りづらいです。
<追記>
http://blog.livedoor.jp/gaziya/archives/52157035.html
に書き直しました。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::BLACK)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Man
def initialize(x, y , deg, rgb)
@gx, @gy = x, y
@r,@g,@b = rgb
@deg = deg
@w, @h = 50, 120
@x, @y = -@w / 2, -@h
end

def update(c)
@deg += 3
@deg = 0 if @deg > 359
rd = @deg * Math::PI / 180
c.matrix = Cairo::Matrix.new(1,0,0.25 * Math::cos(rd),0.75+ 0.25 * Math::sin(rd), 0, 0) * Cairo::Matrix.translate(@gx, @gy)
c.set_source_rgb(@r,@g,@b)
c.rectangle(@x, @y, @w, @h)
c.circle(0, -@h - 25, 25)
c.fill
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@men = []
(0 .. 179).step(30) do |deg|
r,g,b = rand / 2 + 0.5, rand / 2 + 0.5, rand / 2 + 0.5
@men << Man.new(@w / 2, @h - 12, deg, [r,g,b])
end
@deg = 0
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@men.each do |obj|
obj.update(context)
end
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(250, 250, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-19 21:08
関数の曲線を描く練習でサイン曲線を描いた。
後、サイン曲線に添って円をレイアウトした。
ついでだから、横に動かしてみた。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::X11::WHITE)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class SinCurve
def initialize(w, h)
@w, @h = w, h
@x, @y = @w / 2, @h / 3
@vx, @vy = 5, 35
@hz = 4
@vectors = []
pitch = 10
i = -180 * @hz / pitch
(-@hz * Math::PI .. @hz * Math::PI).step(pitch * Math::PI / 180) do |r|
@vectors << [i * @vx, Math::sin(r) * @vy]
i += 1
end
end

def update(c)
@x += 1
@x = @w / 2 if @x == @w / 2 + @vx * 36
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(Cairo::Color::X11::BLACK)
c.set_line_width(8)
c.set_dash([25, 10, 10, 10], 5)
@vectors.inject(true) do |b, v|
x, y = v
if b
c.move_to(x, y)
else
c.line_to(x, y)
end
b = false
end
c.stroke
end
end

class Barrage < SinCurve
def initialize(w, h)
super
@y = h / 3 * 2
end

def update(c)
@x -= 1
@x = @w / 2 if @x == @w / 2 - @vx * 36
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(Cairo::Color::X11::ORANGE)
@vectors.inject(0) do |i, v|
if i % 3 == 0
x, y = v
c.circle(x, y, 5)
c.fill
end
i += 1
end
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@wave = SinCurve.new(@w, @h)
@barrage = Barrage.new(@w, @h)
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@wave.update(context)
@barrage.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(300, 300, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-18 20:14
今回は静的にRangeが使える。
ただ、拡大のマトリックスを使うと、描写が荒くなる。
前回のは、拡大してもきれい。
拡大は、context#font_sizeでも、できるけど縦横比が同じだ。
適材適所に使うしかない。
文字だから、右上を基準にしたい時もあるけど、
ちょっと、治せば良さそうだ。
Stringクラスのcenter、ljust、rjustメソッドなんかも、良さげだ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::WHITE)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Moji
def initialize(w, h)
@x, @y = w / 2, h / 2
@text = 'Cairo on Ruby/SDL'
@image = Cairo::ImageSurface.new(w, h)
c = Cairo::Context.new(@image)
c.set_source_color(Cairo::Color::RED)
c.font_size = 50
e = c.text_extents(@text)
x = -e.x_bearing
y = -e.y_bearing
c.move_to(x, y)
c.show_text(@text)
cx, cy = e.width / 2, e.height / 2
@range_x = -cx .. cx
@range_y = -cy .. cy
end

def update(c)
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source(@image, @range_x.first, @range_y.first)
c.paint
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@moji = Moji.new(@w, @h)
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@moji.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(500, 350, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-17 22:53
文字の中心座標を持つクラスをつくった。
でも、Rangeが使えない。
もう、ひと工夫必要だ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::WHITE)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Moji1
def initialize(w, h)
@x, @y = w / 2, h / 3
@text = 'Cairo on Ruby/SDL'
end

def update(c)
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(Cairo::Color::RED)
c.font_size = 50
extents = c.text_extents(@text)
x = extents.width / 2 + extents.x_bearing
y = extents.height / 2 + extents.y_bearing
c.move_to(-x, -y)
c.show_text(@text)
end
end

class Moji2
def initialize(w, h)
@x, @y = w / 2, h / 3 * 2
@text = 'Cairo on Ruby/SDL'
end

def update(c)
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(Cairo::Color::ORANGE)
c.font_size = 75
extents = c.text_extents(@text)
x = extents.width / 2 + extents.x_bearing
y = extents.height / 2 + extents.y_bearing
c.move_to(-x, -y)
c.text_path(@text)
c.fill_preserve
c.set_source_color(Cairo::Color::TEAL)
c.stroke
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@moji1 = Moji1.new(@w, @h)
@moji2 = Moji2.new(@w, @h)
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@moji1.update(context)
@moji2.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(500, 350, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-17 22:19
ボタンのクラスに中心の座標と実体をRangeクラスを使って置いた。
context#rectangleを使うパターンと
線を描いていくパターンをつくってみた。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class EventHandle
def initialize(handle)
@handle = handle
@type = {
SDL::Event::KeyDown => :sym,
SDL::Event::KeyUp => :sym,
SDL::Event::MouseButtonDown => :button,
SDL::Event::MouseButtonUp => :button
}
end

def handling(event)
name = event.class
if @type[name]
if callback = @handle[[name,event.method(@type[name]).call]]
return callback.call(event)
end
end
if callback = @handle[name]
return callback.call(event)
end
nil
end
end

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::BLACK)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Button
def initialize(w, h)
@width, @height = 80, 30
@color = Cairo::Color::SILVER
@handle = EventHandle.new(
[SDL::Event::MouseButtonDown,SDL::Mouse::BUTTON_LEFT] => proc{|e| @color = Cairo::Color::RED if touch_point?(e)},
[SDL::Event::MouseButtonUp,SDL::Mouse::BUTTON_LEFT] => proc{|e| @color = Cairo::Color::SILVER}
)
end

def handling(e)
@handle.handling(e)
end

def touch_point?(e)
@range_x.include?(e.x - @x) && @range_y.include?(e.y - @y)
end
end

class Button1 < Button
def initialize(w, h)
super
@x, @y = w / 2, h / 3
cx, cy = @width / 2, @height / 2
@vectors = [
[-cx, -cy],
[cx, -cy],
[cx, cy],
[-cx, cy]]
@range_x = -cx .. cx
@range_y = -cy .. cy
end

def update(c)
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(@color)
@vectors.inject(true) do |b, v|
x, y = v
if b
c.move_to(x, y)
else
c.line_to(x, y)
end
b = false
end
c.close_path
c.fill_preserve
c.set_source_color(Cairo::Color::TEAL)
c.stroke
end
end

class Button2 < Button
def initialize(w, h)
super
@x, @y = w / 2, h / 3 * 2
cx, cy = @width / 2, @height / 2
@range_x = -cx .. cx
@range_y = -cy .. cy
end

def update(c)
c.matrix = Cairo::Matrix.translate(@x, @y)
c.set_source_color(@color)
c.rectangle(@range_x.first, @range_y.first, @range_x.last * 2, @range_y.last * 2)
c.fill_preserve
c.set_source_color(Cairo::Color::TEAL)
c.stroke
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@items = []
@items << Button1.new(@w, @h)
@items << Button2.new(@w, @h)
@handle = EventHandle.new(
SDL::Event::Quit => proc{exit},
[SDL::Event::KeyDown,SDL::Key::ESCAPE] => proc{exit}
)
end

def handling(e)
@handle.handling(e)
@items.each do |obj|
obj.handling(e)
end
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@items.each do |obj|
obj.update(context)
end
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
self.handling(e)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
screen = SDL::Screen.open(250, 250, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(screen).run
[PR]
by gaziya | 2011-05-17 19:10