Topic: Converting bitmaps to text

I've got an unusual scripting challenge that I am hoping can be solved by a bit of ruby.. smile

I have a series of large (at least 3000x3000px, could be double or triple that) bitmaps that need to be "dissected", pixel by pixel, and based on a colour key, converted into values (for eventual import into a SQL database).

So I need to get into a CSV or similar file:
- the X & Y pixel coordinate (should be easy enough if I know the exact pixel width of the image)
- the RGB colour value of the pixel and convert (could be one of <50 values) based on a key (this bit can be done later).

IIRC, the bitmap format contains all of these in sets of three values for each pixel anyway - so I don't think it should be too difficult.

Just looking for any tips/pointers to guides, snippets of code or suggestions - not sure where to start with this having never seen anything like it!

Re: Converting bitmaps to text

Sounded really interesting so I gave it a shot, may be useful.
I used the rails forum image as my test - http://railsforum.com/mini_logo.png, so I am not sure if it scales or not.
I also used this page for how to map the data - http://en.wikipedia.org/wiki/BMP_file_format

Here's the code I used:

f = File.new("testbmp.bmp")

# grab the bytes as an array
bytes = f.each_byte.to_a

# based on BMP file format from wikipedia
data_starts_at   = bytes[10]
width_in_pixels  = bytes[18]
height_in_pixels = bytes[22]

pixels = []

# starting at bottom left and completing one row at a time
# byte order is reversed, so colors are BGR instead of RGB
height_in_pixels.times do |row|
  # start with position where data begins and with each row, 
  # increment by width in pixels by 3 bytes for each pixel
  y = data_starts_at + (width_in_pixels * row * 3)

  #skip the last two bytes of data, they are for padding
  col_data = bytes[y..(y + width_in_pixels - 2)]

  # pixels are represented in sets of 3
  # we start with col 0(blue) then ask for 1(green) and 2(red)
  (col_data.size/3).times do |col|
    pixels << {:row => row, :col => col, :blue => col_data[col], :green => col_data[col + 1], :red => col_data[col + 2]}
  end
end

# now you have pixel data and these results should be the same, although I am off by 40 pixels, which is the height of my test, so may not want to subtract 2 pixels per row?
puts width_in_pixels * height_in_pixels
puts pixels.size * 3

Re: Converting bitmaps to text

Actually, this is a bit closer ... the tests at the end should not require the pixels to be multiplied by 3 to come to the same result.  We are dealing with bytes but I mixed in some pixel math along the way ... fixed that here:

f = File.new("testbmp.bmp")
bytes = f.each_byte.to_a
data_starts_at   = bytes[10]
width_in_pixels  = bytes[18]
height_in_pixels = bytes[22]

pixels = []

# starting at bottom left and completing one row at a time
# byte order is reversed, so colors are BGR instead of RGB
height_in_pixels.times do |row|
  # pixels * 3 bytes per pixel + the 2 bytes at the end of each row
  bytes_per_row = width_in_pixels * 3 + 2

  # start with position where data begins and with each row, 
  # increment by width in pixels by 3 bytes for each pixel
  y = data_starts_at + (bytes_per_row * row)

  #skip the last two bytes of data, they are for padding
  col_data = bytes[y..(y + bytes_per_row - 2)]        

  # pixels are represented in sets of 3
  # we start with col 0(blue) then ask for 1(green) and 2(red)
  (col_data.size/3).times do |col|
    pixels << {:row => row, :col => col, :blue => col_data[col], :green => col_data[col + 1], :red => col_data[col + 2]}
  end
end

# now you have pixel data and these results should be the same, although I am off by 26 pixels
puts width_in_pixels * height_in_pixels
puts pixels.size

Re: Converting bitmaps to text

Oh wow, thanks a heap for that! Off to have a play with it now.. smile

Re: Converting bitmaps to text

Wow, when I first looked at his original question, my head started spinning just thinking about it.

You got some mad skills pullmonkey! tongue