Commit 28cfc4c4 authored by Cool Fire's avatar Cool Fire

Initial commit of file.

parents
#!/usr/bin/env ruby
require 'optparse'
# Option parsing
inputfile = ''
outputfile = ''
width = 0
height = 0
padding = 0
decode = false
ARGV.options do |opts|
opts.separator 'When no filenames are provided STDIO is used'
opts.separator 'When no width is provided a the square root of the input size is used.'
opts.on('-i', '--input=filename', 'Read input from file') { |val| inputfile = val }
opts.on('-o', '--output=filename', 'Write output to file') { |val| outputfile = val }
opts.on('-w', '--width=value', 'Make image "value" pixels wide') { |val| width = val.to_i }
opts.on('-p', '--padding', 'Pad pixel rows with 0-bytes to ensure all data is in pixel values') { padding = 1 }
opts.on('-d', '--decode', 'Decode bmp back to original file') { decode = true }
opts.parse!
end
# Start reading input
data = ''
output = ''
if(inputfile == '')
data = ARGF.read
else
data = IO.binread(inputfile)
end
if(decode)
# Decoding
# Read headers we care about
data = data.bytes
padsize = data[6..7].pack('C*').unpack('S_')[0]
padding = data[8..9].pack('C*').unpack('S_')[0]
width = data[18..21].pack('C*').unpack('I')[0]
# Calculate end of data
dend = data.size - padsize - 1
# Calculate row padding
rowpadsize = (width * 3) % 4
if(rowpadsize > 0)
rowpadsize = 4 - rowpadsize
end
# Decode
if(padding == 1 && rowpadsize != 0)
pc = 0
data[54..-1].pack('C*').each_byte { |b|
pc +=1
if(pc > width * 3)
if(pc == (width * 3) + rowpadsize)
pc = 0
end
next
else
output.concat([b].pack('C*'))
end
}
dend = -1 - padsize
output = output.bytes[0..dend].pack('C*')
else
output = data[54..dend].pack('C*')
end
else
# Encoding
# Add padding if needed
padsize = data.bytesize % 4
if(padsize > 0)
padsize = 4 - padsize
end
data = data.concat([0x00].pack('C*') * padsize)
# Calculate image dimensions
if(width == 0)
width = Math.sqrt(data.bytesize / 3).ceil()
height = width
else
height = ((data.bytesize / 3) / width.to_f).ceil()
end
# Calculate extra bytes required for row padding
rowpadsize = (width * 3) % 4
if(rowpadsize > 0)
rowpadsize = 4 - rowpadsize
end
totalrowpad = 0
if(padding == 1)
totalrowpad = rowpadsize * height
end
# Construct BMP header
bfType = [0x42, 0x4D] # BMP specification type
bfSize = [54 + data.bytesize + totalrowpad] # File size
bfReserved1 = [padsize] # Reserved, always 0 [abused to store number of padding bytes added for alignment]
bfReserved2 = [padding] # Reserved, always 0 [abused to store if extra row padding was used]
bfOffBits = [0x36, 0x00, 0x00, 0x00] # Offset to start of image data
# Construct image header
biSize = [0x28, 0x00, 0x00, 0x00] # Image header size [always 40 bytes here]
biWidth = [width] # Image width in px
biHeight = [height] # Image height in px
biPlanes = [0x01, 0x00] # BMP planes [Always 1]
biBitCount = [0x18, 0x00] # Bits per pixel [Always 24 here]
biCompression = [0x00, 0x00, 0x00, 0x00] # Compression [Always no compression here]
biSizeImage = [0x00, 0x00, 0x00, 0x00] # Image size [May be 0 because no compression is used]
biXPelsPerMeter = [0x13, 0x0B, 0x00, 0x00] # Preferred resolution in pixels per meter
biYPelsPerMeter = [0x13, 0x0B, 0x00, 0x00] # Preferred resolution in pixels per meter
biClrUsed = [0x00, 0x00, 0x00, 0x00] # Number of Color Map entities used [unused here]
biClrImportant = [0x00, 0x00, 0x00, 0x00] # Number of signifcant colors [unused here]
# Print headers
output.concat(bfType.pack('C*'))
output.concat(bfSize.pack('I'))
output.concat(bfReserved1.pack('S_'))
output.concat(bfReserved2.pack('S_'))
output.concat(bfOffBits.pack('C*'))
output.concat(biSize.pack('C*'))
output.concat(biWidth.pack('I'))
output.concat(biHeight.pack('I'))
output.concat(biPlanes.pack('C*'))
output.concat(biBitCount.pack('C*'))
output.concat(biCompression.pack('C*'))
output.concat(biSizeImage.pack('I'))
output.concat(biXPelsPerMeter.pack('C*'))
output.concat(biYPelsPerMeter.pack('C*'))
output.concat(biClrUsed.pack('C*'))
output.concat(biClrImportant.pack('C*'))
# Print content
if(padding == 1)
pc = 0
data.each_byte { |b|
pc += 1
output.concat([b].pack('C*'))
if(pc == width * 3)
output.concat([0x00].pack('C*') * rowpadsize)
pc = 0
end
}
else
output.concat(data)
end
end
# Write out results
if(outputfile == '')
print output
else
IO.binwrite(outputfile, output)
end
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment