Created
August 25, 2014 12:14
-
-
Save takehiko/2078abe153c007f6d022 to your computer and use it in GitHub Desktop.
Region calculator using ImageMagick's convert command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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