Skip to content

Instantly share code, notes, and snippets.

@doraTeX
Last active Aug 29, 2015
Embed
What would you like to do?
「ことばのおもみ」自動測定スクリプト http://doratex.hatenablog.jp/entry/20150331/1427755389
#!/usr/bin/ruby -W0
# coding: utf-8
#
# This software is derived from bmp.rb provided by Yoichi Yokogawa.
# https://github.com/yoyoichi/bmp-ruby
#
# This software is released under the MIT License.
# http://opensource.org/licenses/mit-license.php
### BitMap class
class BitMap
def initialize(width, height, dpi = 96)
@width = width
@height = height
@line_size = width * 3 + (4 - (width * 3) % 4) % 4
@buf_size = @line_size * height
@buf = ("\000" * @buf_size).encode('BINARY')
@bit_count = 24
@compression = 0
@size_image = 0
@x_pix_per_meter = (39.375 * dpi).round
@y_pix_per_meter = (39.375 * dpi).round
@clr_used = 0
@cir_important = 0
@black_count = -1
@black_ratio = -1
end
attr_writer :buf
attr_reader :width, :height
def BitMap.read(filename)
buf = nil
open(filename, "rb") do |f|
buf = f.read
end
if buf[0] != ?B or buf[1] != ?M
raise '[Error] read: Invalid Header'
end
real_buf_size = buf.size
buf_size = (buf[2, 4].unpack("l*"))[0]
if buf_size > real_buf_size
raise '[Error] read: Invalid Buffer Size'
end
data_offset = (buf[10, 4].unpack("l*"))[0]
if data_offset != 54
raise '[Error] read: Invalid Data Offset'
end
width = (buf[18, 4].unpack("l*"))[0]
height = (buf[22, 4].unpack("l*"))[0]
bit_count = (buf[28, 2].unpack("s*"))[0]
if bit_count != 24
raise '[Error] read: Unsupported Color Depth'
end
compression = (buf[30, 4].unpack("l*"))[0]
if compression != 0
raise '[Error] read: Compression Not Supported'
end
pix_per_meter = (buf[38, 4].unpack("l*"))[0]
dpi = pix_per_meter / 39.375
image_buf = buf[54, buf_size]
image = BitMap.new(width, height, dpi)
image.buf = image_buf
return image
end
def pget(x, y)
x = 0 if x < 0
x = @width - 1 if x >= @width
y = 0 if y < 0
y = @height - 1 if y >= @height
addr = (@height - 1 - y) * @line_size + x * 3
b = @buf[addr ].ord
g = @buf[addr + 1].ord
r = @buf[addr + 2].ord
return [r, g, b]
end
def blackPixelCount
return @black_count if @black_count >= 0
count = 0
(0...@width).each{|x|
(0...@height).each{|y|
count +=1 if pget(x, y) == [0, 0, 0]
}
}
@black_count = count
end
def blackPixelRatio
return @black_ratio if @black_ratio >= 0
@black_ratio = blackPixelCount.to_f / (@width*@height)
end
end
### main
require 'fileutils'
require 'optparse'
SCRIPT = $0
TEMPNAME = "wordweight"
$texfile = "#{TEMPNAME}.tex"
$bmpfile = "#{TEMPNAME}.bmp"
def usage
puts "Usage : #{File.basename(SCRIPT)} [\e[1m-s\e[0m \e[4msize\e[0m] [\e[1m-r\e[0m \e[4mresolution\e[0m] [\e[1m-d\e[0m] \e[4mfontname\e[0m \e[4mwords...\e[0m "
puts "Options:"
puts " \e[1m-s\e[0m \e[4msize\e[0m : set font size (pt) (default: 100)"
puts " \e[1m-r\e[0m \e[4mresolution\e[0m : set resoluion for font rendering (default: 600)"
puts " \e[1m-d\e[0m : do not delete temporary files for debug"
exit
end
def clean
FileUtils.rm_rf([$texfile, "#{TEMPNAME}.aux", "#{TEMPNAME}.log", "#{TEMPNAME}.pdf", $bmpfile])
end
def measure(word)
clean
zw = $fontsize.to_f
ht = 0.88*zw
dp = 0.12*zw
open($texfile, "w") {|f| f.write <<EOS
\\documentclass{article}
\\usepackage{fontspec}
\\newfontfamily\\theFont{#{$fontname}}
\\pagestyle{empty}
\\usepackage[tightpage,active]{preview}
\\PreviewEnvironment{minipage}
\\parindent=0pt
\\begin{document}
\\setbox0=\\hbox{\\theFont\\fontsize{#{$fontsize}pt}{0pt}\\selectfont #{word}}%
\\ht0=#{ht}pt
\\dp0=#{dp}pt
\\begin{minipage}{\\wd0}\\box0\\end{minipage}
\\end{document}
EOS
}
system("xelatex -no-shell-escape -interaction=batchmode #{TEMPNAME} > /dev/null")
system("gs -sDEVICE=bmp16m -dNOPAUSE -dBATCH -sOutputFile=#{$bmpfile} -r#{$resolution} #{TEMPNAME}.pdf > /dev/null") if $? == 0
if $? == 0 && File.exist?($bmpfile)
bmp = BitMap.read($bmpfile)
puts "Font name : #{$fontname}"
puts "Font size : #{$fontsize}pt"
puts "Word : #{word}"
puts "Resolution : #{$resolution}dpi"
puts "Total pixels : #{bmp.width * bmp.height}"
puts "Black pixels : #{bmp.blackPixelCount}"
puts "Ratio : #{sprintf("%.2f%%", 100*bmp.blackPixelRatio)}"
else
puts "ERROR"
end
clean unless $debug
end
opt = OptionParser.new
$fontsize = 100
$resolution = 600
$debug = false
begin
opt.on('-s VAL') {|v|
$fontsize = v.to_i
usage unless $fontsize > 0
}
opt.on('-r VAL') {|v|
$resolution = v.to_i
usage unless $resolution > 0
}
opt.on('-d') { $debug = true }
opt.parse!(ARGV)
usage unless ARGV.length >= 2
$fontname = ARGV.shift
words = ARGV
rescue
usage
end
words.each{|w| measure(w)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment