適当なRubyのお絵描きツール

Postscriptを出力できます。Postscriptしか出力できません。
線の補正とかしようかと思ったけどめんどかったので相当やる気無い方法になってます。

忘れてた

保存ダイアログはEnterキーで呼び出します。


Ruby/Tkの方の線の表示が汚ないのは仕様です。

ActiveScriptRuby 1.8.6 + ActiveTcl 8.4.16.1 で動作確認。
以下ソース

#!/usr/bin/ruby

require "tk"

class Point
  def initialize(x, y)
    @x = x
    @y = y
  end
  def x
    @x
  end
  def y
    @y
  end
end
class TkcCurveLine
  def initialize(parent, x, y)
    @parent = parent
    @points = [Point.new(x, y)]
    @lines = []
    @width = 5
  end
  def appendPoint(x, y)
    prevpt = @points[-1]
    point = Point.new(x, y)
    @points.push(point)
    line = TkcLine.new(@parent, prevpt.x, prevpt.y, x, y)
    line.width = @width
    @lines.push(line)
  end
  def reshape
    newpoints = []
    for i in 0..(@points.length-1)
      if(i>0 && i<@points.length-1)
        prevpt = @points[i-1]
        nextpt = @points[i+1]
        newpt = Point.new((prevpt.x+nextpt.x)/2, (prevpt.y+nextpt.y)/2)
        newpoints.push(newpt)
      else
        newpoints.push(@points[i])
      end
    end
    @points = newpoints
    repaint
  end
  def repaint
    delete
    prevpt = false
    @points.each{|p|
      if(prevpt)
        line = TkcLine.new(@parent, prevpt.x, prevpt.y, p.x, p.y)
        line.width = @width
        @lines.push(line)
      end
      prevpt = p
    }
  end
  def delete
    @lines.each{|line|
      line.delete
    }
  end
  def to_psseg
    seg = ""
    @points.each{|p|
      if(seg=="")
        seg += sprintf("%d %d moveto\n", p.x, p.y)
        first = false
      else
        seg += sprintf("%d %d lineto\n", p.x, p.y)
      end
    }
    seg += sprintf("%d setlinewidth\n", @width)
    seg += "stroke\n"
    seg
  end
end
class TkPaintCanvas < TkCanvas
  def initialize
    super
    self.bg = "white"
    @press = false
    @lines = []
    self.bind("Motion", proc{|x, y| mouseMotion(x, y)}, "%x %y")
    self.bind("ButtonPress", proc{|x, y| mousePress(x, y)}, "%x %y")
    self.bind("ButtonRelease", proc{|x, y| mouseRelease(x, y)}, "%x %y")
  end
  def mouseMotion(x, y)
    if(@press)
      mouseDrag(x, y)
    end
  end
  def mouseDrag(x, y)
    @curve.appendPoint(x, y)
  end
  def mousePress(x, y)
    @press = true
    @curve = TkcCurveLine.new(self, x, y)
  end
  def mouseRelease(x, y)
    @curve.reshape
    @lines.push(@curve)
    @press = false
  end
  def saveImage
    savepath = Tk.getSaveFile("defaultextension"=>".eps")
    pssegs = "%!PS-Adobe-3.0 EPSF-3.0\n"
    pssegs += sprintf("%%%%BoundingBox: 0 0 %d %d\n", self.width, self.height)
    pssegs += sprintf("0 %d translate 1 -1 scale\n", self.height)
    pssegs += "newpath\n"
    if(savepath!="")
      @lines.each{|line|
        pssegs +=  line.to_psseg
      }
      File.open(savepath, "w"){|file|
        file.print(pssegs)
      }
    end
  end
end
canvas = TkPaintCanvas.new
canvas.pack
rootResize = proc{|w, h|
  canvas.width = w-4
  canvas.height = h-4
}
Tk.root.bind("Configure", rootResize, "%w %h")
Tk.root.bind("Return", proc{canvas.saveImage})
Tk.mainloop

rootResizeのw-4の4ってなんでしょうね。俺にもよくわかりません。
そうしないとキャンバスがどんどんおっきくなっちゃったので。なんかもっと良い方法は絶対あるはずだけどめんどいので。

Postscriptとか全然憶えてなくて困った。

test