require 'chunky_png'
class Color
  def initialize(color_table=nil)
    @color_table = color_table || [1, 0]
  end

  def rgb
    colors = [
      [[255,192,192], [255,0,0], [192,0,0]], # Red
      [[255,255,192], [255,255,0], [192,192,0]], # Yellow
      [[192,255,192], [0,255,0], [0,192,0]], # Green
      [[192,255,255], [0,255,255], [0,192,192]], # Cyan
      [[192,192,255], [0,0,255], [0,0,192]], # Blue
      [[255,192,255], [255,0,255], [192,0,192]], # Magenta
    ]
    colors[@color_table[1]][@color_table[0]]
  end

  def push_color
    @color_table[0] = (@color_table[0] + 1) % 3
    rgb
  end

  def write_color
    @color_table[0] = (@color_table[0] + 2) % 3
    @color_table[1] = (@color_table[1] + 5) % 6
    rgb
  end
end

current_color = Color.new
piet_painting = []

def draw_block(piet_painting, current_color,size,num)
  block = Array.new(12) { Array.new(12) { Array.new(3, 0) } }
  if num != 0
    old_push_color = current_color.push_color
    current_color.write_color

    block.each_index do |i|
      block[i].each_index do |j|
        block[i][j] = current_color.rgb
      end
    end
    block[0][0] = old_push_color
    size += 1
  else
    block.each_index do |i|
      block[i].each_index do |j|
        block[i][j] = current_color.rgb
      end
    end
  end

  pix_lft = 144 - size
  div = pix_lft / 12
  rem = pix_lft % 12

  if div != 0
    block[(12-div)..-1].each_index do |i|
      block[(12-div)..-1][i].each_index do |j|
        block[(12-div)+i][j] = [0,0,0]
      end
    end
  end
  block[(11-div)..-1].each_index do |i|
    block[(11-div)..-1][i][0...rem].each_index do |j|
      block[(11-div)+i][j] = [0,0,0]
    end
  end
  pos_y = 12 * num
  pos_x = 0
  piet_painting[pos_x...(pos_x+12)].each_index do |i|
    piet_painting[pos_x...(pos_x+12)][i][pos_y...(pos_y+12)].each_index do |j|
      piet_painting[pos_x+i][pos_y+j] = block[i][j]
    end
  end
end

def draw_end(piet_painting, current_color, num)
  block = Array.new(12) { Array.new(5) { Array.new(3, 255) } }

  old_push_color = current_color.push_color
  block[0][0] = old_push_color
  block[0][1] = current_color.write_color
  block[0...2].each_index do |i|
    block[i][3] = [0, 0, 0]
  end
  block[1][1] = [0, 0, 0]
  block[2][0] = [0, 0, 0]
  block[2][4] = [0, 0, 0]
  block[3][1...4].each_index do |i|
    block[3][i + 1] = [0, 0, 0]
  end
  c_color = current_color.write_color
  block[2][1...4].each_index do |i|
    block[2][i + 1] = c_color
  end
  pos_y = 12 * num
  pos_x = 0
  piet_painting[pos_x...(pos_x+12)].each_index do |i|
    piet_painting[pos_x...(pos_x+12)][i][pos_y...(pos_y+5)].each_index do |j|
      piet_painting[pos_x+i][pos_y+j] = block[i][j]
    end
  end
end

# if painting_len < 390
#   # plato_painting = Array.new(12 * painting_len) { Array.new(3, 0) }
#   plato_painting = Array.new(12) { Array.new(painting_len) { Array.new(3, 0) } }
#   plato_painting[0...12].map! { |row| row[0...painting_len] = piet_painting }
#   image = MiniMagick::Image.read(plato_painting.flatten.join("\n"))
#   # image = MiniMagick::Image.new("xc:white")
#   image.format("png")
#   # image.from_array(plato_painting, format: 'rgb')
#   image.write('plato_code.png')
# end
message = 'Let life be beautiful like summer flowers and death like autumn leaves.'
painting_len = message.length * 12 + 5
piet_painting = Array.new(12) { Array.new(painting_len) { Array.new(3, 0) } }
i = 0
message.chars.each_with_index do |char|
  draw_block(piet_painting, current_color, char.ord, i)
  i += 1
end
draw_end(piet_painting, current_color, i)
data = ChunkyPNG::Image.from_rgb_stream(painting_len, 12, piet_painting.flatten.pack('C*'))
data.save('poem.png')
针对上面的代码写个piet编译器 The hard part is obviously reading the images and calculating the transitions, but even that should be a piece of cake with the help of the libraries.