Module: Emfsvg::DibEncoder

Defined in:
lib/emfsvg/dib_encoder.rb

Overview

Encode RGBA pixels + dimensions to Windows DIB (BITMAPINFOHEADER + pixel array) suitable for embedding in EMR_STRETCHDIBITS and related records. The inverse of emfsvg's DibDecoder.

Output layout (BI_RGB, 32-bpp, bottom-up):

* BITMAPINFOHEADER (40 bytes)
* pixel array (BGRA per pixel, row-major from bottom to top)

Constant Summary collapse

BITMAPINFOHEADER_SIZE =
40
BI_RGB =
0

Class Method Summary collapse

Class Method Details

.bgra_pixel_array(width, height, rgba_bytes) ⇒ Object

Convert RGBA → BGRA (the byte order DIB expects), keeping the bottom-up row order (rows reversed).



45
46
47
48
49
50
51
52
53
54
# File 'lib/emfsvg/dib_encoder.rb', line 45

def bgra_pixel_array(width, height, rgba_bytes)
  row_size = width * 4
  out = String.new capacity: width * height * 4
  (0...height).to_a.reverse_each do |src_row|
    row_start = src_row * row_size
    row_bytes = rgba_bytes.byteslice(row_start, row_size)
    out << swap_rb_in_row(row_bytes)
  end
  out
end

.build_header(width, height) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/emfsvg/dib_encoder.rb', line 26

def build_header(width, height)
  pixel_bytes = width * height * 4
  [
    BITMAPINFOHEADER_SIZE, # biSize  (uint32)
    width,                            # biWidth (int32)
    height,                           # biHeight (int32, positive = bottom-up)
    1,                                # biPlanes (uint16)
    32,                               # biBitCount (uint16)
    BI_RGB,                           # biCompression (uint32)
    pixel_bytes,                      # biSizeImage (uint32)
    2835,                             # biXPelsPerMeter (~72 DPI)
    2835,                             # biYPelsPerMeter
    0,                                # biClrUsed
    0                                 # biClrImportant
  ].pack("Vl<l<vvVVVVVV")
end

.encode(width, height, rgba_bytes) ⇒ Object



17
18
19
20
21
22
23
24
# File 'lib/emfsvg/dib_encoder.rb', line 17

def encode(width, height, rgba_bytes)
  return "" if width <= 0 || height <= 0
  return "" if rgba_bytes.nil? || rgba_bytes.bytesize < (width * height * 4)

  header = build_header(width, height)
  pixels = bgra_pixel_array(width, height, rgba_bytes)
  header + pixels
end

.swap_rb_in_row(row_bytes) ⇒ Object



56
57
58
59
60
61
62
63
64
65
# File 'lib/emfsvg/dib_encoder.rb', line 56

def swap_rb_in_row(row_bytes)
  bytes = row_bytes.dup
  (0...bytes.bytesize).step(4).each do |i|
    r = bytes.getbyte(i)
    b = bytes.getbyte(i + 2)
    bytes.setbyte(i, b)
    bytes.setbyte(i + 2, r)
  end
  bytes
end