SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|

2023-09-05(Tue) Rubyで端末画面に画像を表示する

  一応、CUIコンソール画面に画像を出力できたんだが、Maveに実装することを考えれば、縮小(ついでに拡大)機能と、右側のトリミング機能が必要だ。ついでに透過処理もできるとカッコいい。

  さて、透過処理はどうすれば……と考え込んだところで「▀」という「上半分塗りつぶし」文字と「▄」という「下半分塗りつぶし」文字を使い分ける必要があることに気づく。そういや、参考に読んだcatimgのコードで両方を使い分けていたのはそういうことだっとのか。

  しかし、どうも美しく実装できない。上から順に処理しつつ、上下2ドットを同時に処理する、というのが厄介。

  ちなみに、今回のケースもやや当てはまるのだが、こういう処理が必要な状況って時々ある。

# ./grouping.rb 
["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R"]
1: A,B,C,D,E
2: F,G,H,I,J
3: K,L,M,N,O
4: P,Q,R

  で、以下のようなコードを書いたりするのだが。

#!/usr/bin/env ruby
 
x = '@'; xs = []; 18.times {
    xs << x.succ!.dup
}
puts(xs.inspect)
 
n = 0; xp = []; xs.each {|x|
    xp << x
    if(xp.size == 5)
        puts('%d: %s' % [n += 1, xp.join(',')]) # same!
        xp.clear
    end
}
puts('%d: %s' % [n += 1, xp.join(',')])         # same!
 
__END__

  ここで「same!」とある行を2度書くのがすごくイヤなんだよな。こういうのに対応する構文を持つ言語ってあるのかしらん……とか考えつつ、その部分はさておき、他はどうにかこうにか納得できるコードが書けた。

#!/usr/bin/env ruby
 
require 'rmagick'
 
if(ARGV.size == 0)
    abort(<<USAGE)
Usage: rcatimg image_file [width] [trim]
USAGE
end
 
image = Magick::Image.read(ARGV[0])
w = image[0].columns
h = image[0].rows
 
tgt_w = `tput cols`.to_i
tgt_w > w and tgt_w = w
(it = ARGV[1]) and tgt_w = it.to_i
trm_x = false
(it = ARGV[2]) and trm_x = it.to_i
tgt_h = h * tgt_w / w
sstep = (h << 8) / tgt_h
 
# +---------+   tdms = [    [ 0b00, 'Ar;Ag;Ab', 'Wr;Wg;Wb' ],
# | A   C D |               [ 0b10,        nil, 'Xr;Xg;Xb' ],
# | W X   Z |               [ 0b01, 'Cr;Cg;Cb',        nil ],
# +---------+               [ 0b00, 'Dr;Dg;Db', 'Zr;Zg;Zb' ] ]
 
ess = [ "\e[38;2;%2$sm\e[48;2;%3$sm\u2580\e[m", # 0b00: f_col,  b_col,  [▀]
        "\e[38;2;%2$sm\u2580\e[m",              # 0b01: f_col,          [▀]
        "\e[38;2;%3$sm\u2584\e[m",              # 0b10:         f_col,  [▄]
        ' ' ]                                   # 0b11:                 [ ]
 
y8 = 0; tdms = []; tgt_h.times {
    x8 = 0; tgt_w.times {|cx|
        trm_x and (cx < trm_x or break)
        c = image[0].pixel_color(x8 >> 8, y8 >> 8)
        tdms[cx] ||= [0]
        tdms[cx][0] <<= 1
        if(c.opacity < 64)
            tdms[cx] << '%d;%d;%d' % [c.red >> 8, c.green >> 8, c.blue >> 8]
        else
            tdms[cx][0] += 1    # 透明
            tdms[cx] << nil
        end
        x8 += sstep
    }
    if(tdms[0].size == 3)
        tdms.each {|tdm|
            print(ess[tdm[0]] % tdm)
        }
        puts; tdms.clear
    end
    y8 += sstep
}
if(tdms.size != 0)
    tdms.each {|tdm|
        print(ess[(tdm[0] << 1) + 1] % tdm)
    }
    puts
end
 
if(ENV['INFO'])
    puts('#' * trm_x) if(trm_x)
    puts('#' * tgt_w)
    puts('[%d, %d] -> x%d/%d -> [%d, %d]' % [w, h, 256, sstep, tgt_w, tgt_h])
end
 
__END__

  画像の説明

  さて、次はMaveの方を見てみるかな。