...

Source file src/golang.org/x/image/bmp/writer.go

Documentation: golang.org/x/image/bmp

     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, opaque bool) error {
    53  	buf := make([]byte, step)
    54  	if opaque {
    55  		for y := dy - 1; y >= 0; y-- {
    56  			min := y*stride + 0
    57  			max := y*stride + dx*4
    58  			off := 0
    59  			for i := min; i < max; i += 4 {
    60  				buf[off+2] = pix[i+0]
    61  				buf[off+1] = pix[i+1]
    62  				buf[off+0] = pix[i+2]
    63  				off += 3
    64  			}
    65  			if _, err := w.Write(buf); err != nil {
    66  				return err
    67  			}
    68  		}
    69  	} else {
    70  		for y := dy - 1; y >= 0; y-- {
    71  			min := y*stride + 0
    72  			max := y*stride + dx*4
    73  			off := 0
    74  			for i := min; i < max; i += 4 {
    75  				a := uint32(pix[i+3])
    76  				if a == 0 {
    77  					buf[off+2] = 0
    78  					buf[off+1] = 0
    79  					buf[off+0] = 0
    80  					buf[off+3] = 0
    81  					off += 4
    82  					continue
    83  				} else if a == 0xff {
    84  					buf[off+2] = pix[i+0]
    85  					buf[off+1] = pix[i+1]
    86  					buf[off+0] = pix[i+2]
    87  					buf[off+3] = 0xff
    88  					off += 4
    89  					continue
    90  				}
    91  				buf[off+2] = uint8(((uint32(pix[i+0]) * 0xffff) / a) >> 8)
    92  				buf[off+1] = uint8(((uint32(pix[i+1]) * 0xffff) / a) >> 8)
    93  				buf[off+0] = uint8(((uint32(pix[i+2]) * 0xffff) / a) >> 8)
    94  				buf[off+3] = uint8(a)
    95  				off += 4
    96  			}
    97  			if _, err := w.Write(buf); err != nil {
    98  				return err
    99  			}
   100  		}
   101  	}
   102  	return nil
   103  }
   104  
   105  func encodeNRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
   106  	buf := make([]byte, step)
   107  	if opaque {
   108  		for y := dy - 1; y >= 0; y-- {
   109  			min := y*stride + 0
   110  			max := y*stride + dx*4
   111  			off := 0
   112  			for i := min; i < max; i += 4 {
   113  				buf[off+2] = pix[i+0]
   114  				buf[off+1] = pix[i+1]
   115  				buf[off+0] = pix[i+2]
   116  				off += 3
   117  			}
   118  			if _, err := w.Write(buf); err != nil {
   119  				return err
   120  			}
   121  		}
   122  	} else {
   123  		for y := dy - 1; y >= 0; y-- {
   124  			min := y*stride + 0
   125  			max := y*stride + dx*4
   126  			off := 0
   127  			for i := min; i < max; i += 4 {
   128  				buf[off+2] = pix[i+0]
   129  				buf[off+1] = pix[i+1]
   130  				buf[off+0] = pix[i+2]
   131  				buf[off+3] = pix[i+3]
   132  				off += 4
   133  			}
   134  			if _, err := w.Write(buf); err != nil {
   135  				return err
   136  			}
   137  		}
   138  	}
   139  	return nil
   140  }
   141  
   142  func encode(w io.Writer, m image.Image, step int) error {
   143  	b := m.Bounds()
   144  	buf := make([]byte, step)
   145  	for y := b.Max.Y - 1; y >= b.Min.Y; y-- {
   146  		off := 0
   147  		for x := b.Min.X; x < b.Max.X; x++ {
   148  			r, g, b, _ := m.At(x, y).RGBA()
   149  			buf[off+2] = byte(r >> 8)
   150  			buf[off+1] = byte(g >> 8)
   151  			buf[off+0] = byte(b >> 8)
   152  			off += 3
   153  		}
   154  		if _, err := w.Write(buf); err != nil {
   155  			return err
   156  		}
   157  	}
   158  	return nil
   159  }
   160  
   161  // Encode writes the image m to w in BMP format.
   162  func Encode(w io.Writer, m image.Image) error {
   163  	d := m.Bounds().Size()
   164  	if d.X < 0 || d.Y < 0 {
   165  		return errors.New("bmp: negative bounds")
   166  	}
   167  	h := &header{
   168  		sigBM:         [2]byte{'B', 'M'},
   169  		fileSize:      14 + 40,
   170  		pixOffset:     14 + 40,
   171  		dibHeaderSize: 40,
   172  		width:         uint32(d.X),
   173  		height:        uint32(d.Y),
   174  		colorPlane:    1,
   175  	}
   176  
   177  	var step int
   178  	var palette []byte
   179  	var opaque bool
   180  	switch m := m.(type) {
   181  	case *image.Gray:
   182  		step = (d.X + 3) &^ 3
   183  		palette = make([]byte, 1024)
   184  		for i := 0; i < 256; i++ {
   185  			palette[i*4+0] = uint8(i)
   186  			palette[i*4+1] = uint8(i)
   187  			palette[i*4+2] = uint8(i)
   188  			palette[i*4+3] = 0xFF
   189  		}
   190  		h.imageSize = uint32(d.Y * step)
   191  		h.fileSize += uint32(len(palette)) + h.imageSize
   192  		h.pixOffset += uint32(len(palette))
   193  		h.bpp = 8
   194  
   195  	case *image.Paletted:
   196  		step = (d.X + 3) &^ 3
   197  		palette = make([]byte, 1024)
   198  		for i := 0; i < len(m.Palette) && i < 256; i++ {
   199  			r, g, b, _ := m.Palette[i].RGBA()
   200  			palette[i*4+0] = uint8(b >> 8)
   201  			palette[i*4+1] = uint8(g >> 8)
   202  			palette[i*4+2] = uint8(r >> 8)
   203  			palette[i*4+3] = 0xFF
   204  		}
   205  		h.imageSize = uint32(d.Y * step)
   206  		h.fileSize += uint32(len(palette)) + h.imageSize
   207  		h.pixOffset += uint32(len(palette))
   208  		h.bpp = 8
   209  	case *image.RGBA:
   210  		opaque = m.Opaque()
   211  		if opaque {
   212  			step = (3*d.X + 3) &^ 3
   213  			h.bpp = 24
   214  		} else {
   215  			step = 4 * d.X
   216  			h.bpp = 32
   217  		}
   218  		h.imageSize = uint32(d.Y * step)
   219  		h.fileSize += h.imageSize
   220  	case *image.NRGBA:
   221  		opaque = m.Opaque()
   222  		if opaque {
   223  			step = (3*d.X + 3) &^ 3
   224  			h.bpp = 24
   225  		} else {
   226  			step = 4 * d.X
   227  			h.bpp = 32
   228  		}
   229  		h.imageSize = uint32(d.Y * step)
   230  		h.fileSize += h.imageSize
   231  	default:
   232  		step = (3*d.X + 3) &^ 3
   233  		h.imageSize = uint32(d.Y * step)
   234  		h.fileSize += h.imageSize
   235  		h.bpp = 24
   236  	}
   237  
   238  	if err := binary.Write(w, binary.LittleEndian, h); err != nil {
   239  		return err
   240  	}
   241  	if palette != nil {
   242  		if err := binary.Write(w, binary.LittleEndian, palette); err != nil {
   243  			return err
   244  		}
   245  	}
   246  
   247  	if d.X == 0 || d.Y == 0 {
   248  		return nil
   249  	}
   250  
   251  	switch m := m.(type) {
   252  	case *image.Gray:
   253  		return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
   254  	case *image.Paletted:
   255  		return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
   256  	case *image.RGBA:
   257  		return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
   258  	case *image.NRGBA:
   259  		return encodeNRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
   260  	}
   261  	return encode(w, m, step)
   262  }
   263  

View as plain text