class DiscreetProxy::Proxy

This class represents a proxy.

Attributes

height[R]

Image dimensions, standard is 126x92

rows[R]

Array of rows with each row being an array of packed color integers (you can unpack them with ChunkyPNG::Color)

width[R]

Image dimensions, standard is 126x92

Public Class Methods

new(w = DEFAULT_WIDTH, h = DEFAULT_HEIGHT) click to toggle source
# File lib/discreet_proxy.rb, line 57
def initialize(w = DEFAULT_WIDTH, h = DEFAULT_HEIGHT)
  @width, @height = w.to_i, h.to_i
  # Blank out the pixel values with black
  generate_black
end

Public Instance Methods

[](left, top) click to toggle source

Get an array of the [r,g,b] pixel values at the specific coordinate

# File lib/discreet_proxy.rb, line 75
def [](left, top)
  png_color_int = @rows[top][left]
  unpack_rgb(png_color_int)
end
[]=(x, y, *rgb) click to toggle source

Set the color value at the specific coordinate. If the passed value is a single integer, it gets interpreted as a PNG color value. If a triplet array with three components is passed it's interpreted as RGB

# File lib/discreet_proxy.rb, line 83
def []=(x, y, *rgb)
  color = rgb.flatten
  
  # Check for raw pixel value
  if color.length == 1 && color[0].is_a?(Numeric)
    @rows[y][x] = color[0]
  else
    r, g, b = color.map{|e| e.to_i }
    @rows[y][x] = pack_rgb(r, g ,b)
  end
end
fill_pixbuf(io) click to toggle source

Once the proxy metadata is known, this method can parse out the actual pixel data from the passed IO

# File lib/discreet_proxy.rb, line 119
def fill_pixbuf(io)
  @rows = []
  
  # Data comes in row per row, starting on bottom left because of endianness
  per_row = (@width.to_i + row_pad) * 3
  total_size = ((per_row + row_pad) * @height) + 1
  blob = StringIO.new(io.read(total_size))
  
  @height.times do
    row = []
    row_data = blob.read(@width.to_i * 3)
    row_data = StringIO.new(row_data.to_s)
    
    # Read 3x8bit for each pixel
    @width.times do
      rgb = (row_data.read(3) || "AAA").unpack("CCC")
      row.push(pack_rgb(*rgb))
    end
    
    # At the end of each row (thus at the beginning byteswap),
    # 2 bytes contain garbage since rows are aligned
    # to start at 8-complement byte offsets. If they are not discarded this disturbs
    # the RGB cadence of the other values.
    blob.seek(blob.pos + row_pad)
    
    # Since the file is actually BE, the rows are ordered top to bottom in the file
    @rows.unshift(row)
  end
end
save(filename) click to toggle source

Save out the .p file

# File lib/discreet_proxy.rb, line 150
def save(filename)
  File.open(filename, 'wb') { |io| io.write(to_dotp) }
end
save_png(filename) click to toggle source

Save out the PNG version of the file

# File lib/discreet_proxy.rb, line 155
def save_png(filename)
  to_png.save(filename)
end
to_dotp() click to toggle source

Compose a string with the entire contents of a proxy file

# File lib/discreet_proxy.rb, line 96
def to_dotp
  # Pack the header
  buf = StringIO.new(0xFF.chr * 40)
  byteswap_version = [PROXY_VERSION].pack("e").reverse
  header = [MAGIC, VERSION_BSWAP, width, height, PROXY_DEPTH].pack("na6nnn")
  buf.write(header)
  buf.seek(40)
  
  # Write out all the rows starting with the last one
  @rows.reverse.each do | row |
    row.each do | pix |
      rgb = unpack_rgb(pix).pack("CCC")
      buf.write(rgb) 
    end
    # Then write the padding
    buf.write(0x00.chr * row_pad)
  end
  
  buf.string
end
to_png() click to toggle source
# File lib/discreet_proxy.rb, line 63
def to_png
  png = ChunkyPNG::Image.new(@width, @height)
  png.metadata["Software"] = "Ruby DiscreetProxy converter/chunky_png"
  @rows.each_with_index do | row, y |
    png.replace_row!(y, row)
  end
  # Bump it to the default icon size
  png.resample_bilinear!(DEFAULT_WIDTH, DEFAULT_HEIGHT)
  png
end

Private Instance Methods

generate_black() click to toggle source
# File lib/discreet_proxy.rb, line 175
def generate_black
  @rows = []
  row = [0] * @width
  @height.times{ @rows.push(row.dup) }
end
pack_rgb(r,g,b) click to toggle source
# File lib/discreet_proxy.rb, line 167
def pack_rgb(r,g,b)
  ChunkyPNG::Color.rgb(r.to_i, g.to_i, b.to_i)
end
row_pad() click to toggle source

Rows start at 8-byte aligned boundaries. BUT due to the fact that this is a BDSM Silicon Graphics format the start of the row is END of the image.

# File lib/discreet_proxy.rb, line 163
def row_pad
  @row_pad ||= ((@width * 3) % 8)
end
unpack_rgb(rgb) click to toggle source
# File lib/discreet_proxy.rb, line 171
def unpack_rgb(rgb)
  [ChunkyPNG::Color.r(rgb), ChunkyPNG::Color.g(rgb), ChunkyPNG::Color.b(rgb)]
end