764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
|
# File 'lib/tessel.rb', line 764
def decode(bytes, max_pixels: 16384 * 16384)
bytes = String(bytes).b
raise DecodeError, "invalid BMP" unless bytes.start_with?("BM") && bytes.bytesize >= 54
offset = bytes.byteslice(10, 4).unpack1("L<")
= bytes.byteslice(14, 4).unpack1("L<")
width, height, planes, depth, compression = bytes.byteslice(18, 16).unpack("l<l<S<S<L<")
raise UnsupportedError, "unsupported BMP" unless >= 40 && planes == 1 && [24, 32].include?(depth) && compression.zero?
top_down = height.negative?
height = height.abs
raise DecodeError, "invalid BMP dimensions" unless width.positive? && height.positive?
raise LimitError, "image exceeds pixel limit" if width * height > max_pixels
row_size = ((width * depth + 31) / 32) * 4
raise DecodeError, "truncated BMP pixel data" if offset < 54 || offset + row_size * height > bytes.bytesize
output = "".b
height.times do |row|
source_y = top_down ? row : height - row - 1
data = bytes.byteslice(offset + source_y * row_size, width * depth / 8)
data.bytes.each_slice(depth / 8) { |b, g, r, a| output << [r, g, b, depth == 32 ? a : 255].pack("C4") }
end
Image.from_rgba(width, height, output)
rescue StandardError => e
raise e if e.is_a?(Tessel::Error) || e.is_a?(ArgumentError)
raise DecodeError, "invalid BMP: #{e.message}"
end
|