Skip to content

Instantly share code, notes, and snippets.

@takehiko
Created August 25, 2014 12:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takehiko/2078abe153c007f6d022 to your computer and use it in GitHub Desktop.
Save takehiko/2078abe153c007f6d022 to your computer and use it in GitHub Desktop.
Region calculator using ImageMagick's convert command
#!/usr/bin/env ruby
# im-text-region.rb - Region calculator using ImageMagick's convert command
# by takehikom
# ruby $S/priv/rb/im-text-region.rb
# ruby $S/priv/rb/im-text-region.rb '和歌山' Meiryo-UI-Regular
class TextRegion
def initialize(opt = {})
@debug = opt[:debug] #|| true
@str = opt[:str] || "-|-"
@font = opt[:font] || "Liberation-Sans-Regular"
@pointsize = opt[:pointsize] || 48
@basename = opt[:basename] || setup_basename
@direction = opt[:direction] || "center"
@xpm_width = @pointsize * @str.length
@xpm_height = @pointsize
@region = [0, 0, 100, 100] # x1,y1,x2,y2
setup_region
end
def setup_basename
require "tempfile"
t = Tempfile.open("tmsr")
@basename = t.path
puts "basename: #{@basename}" if @debug
t.close!
@basename
end
def setup_region
init_xpm_size
create_xpm
analyze_xpm
end
def init_xpm_size
ext = 2
command = "convert -debug annotate xc:" +
" -font %s -pointsize %d -annotate 0 '%s'" % [@font, @pointsize, @str] +
" null: 2>&1 | grep Metrics:"
puts command if @debug
result = `#{command}`
if /width:\s*(\d*(\.\d*)?)/ =~ result
@xpm_width = $1.to_f.ceil.to_i + ext
else
raise "#{command} --- \"width:\" not found"
end
if /height:\s*(\d*(\.\d*)?)/ =~ result
@xpm_height = $1.to_f.ceil.to_i + ext
else
raise "#{command} --- \"height:\" not found"
end
puts "xpm_image: #{@xpm_width}x#{@xpm_height}" if @debug
end
def create_xpm
@xpmfile = @basename + ".xpm"
command = "convert -size %dx%d xc:white" % [@xpm_width, @xpm_height] +
" -fill black -font %s -pointsize %d" % [@font, @pointsize] +
" -draw \"text %d,%d \'%s\'\"" % [0, @pointsize, @str] +
" -colors 2 %s" % @xpmfile
puts command if @debug
system command
if !test(?f, @xpmfile)
raise "#{@xpmfile} not created"
end
end
def analyze_xpm
@color = [] # [[" ", "#067D067D067D"], [".", "#FDE6FDE6FDE6"]]
@pixel = [] # ["...", "...", ...]
open(@xpmfile) do |f_in|
f_in.each_line do |line0|
next unless /^\".*\",?/ =~ line0
line = line0.strip.sub(/\"/, "").sub(/\",?/, "")
next if /(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/ =~ line
if /(.) c / =~ line
@color << [$1, $']
else
@pixel << line
end
end
end
if @color.empty?
raise "#{@xpmfile}: color not specified."
elsif @color.length != 2
raise "#{@xpmfile}: not a B/W image."
elsif @pixel.empty?
raise "#{@xpmfile}: image not specified."
end
if @debug
puts "image: #{@pixel[0].length}x#{@pixel.length}"
puts "color:"
@color.each do |item|
puts " #{item[0]} => #{item[1]}"
end
end
c_black, c_white = @color.
sort_by { |item| item.last }.
map { |item| item.first }
puts " black => \"#{c_black}\"" if @debug
puts " white => \"#{c_white}\"" if @debug
x1 = @pixel[0].length
x2 = -1
y1 = @pixel.length
y2 = -1
@pixel.each_with_index do |line, i|
next if (pos = line.index(c_black)).nil?
if y1 == @pixel.length
y1 = i
end
y2 = i
if pos < x1
x1 = pos
end
pos2 = line.rindex(c_black, -1)
if pos2 && pos2 > x2
x2 = pos2
end
end
if x2 == -1 || y2 == -1
raise "#{@xpmfile}: seems to be all-white."
end
@region = [x1, y1, x2, y2]
puts "region: (%d,%d)-(%d,%d)" % @region if @debug
File.delete(@xpmfile) unless @debug
end
def test_draw
@pngfile1 = @basename + "1.png"
ofst_x, ofst_y = get_offset
puts "ofst: (#{ofst_x},#{ofst_y})" if @debug
command = "convert -size 400x400 xc:skyblue" +
" -stroke blue -strokewidth 1 -draw \"line 0,200 400,200\" -draw \"line 200,0 200,400\"" +
" -stroke none -fill black -font %s -pointsize %d" % [@font, @pointsize] +
" -draw \"text %d,%d \'%s\'\"" % [200 + ofst_x, 200 + ofst_y, @str] +
" -quality 90 %s" % @pngfile1
puts command if @debug
system command
@pngfile2 = @basename + "2.png"
command = "convert -size %dx%d xc:white" % [@xpm_width, @xpm_height] +
" -fill black -font %s -pointsize %d" % [@font, @pointsize] +
" -draw \"text %d,%d \'%s\'\"" % [0, @pointsize, @str] +
" -fill none -stroke red -strokewidth 1" +
" -draw \"rectangle %d,%d %d,%d\"" % @region +
" -draw \"line %d,%d %d,%d\"" % @region +
" -draw \"line %d,%d %d,%d\"" % @region.values_at(0, 3, 2, 1) +
" -quality 90 %s" % @pngfile2
puts command if @debug
system command
end
def get_offset(dir = @direction)
# "northwest" "north" "northeast"
# "west" "center" "east"
# "southwest" "south" "southeast"
x = (@region[0] + @region[2]) * 0.5 * (-1)
y = (@region[1] + @region[3]) * 0.5 * (-1) + @pointsize
if /west|left/i =~ dir
x = @region[0] * (-1)
elsif /east|right/i =~ dir
x = @region[2] * (-1)
end
if /north|up/i =~ dir
y = @region[1] * (-1) + @pointsize
elsif /south|low/i =~ dir
y = @region[3] * (-1) + @pointsize
end
[x, y]
end
alias :start :test_draw
end
if __FILE__ == $0
str = ARGV.shift || "-|-"
font = ARGV.shift || "Liberation-Sans-Regular"
pointsize = (ARGV.shift || 48).to_i
basename = ARGV.shift || "im-text-region"
direction = ARGV.shift || "center"
TextRegion.new(:str => str,
:font => font,
:pointsize => pointsize,
:basename => basename,
:direction => direction).start
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment