github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/image/bmp/writer.go (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bmp
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"image"
    11  	"io"
    12  )
    13  
    14  type header struct {
    15  	sigBM           [2]byte
    16  	fileSize        uint32
    17  	resverved       [2]uint16
    18  	pixOffset       uint32
    19  	dibHeaderSize   uint32
    20  	width           uint32
    21  	height          uint32
    22  	colorPlane      uint16
    23  	bpp             uint16
    24  	compression     uint32
    25  	imageSize       uint32
    26  	xPixelsPerMeter uint32
    27  	yPixelsPerMeter uint32
    28  	colorUse        uint32
    29  	colorImportant  uint32
    30  }
    31  
    32  func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
    33  	var padding []byte
    34  	if dx < step {
    35  		padding = make([]byte, step-dx)
    36  	}
    37  	for y := dy - 1; y >= 0; y-- {
    38  		min := y*stride + 0
    39  		max := y*stride + dx
    40  		if _, err := w.Write(pix[min:max]); err != nil {
    41  			return err
    42  		}
    43  		if padding != nil {
    44  			if _, err := w.Write(padding); err != nil {
    45  				return err
    46  			}
    47  		}
    48  	}
    49  	return nil
    50  }
    51  
    52  func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
    53  	buf := make([]byte, step)
    54  	for y := dy - 1; y >= 0; y-- {
    55  		min := y*stride + 0
    56  		max := y*stride + dx*4
    57  		off := 0
    58  		for i := min; i < max; i += 4 {
    59  			buf[off+2] = pix[i+0]
    60  			buf[off+1] = pix[i+1]
    61  			buf[off+0] = pix[i+2]
    62  			off += 3
    63  		}
    64  		if _, err := w.Write(buf); err != nil {
    65  			return err
    66  		}
    67  	}
    68  	return nil
    69  }
    70  
    71  func encode(w io.Writer, m image.Image, step int) error {
    72  	b := m.Bounds()
    73  	buf := make([]byte, step)
    74  	for y := b.Max.Y - 1; y >= b.Min.Y; y-- {
    75  		off := 0
    76  		for x := b.Min.X; x < b.Max.X; x++ {
    77  			r, g, b, _ := m.At(x, y).RGBA()
    78  			buf[off+2] = byte(r >> 8)
    79  			buf[off+1] = byte(g >> 8)
    80  			buf[off+0] = byte(b >> 8)
    81  			off += 3
    82  		}
    83  		if _, err := w.Write(buf); err != nil {
    84  			return err
    85  		}
    86  	}
    87  	return nil
    88  }
    89  
    90  // Encode writes the image m to w in BMP format.
    91  func Encode(w io.Writer, m image.Image) error {
    92  	d := m.Bounds().Size()
    93  	if d.X < 0 || d.Y < 0 {
    94  		return errors.New("bmp: negative bounds")
    95  	}
    96  	h := &header{
    97  		sigBM:         [2]byte{'B', 'M'},
    98  		fileSize:      14 + 40,
    99  		pixOffset:     14 + 40,
   100  		dibHeaderSize: 40,
   101  		width:         uint32(d.X),
   102  		height:        uint32(d.Y),
   103  		colorPlane:    1,
   104  	}
   105  
   106  	var step int
   107  	var palette []byte
   108  	switch m := m.(type) {
   109  	case *image.Gray:
   110  		step = (d.X + 3) &^ 3
   111  		palette = make([]byte, 1024)
   112  		for i := 0; i < 256; i++ {
   113  			palette[i*4+0] = uint8(i)
   114  			palette[i*4+1] = uint8(i)
   115  			palette[i*4+2] = uint8(i)
   116  			palette[i*4+3] = 0xFF
   117  		}
   118  		h.imageSize = uint32(d.Y * step)
   119  		h.fileSize += uint32(len(palette)) + h.imageSize
   120  		h.pixOffset += uint32(len(palette))
   121  		h.bpp = 8
   122  
   123  	case *image.Paletted:
   124  		step = (d.X + 3) &^ 3
   125  		palette = make([]byte, 1024)
   126  		for i := 0; i < len(m.Palette) && i < 256; i++ {
   127  			r, g, b, _ := m.Palette[i].RGBA()
   128  			palette[i*4+0] = uint8(b >> 8)
   129  			palette[i*4+1] = uint8(g >> 8)
   130  			palette[i*4+2] = uint8(r >> 8)
   131  			palette[i*4+3] = 0xFF
   132  		}
   133  		h.imageSize = uint32(d.Y * step)
   134  		h.fileSize += uint32(len(palette)) + h.imageSize
   135  		h.pixOffset += uint32(len(palette))
   136  		h.bpp = 8
   137  	default:
   138  		step = (3*d.X + 3) &^ 3
   139  		h.imageSize = uint32(d.Y * step)
   140  		h.fileSize += h.imageSize
   141  		h.bpp = 24
   142  	}
   143  
   144  	if err := binary.Write(w, binary.LittleEndian, h); err != nil {
   145  		return err
   146  	}
   147  	if palette != nil {
   148  		if err := binary.Write(w, binary.LittleEndian, palette); err != nil {
   149  			return err
   150  		}
   151  	}
   152  
   153  	if d.X == 0 || d.Y == 0 {
   154  		return nil
   155  	}
   156  
   157  	switch m := m.(type) {
   158  	case *image.Gray:
   159  		return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
   160  	case *image.Paletted:
   161  		return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
   162  	case *image.RGBA:
   163  		return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step)
   164  	}
   165  	return encode(w, m, step)
   166  }