writer.go 5.7 KB

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