gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

writer.go (5818B)


      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 }