Class: Pura::Bmp::Decoder
- Inherits:
-
Object
- Object
- Pura::Bmp::Decoder
- Defined in:
- lib/pura/bmp/decoder.rb
Constant Summary collapse
- BI_RGB =
Compression types
0- BI_RLE8 =
1- BI_RLE4 =
2- BI_BITFIELDS =
3
Class Method Summary collapse
Instance Method Summary collapse
- #decode ⇒ Object
-
#initialize(data) ⇒ Decoder
constructor
A new instance of Decoder.
Constructor Details
#initialize(data) ⇒ Decoder
Returns a new instance of Decoder.
23 24 25 26 |
# File 'lib/pura/bmp/decoder.rb', line 23 def initialize(data) @data = data @pos = 0 end |
Class Method Details
.decode(input) ⇒ Object
14 15 16 17 18 19 20 21 |
# File 'lib/pura/bmp/decoder.rb', line 14 def self.decode(input) data = if input.is_a?(String) && !input.include?("\x00") && input.bytesize < 4096 && File.exist?(input) File.binread(input) else input.b end new(data).decode end |
Instance Method Details
#decode ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/pura/bmp/decoder.rb', line 28 def decode # File header (14 bytes) magic = read_bytes(2) raise DecodeError, "Not a BMP file (missing BM signature)" unless magic == "BM" _file_size = read_uint32_le _reserved1 = read_uint16_le _reserved2 = read_uint16_le pixel_offset = read_uint32_le # Info header header_size = read_uint32_le raise DecodeError, "Unsupported BMP header size: #{header_size}" unless header_size >= 40 width = read_int32_le height = read_int32_le _planes = read_uint16_le bit_depth = read_uint16_le compression = read_uint32_le _image_size = read_uint32_le _x_ppm = read_int32_le _y_ppm = read_int32_le colors_used = read_uint32_le _colors_important = read_uint32_le # Handle negative height (top-down storage) top_down = height.negative? height = height.abs raise DecodeError, "Invalid dimensions: #{width}x#{height}" if width <= 0 || height <= 0 # Read additional header bytes if header is larger than 40 extra_header = header_size - 40 bitfield_masks = nil if compression == BI_BITFIELDS && extra_header >= 12 r_mask = read_uint32_le g_mask = read_uint32_le b_mask = read_uint32_le extra_header -= 12 bitfield_masks = { r: r_mask, g: g_mask, b: b_mask } end skip_bytes(extra_header) if extra_header.positive? # Read color palette for indexed images palette = nil if bit_depth <= 8 num_colors = colors_used.positive? ? colors_used : (1 << bit_depth) palette = read_palette(num_colors) end # Seek to pixel data @pos = pixel_offset # Decode pixel data pixels = case bit_depth when 24 decode_24bit(width, height, top_down) when 32 decode_32bit(width, height, top_down, bitfield_masks) when 8 if compression == BI_RLE8 decode_rle8(width, height, top_down, palette) else decode_8bit(width, height, top_down, palette) end when 4 decode_4bit(width, height, top_down, palette) when 1 decode_1bit(width, height, top_down, palette) else raise DecodeError, "Unsupported bit depth: #{bit_depth}" end Image.new(width, height, pixels) end |