module SimpleBMP

Currently there are no need of classes – just a single public module method.

Export only to BITMAPCOREHEADER (12 bytes), because it’s enough. Import BITMAPCOREHEADER and 24bpp BITMAPINFOHEADER because MS Paint uses it.

Public Class Methods

enlarge(array, **args) click to toggle source

Truncated box modal resizing

# File lib/simple_bmp.rb, line 74
def self.enlarge array, **args
    array = array.flat_map{ |row| [ row.flat_map{ |cell| [cell] * args[:times] } ] * args[:times] }
end
export(pixels, filename = "temp.bmp") click to toggle source

+pixels+ is either two or three dimensional array:

[height x width x 3] of 0..255 for RGB
[height x width] of 0..255 for grayscale

Two-dimensional will be processed as it’s three, where R, G anb B are equal.

Examples of exporting a single pixel image which is almost gray:

export [[100]], "temp.bmp"
export [[[90,100,110]]], "temp.bmp"
# File lib/simple_bmp.rb, line 19
def self.export pixels, filename = "temp.bmp"
    #fail "pixel array shouldn't be empty" if pixels.empty?
    fail "all pixel array rows should be of the same length" if pixels.map(&:size).uniq.size != 1
    bitmap_width = pixels.first.size
    bitmap_height = pixels.size
    pixel_array = pixels.reverse.flat_map do |row|
        # row_bytes = row.map(&hsv2bgr).flatten
        row_bytes = row.flat_map{ |pixel| pixel.is_a?(Array) ? pixel.reverse : [pixel]*3 }
        row_bytes.fill 0, row_bytes.size .. @@align4[row_bytes.size] - 1
    end

    # 12=>BITMAPCOREHEADER, 40=>BITMAPINFOHEADER
    dib_header_size = 12
    file_size = 14 + dib_header_size + pixel_array.size

    open(filename, "wb") do |file|
        # Bitmap file header
        file.write ["BM", file_size, 14 + dib_header_size].pack "A2qi" # "A2QL"
        # DIB header
        # file.write [dib_header_size, bitmap_width, bitmap_height, 1, 24].pack "LllSS"
        # file.write [0, 0, 1, 1, 0, 0].pack "LLllLL" # BITMAPINFOHEADER
        file.write [dib_header_size, bitmap_width, bitmap_height, 1, 24].pack "LSSSS"
        file.write pixel_array.pack "C*"
    end
end
import(filename = "temp.bmp") click to toggle source

This imports BITMAPCOREHEADER and 24bpp BITMAPINFOHEADER headed RGB bmp images returning a 3-dimentional array.

# File lib/simple_bmp.rb, line 47
def self.import filename = "temp.bmp"
    File.open(filename, "rb") do |file|
        _, _, shift = file.read(14).unpack("A2qi")
        dib_header_size, = file.read(4).unpack("L")
        case dib_header_size
            when 12 ; bitmap_width, bitmap_height = file.read(4).unpack("SS")
            when 40 ; bitmap_width, bitmap_height = file.read(8).unpack("ii")
            else ; fail "can import only BITMAPCOREHEADER (12 bytes) and 24bpp BITMAPINFOHEADER (40 bytes)"
        end
        file.pos = shift
        (file.read(bitmap_height * @@align4[bitmap_width * 3]).unpack("C*")).
                each_slice(@@align4[bitmap_width * 3]).map do |row|
            row.each_slice(3).take(bitmap_width).map(&:reverse)
        end.reverse
    end
end
reduce(array, **args) click to toggle source

Truncated box modal resizing

# File lib/simple_bmp.rb, line 65
def self.reduce array, **args
    array = array.each_slice(args[:times]).take(array.size/args[:times]).map{ |rows|
        rows.transpose.each_slice(args[:times]).take(array.first.size/args[:times]).map{ |cells|
            cells.flatten(1).group_by{ |i| i }.sort_by{ |i,g| g.size }.last.first
        }
    }
end