--- /dev/null
+#!/usr/bin/env ruby
+# CSF module by eto 2002-1115
+
+require 'sgl'
+require 'kconv'
+require 'uconv'
+
+module StrokeFont
+ CSF_FONT_DIR = 'd:/work/chise/csf/'
+ CSF_DEFAULT_FILE = 'KST32B.CSF1'
+ CSF_KOUKOTSU_FILE = 'KST32ZX.CSF1'
+
+ class CSFStrokeMaker #======================================================================
+ DEST_WIDTH = 1000 #\91å\82«\82³\82ð\82¨\82¨\82æ\82»1000x1000\82É\90³\8bK\89»\82·\82é\81B
+ ORG_WIDTH = 32 #\8c³\82Ì\83T\83C\83Y\82Í\81A\89¡30\81~\8fc32
+ def initialize
+ @x, @y, @nx, @ny = 0, 0, 0, 0
+ @strokes = Strokes.new
+ end
+ attr_reader :strokes
+ def move_to_x(x) @x = x; @nx = x; end
+ def draw_to_x(x) @nx = x; drawline; @x = @nx; @y = @ny; end
+ def next_x_to(x) @nx = x; end
+ def move_to_y(y) @y = y; @ny = y; end
+ def draw_to_y(y) @ny = y; drawline; @x = @nx; @y = @ny; end
+ def drawline()
+ @strokes.add_line(t(@x), t(@y), t(@nx), t(@ny))
+ end
+ def t(a) a*DEST_WIDTH/ORG_WIDTH; end
+ end
+
+ class CSFParser #======================================================================
+ def self.parse(str) #Strokes\82ð\95Ô\82·
+ return Strokes.new if str == nil
+ sm = CSFStrokeMaker.new
+ (0...str.length).each {|i|
+ n = str[i]
+ if 0x21 <= n && n <= 0x26
+ sm.move_to_x(n - 0x21)
+ elsif 0x28 <= n && n <= 0x3f
+ sm.move_to_x(n - 0x28 + 6)
+ elsif 0x40 <= n && n <= 0x5b
+ sm.draw_to_x(n - 0x40)
+ elsif 0x5e <= n && n <= 0x5f
+ sm.draw_to_x(n - 0x5e + 28)
+ elsif 0x60 <= n && n <= 0x7d
+ sm.next_x_to(n - 0x60)
+ elsif 0x7e == n
+ sm.move_to_y(n - 0x7e)
+ elsif 0xa1 <= n && n <= 0xbf
+ sm.move_to_y(n - 0xa1 + 1)
+ elsif 0xc0 <= n && n <= 0xdf
+ sm.draw_to_y(n - 0xc0)
+ end
+ }
+ return sm.strokes
+ end
+ end
+
+ class CSFGlyph #======================================================================
+ def initialize(code, stroke)
+ @code = code
+ @stroke_str = stroke
+ @strokes = nil
+ end
+ attr_reader :strokes
+ def parse()
+ return if @strokes
+ @strokes = CSFParser.parse(@stroke_str)
+ end
+ def init
+ parse if @strokes.nil?
+ end
+ end
+
+ class CSFFont #======================================================================
+ def initialize(file=CSF_DEFAULT_FILE)
+ @file = CSF_FONT_DIR + file
+ @glyphs = []
+ read_file
+ @rend = nil
+ @rend = StrokesRenderer.new
+ @rend.hsv = [50, 100, 100]
+ end
+ def read_file()
+ open(@file) {|f|
+ while(line = f.gets)
+ next if line =~ /^\*/
+ c, s = line.split
+ code = c.hex #JIS\82Ì\92l\82ª\90\94\92l\82Å\82Í\82¢\82é
+ @glyphs[code] = CSFGlyph.new(code, s)
+ end
+ }
+ end
+ def init(code)
+ glyph = @glyphs[code]
+ return if glyph == nil
+ glyph.init()
+ glyph.parse
+ @rend.set_strokes(glyph.strokes)
+ end
+ def draw(code) #\88ø\90\94\82É\82ÍJIS\82ð\90\94\92l\89»\82µ\82½\82à\82Ì\82ª\82Í\82¢\82é
+ glyph = @glyphs[code]
+ return if glyph == nil
+ @rend.draw
+ end
+ def print(code)
+ jis = JISX0208.new
+ char = jis.get_char(code)
+ printf("[%s][%04x]\n", char.nil? ? "nil" : char.map_sjis, code)
+ end
+ def ucs_to_jis(ucs)
+ char = Character.get(ucs)
+ j = char.japanese_jisx0208
+ return j
+ end
+ end
+
+end
+
+#----------------------------------------------------------------------\8fI\97¹
--- /dev/null
+#!/usr/bin/env ruby
+# KageFont library by eto 2003-0311
+
+require 'sgl'
+require 'kageserver'
+
+#こんな感じのフォーマットになっている。
+#<?xml version="1.0"?>
+#<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+#<svg viewBox="0 0 1000 1000">
+#<path d="M 50,540 950,255 " style="fill: none; stroke: black; stroke-width: 10; stroke-linecap: round;"/>
+#<path d="M 330,50 330,900 M 330,900 Q 330,950 380,950 M 380,950 840,950 M 840,950 Q 890,950 915,850 " style="fill: none; stroke: black; stroke-width: 10; stroke-linecap: round;"/>
+#</svg>
+
+module StrokeFont
+ class KageParser #======================================================================
+ def self.parse(svg)
+ @strokes = Strokes.new
+ lines = svg.split(/\n/)
+ lines.each {|line|
+ next unless line =~ /^<path/
+ if line =~ /d=\"([a-zA-Z0-9, ]+)\"/
+ KageParser.parse_path($1)
+ end
+ }
+ return @strokes
+ end
+ def self.parse_path(str)
+ #M 50,540 950,255
+ #M 330,50 330,900 M 330,900 Q 330,950 380,950 M 380,950 840,950 M 840,950 Q 890,950 915,850
+ px, py = -1, -1
+ str.split.each {|par|
+ next if par.length == 1 #一文字はとばします。本来はちゃんとベジェを展開する。
+ if par =~ /[,0-9]+/
+ sx, sy = par.split(/,/)
+ x, y = sx.to_i, (1000 - sy.to_i)
+ if px != -1
+ @strokes.add_line(px, py, x, y)
+ end
+ px, py = x, y
+ end
+ }
+ end
+ end
+
+ class KageGlyph #====================================================================== てなかんじ
+ def initialize(code, svg)
+ @code = code
+ @svg = svg
+ @strokes = nil
+ end
+ attr_reader :strokes
+ def parse
+ return if @strokes
+ @strokes = KageParser.parse(@svg)
+ end
+ def init
+ parse if @strokes.nil?
+ end
+ end
+
+ class KageFont #======================================================================
+ def initialize
+ @server = KageServer.instance
+ @glyphs = []
+ @cache_list = @server.list_cache
+ @rend = nil
+ @rend = StrokesRenderer.new
+ @rend.hsv = [13, 100, 100]
+ end
+ attr_reader :cache_list
+ def get(code)
+ return @glyphs[code] if @glyphs[code]
+ svg = @server.get(code)
+ return nil if svg.nil?
+ @glyphs[code] = KageGlyph.new(code, svg)
+ end
+ def init(code)
+ glyph = get(code)
+ return if glyph.nil?
+ glyph.init
+ glyph.parse
+ @rend.set_strokes(glyph.strokes)
+ end
+ def draw(code)
+ glyph = get(code)
+ return if glyph.nil?
+ @rend.draw
+ end
+ def print(code)
+ char = Character.new(@code)
+ printf("[%s][%04x]\n", char.nil? ? "nil" : char.map_sjis, code)
+ end
+ end
+
+end
+
+#----------------------------------------------------------------------end.
--- /dev/null
+#!/usr/bin/env ruby
+
+$LOAD_PATH << '../ruby/src'
+require 'chise'
+include CHISE
+require 'singleton'
+require 'net/http'
+require 'uri'
+require 'network' #漢字間接続のネットワークを計算する
+
+class KageServer #======================================================================
+ include Singleton
+ TYPES = "skeleton mincho gothic".split
+ SKELETON = 0
+ MINCHO = 1
+ GOTHIC = 2
+ HOME_DIR = "d:/work/chise/"
+ CACHE_DIR = HOME_DIR + "cache_kage"
+ URL = "http://192.168.2.60:5100/"
+ #URL = "http://218.219.209.16:5100/"
+ def initialize(url=URL)
+ @url = url
+ @glyphs = []
+ @use_cache = true #デフォルト: cacheに存在する場合はcacheから引き出す。
+ @offline = false #テスト用
+ @offline = true #テスト用
+ Dir.mkdir(CACHE_DIR) unless FileTest.directory?(CACHE_DIR)
+ end
+ attr_accessor :url, :use_cache
+ def filename(num, type=SKELETON) sprintf("u%04x.%s", num, TYPES[type]) end
+ def cache_file(num, type=SKELETON) CACHE_DIR+"/"+filename(num, type)+".svg" end
+
+ def list_cache
+ ar = []
+ Dir.chdir(CACHE_DIR)
+ Dir.glob("*.svg").each {|file|
+ if file =~ /^u([0-9a-fA-F]+).skeleton.svg$/
+ code = $1.hex
+ ar << code
+ end
+ }
+ ar
+ end
+
+ def get(num, type=SKELETON)
+ return open(cache_file(num, type)).read if FileTest.exist?(cache_file(num, type))
+ svg = get_http(num, type)
+ return svg if svg
+ return nil
+ end
+ def get_http(num, type=SKELETON)
+ return nil if @offline
+ uri = URI.parse(URL + filename(num, type))
+ p ['uri', uri.to_s]
+ Net::HTTP.version_1_1 # declear to use 1.1 features.
+ Net::HTTP.start( uri.host, uri.port ) {|http|
+ response, body = http.get('/'+filename(num, type)+".svg")
+ if body
+ if error?(body)
+ p ['error', uri.to_s]
+ return nil
+ else
+ store_cache(num, type, body)
+ return body
+ end
+ end
+ }
+ return nil
+ end
+ def store_cache(num, type, svg)
+ open(cache_file(num, type), "w") {|f|
+ f.print svg
+ }
+ end
+ def error?(svg)
+ (svg =~ /<!-- error -->/)
+ end
+ def read_list
+ h = {}
+ open("kage-list.txt"){|f|
+ while line = f.gets
+ if line =~ /u([0-9a-f]+)\.skeleton/
+ code = $1
+ num = code.hex
+ error = false
+ error = true if line =~ /error/
+ h[num] = error
+ end
+ end
+ }
+ return h
+ end
+ def get_all
+ #error_h = read_list
+ STDOUT.binmode
+ @kn = KanjiNetwork.new
+ @kl = KanjiList.instance
+ #list = @kl.awase(0)
+ #list = @kl.awase(1)
+ list = @kl.joyo
+ @kn.make_network(list)
+ nodes, edges = @kn.nodes_and_edges
+ ar = []
+ nodes.each {|ch|
+ char = ch.char
+ num = char.to_i
+ #next if 0xffff < num
+ ar << num
+ }
+ get_ar(ar)
+ end
+ def get_ar(ar)
+ ar.each {|num| #intの数列
+ char = Character.get(num)
+ ch = char.to_s
+ er = char.to_er
+ #TYPES.each_with_index {|type, index|
+ #(0..2).each {|index|
+ (0..0).each {|index|
+ result = get(num, index) #cacheに保存するべしと。
+ next if result
+ err = "error"
+ print "#{er} #{ch} #{err}\n"
+ }
+ }
+ end
+ def test_kanji
+ char = "&CDP-8BA5;".de_er
+ #p char.inspect_all
+ #str = (char.to_s+"真")
+ str = (char.to_s+"直")
+ p str.find
+ end
+end
+
+if $0 == __FILE__ #======================================================================
+ ks = KageServer.instance
+ #print ks.get(0x4e03)
+ ks.get_all
+end
+
+#----------------------------------------------------------------------end.
--- /dev/null
+#!/usr/bin/env ruby
+# StrokeFont library by eto 2003-0311
+
+require 'sgl'
+require 'kage'
+require 'csf'
+
+module StrokeFont
+ class StrokesRenderer #======================================================================
+ def initialize
+ @start_time = nil
+ @strokes = nil
+ @hsv = [0, 0, 100]
+ init
+ end
+ attr_accessor :hsv
+ def init() @start_time = Time.now; end
+ def set_strokes(strokes)
+ @strokes = strokes
+ init
+ end
+ def draw
+ @strokes.strokes.each_with_index {|stroke, index|
+ draw_delay(stroke, index)
+ }
+ end
+ def draw_alpha(stroke, time)
+ px, py = 0, 0
+ span = 0.1
+ time += span*2
+ stroke.points.each {|x, y|
+ a = time / span
+ colorHSV(@hsv[0], @hsv[1], @hsv[2], a*100.0)
+ line(px, py, x, y) if (px != 0 || py != 0) #最初の点ではない
+ px, py = x, y
+ time -= span
+ }
+ end
+ def draw_delay(stroke, index)
+ now = Time.now
+ @start_time = Time.now if @start_time == nil
+ diff = now - @start_time #開始からの秒数がはいる
+ draw_alpha(stroke, diff - index*0.3)
+ end
+ end
+
+ class Stroke #====================================================================== 一本の線
+ def initialize
+ @points = []
+ @length = nil
+ end
+ attr_reader :points
+ def add_point(x, y)
+ @points << [x, y]
+ end
+ def length #未チェック
+ return @length if @length
+ len = 0.0
+ px, py = -1, -1
+ @points.each {|x, y|
+ if px != -1
+ len += Math.sqrt((x-px)*(x-px)+(y-py)*(y-py))
+ end
+ px, py = x, y
+ }
+ @length = len
+ return @length
+ end
+ end
+
+ class Strokes #====================================================================== 複数の線
+ def initialize
+ @strokes = []
+ @px1, @py1, @px2, @py2 = 0, 0, 0, 0
+ @x1, @y1, @x2, @y2 = 0, 0, 0, 0
+ @px, @py = -1, -1
+ end
+ attr_reader :strokes
+ def add_line(x1, y1, x2, y2)
+ if (@px != x1 || @py != y1) #以前の点とつながっていなかったら、
+ @strokes << Stroke.new
+ @strokes.last.add_point(x1, y1)
+ end
+ @strokes.last.add_point(x2, y2)
+ @px, @py = x2, y2
+ end
+ end
+
+ class CodeSelector #======================================================================
+ WIDTH, HEIGHT = 256, 256
+ SCALE = 2
+ def initialize(cx=0, cy=0)
+ @cx, @cy = cx, cy
+ @s = SCALE
+ @x1, @y1 = @cx-@s*WIDTH/2, @cy-@s*HEIGHT/2
+ @x2, @y2 = @cx+@s*WIDTH/2, @cy+@s*HEIGHT/2
+ @px, @py = @cx, @cy #とりあえず中心が開始点
+ @pw, @ph, @pr = 30, 30, 10
+ @dragging = false
+ @onkeydown = false
+ @code = 0
+ calc_code
+ end
+ attr_reader :code
+ def draw
+ colorHSV(0, 0, 100, 10) #まずは下敷きになる枠を書きます。
+ rect(@x1, @y1, @x2, @y2)
+ lineWidth(1)
+ colorHSV(0, 0, 100, 50)
+ b = 8; s = @s*WIDTH/b
+ (0..b).each {|n|
+ line(@x1, @y1+n*s, @x2, @y1+n*s)
+ line(@x1+n*s, @y1, @x1+n*s, @y2)
+ }
+ colorHSV(0, 100, 100, 100) # 次にポインターを書きます
+ circle(@px, @py, @pr)
+ line(@px-@pw/2, @py, @px+@pw/2, @py)
+ line(@px, @py-@ph/2, @px, @py+@ph/2)
+ end
+ def onMouse(x, y)
+ if @onkeydown
+ x, y = @px, @py
+ end
+ if @dragging || @onkeydown
+ @onkeydown = false
+ @px, @py = x, y #p [x, y]
+ @px = @x1 if @px < @x1
+ @py = @y1 if @py < @y1
+ @px = @x2-1 if @x2-1 < @px
+ @py = @y2-1 if @y2-1 < @py
+ return calc_code
+ else
+ return false
+ end
+ end
+ def calc_code()
+ x = ((@px - @x1)/@s).to_i
+ y = HEIGHT-1 - ((@py - @y1)/@s).to_i
+ code = x + y*WIDTH
+ if @code != code
+ @code = code
+ return true #changed
+ #p [x, y, code]
+ printf("%02x %02x %04x\n", x, y, @code)
+ else
+ return false
+ end
+ end
+ def show_list(list)
+ colorHSV(0, 100, 100, 100)
+ list.each {|code|
+ x, y = code_to_xy(code)
+ rect(x, y, x+2, y-2)
+ }
+ end
+ def code_to_xy(code)
+ cx = code % WIDTH
+ cy = HEIGHT - (code / WIDTH) #intになる?
+ x = cx * SCALE + @x1
+ y = cy * SCALE + @y1
+ return x, y
+ end
+ def length(x, y) Math.sqrt(x*x + y*y) end
+ def onMouseDown(x, y)
+ if length(@px-x, @py-y) < @pr
+ @dragging = true
+ end
+ end
+ def onMouseUp(x, y) @dragging = false end
+ def onKeyDown(key)
+ @onkeydown = true
+ case key
+ when 273
+ @py += @s
+ when 274
+ @py -= @s
+ when 276
+ @px -= @s
+ when 275
+ @px += @s
+ end
+ end
+ end
+
+end
+
+if $0 == __FILE__ #======================================================================
+ $LOAD_PATH << '../ruby/src'
+ require 'chise'
+ include CHISE
+ require 'stroke'
+ include StrokeFont
+
+ def setup
+ useSmooth()
+ window(-300,-300,300,300)
+ background 0,0,20
+ useFramerate(30)
+ @cs = CodeSelector.new
+ @csf1 = CSFFont.new() #普通の文字
+ @csf2 = CSFFont.new(CSF_KOUKOTSU_FILE) #甲骨文字
+ @key = 1
+ @kage = KageFont.new()
+ @changed = nil
+ end
+
+ def display
+ @changed = @cs.onMouse(mouseX, mouseY) #変化があったか?
+ @cs.draw
+ @cs.show_list(@kage.cache_list)
+ code = @cs.code
+
+ push
+ scale 0.2
+ translate -500,-500
+ lineWidth(2)
+ draw_kage(code)
+ draw_csf(code)
+ pop
+ end
+
+ def draw_kage(code)
+ char = Character.get(code)
+ return if char.nil?
+ @kage.init(code) if @changed
+ @kage.print(code) if @changed
+ @kage.draw(code)
+ end
+
+ def draw_csf(ucs)
+ char = Character.get(ucs)
+ return if char.nil?
+ j = char.japanese_jisx0208
+ return if j.nil?
+ code = j
+ csf = @key == 1 ? @csf1 : @csf2
+ csf.init(code) if @changed
+ csf.print(code) if @changed
+ csf.draw(code)
+ end
+
+ def onMouseDown(x, y) @cs.onMouseDown(x, y)end
+ def onMouseUp(x, y) @cs.onMouseUp(x, y)end
+ def onKeyDown(key)
+ @key = key
+ @cs.onKeyDown(key)
+ end
+ mainloop
+end
+
+#----------------------------------------------------------------------end.