clone.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package imaging
  2. import (
  3. "image"
  4. "image/color"
  5. )
  6. // Clone returns a copy of the given image.
  7. func Clone(img image.Image) *image.NRGBA {
  8. dstBounds := img.Bounds().Sub(img.Bounds().Min)
  9. dst := image.NewNRGBA(dstBounds)
  10. switch src := img.(type) {
  11. case *image.NRGBA:
  12. copyNRGBA(dst, src)
  13. case *image.NRGBA64:
  14. copyNRGBA64(dst, src)
  15. case *image.RGBA:
  16. copyRGBA(dst, src)
  17. case *image.RGBA64:
  18. copyRGBA64(dst, src)
  19. case *image.Gray:
  20. copyGray(dst, src)
  21. case *image.Gray16:
  22. copyGray16(dst, src)
  23. case *image.YCbCr:
  24. copyYCbCr(dst, src)
  25. case *image.Paletted:
  26. copyPaletted(dst, src)
  27. default:
  28. copyImage(dst, src)
  29. }
  30. return dst
  31. }
  32. func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
  33. srcMinX := src.Rect.Min.X
  34. srcMinY := src.Rect.Min.Y
  35. dstW := dst.Rect.Dx()
  36. dstH := dst.Rect.Dy()
  37. rowSize := dstW * 4
  38. parallel(dstH, func(partStart, partEnd int) {
  39. for dstY := partStart; dstY < partEnd; dstY++ {
  40. di := dst.PixOffset(0, dstY)
  41. si := src.PixOffset(srcMinX, srcMinY+dstY)
  42. copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
  43. }
  44. })
  45. }
  46. func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
  47. srcMinX := src.Rect.Min.X
  48. srcMinY := src.Rect.Min.Y
  49. dstW := dst.Rect.Dx()
  50. dstH := dst.Rect.Dy()
  51. parallel(dstH, func(partStart, partEnd int) {
  52. for dstY := partStart; dstY < partEnd; dstY++ {
  53. di := dst.PixOffset(0, dstY)
  54. si := src.PixOffset(srcMinX, srcMinY+dstY)
  55. for dstX := 0; dstX < dstW; dstX++ {
  56. dst.Pix[di+0] = src.Pix[si+0]
  57. dst.Pix[di+1] = src.Pix[si+2]
  58. dst.Pix[di+2] = src.Pix[si+4]
  59. dst.Pix[di+3] = src.Pix[si+6]
  60. di += 4
  61. si += 8
  62. }
  63. }
  64. })
  65. }
  66. func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
  67. srcMinX := src.Rect.Min.X
  68. srcMinY := src.Rect.Min.Y
  69. dstW := dst.Rect.Dx()
  70. dstH := dst.Rect.Dy()
  71. parallel(dstH, func(partStart, partEnd int) {
  72. for dstY := partStart; dstY < partEnd; dstY++ {
  73. di := dst.PixOffset(0, dstY)
  74. si := src.PixOffset(srcMinX, srcMinY+dstY)
  75. for dstX := 0; dstX < dstW; dstX++ {
  76. a := src.Pix[si+3]
  77. dst.Pix[di+3] = a
  78. switch a {
  79. case 0:
  80. dst.Pix[di+0] = 0
  81. dst.Pix[di+1] = 0
  82. dst.Pix[di+2] = 0
  83. case 0xff:
  84. dst.Pix[di+0] = src.Pix[si+0]
  85. dst.Pix[di+1] = src.Pix[si+1]
  86. dst.Pix[di+2] = src.Pix[si+2]
  87. default:
  88. var tmp uint16
  89. tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
  90. dst.Pix[di+0] = uint8(tmp)
  91. tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
  92. dst.Pix[di+1] = uint8(tmp)
  93. tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
  94. dst.Pix[di+2] = uint8(tmp)
  95. }
  96. di += 4
  97. si += 4
  98. }
  99. }
  100. })
  101. }
  102. func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
  103. srcMinX := src.Rect.Min.X
  104. srcMinY := src.Rect.Min.Y
  105. dstW := dst.Rect.Dx()
  106. dstH := dst.Rect.Dy()
  107. parallel(dstH, func(partStart, partEnd int) {
  108. for dstY := partStart; dstY < partEnd; dstY++ {
  109. di := dst.PixOffset(0, dstY)
  110. si := src.PixOffset(srcMinX, srcMinY+dstY)
  111. for dstX := 0; dstX < dstW; dstX++ {
  112. a := src.Pix[si+6]
  113. dst.Pix[di+3] = a
  114. switch a {
  115. case 0:
  116. dst.Pix[di+0] = 0
  117. dst.Pix[di+1] = 0
  118. dst.Pix[di+2] = 0
  119. case 0xff:
  120. dst.Pix[di+0] = src.Pix[si+0]
  121. dst.Pix[di+1] = src.Pix[si+2]
  122. dst.Pix[di+2] = src.Pix[si+4]
  123. default:
  124. var tmp uint16
  125. tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
  126. dst.Pix[di+0] = uint8(tmp)
  127. tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
  128. dst.Pix[di+1] = uint8(tmp)
  129. tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
  130. dst.Pix[di+2] = uint8(tmp)
  131. }
  132. di += 4
  133. si += 8
  134. }
  135. }
  136. })
  137. }
  138. func copyGray(dst *image.NRGBA, src *image.Gray) {
  139. srcMinX := src.Rect.Min.X
  140. srcMinY := src.Rect.Min.Y
  141. dstW := dst.Rect.Dx()
  142. dstH := dst.Rect.Dy()
  143. parallel(dstH, func(partStart, partEnd int) {
  144. for dstY := partStart; dstY < partEnd; dstY++ {
  145. di := dst.PixOffset(0, dstY)
  146. si := src.PixOffset(srcMinX, srcMinY+dstY)
  147. for dstX := 0; dstX < dstW; dstX++ {
  148. c := src.Pix[si]
  149. dst.Pix[di+0] = c
  150. dst.Pix[di+1] = c
  151. dst.Pix[di+2] = c
  152. dst.Pix[di+3] = 0xff
  153. di += 4
  154. si++
  155. }
  156. }
  157. })
  158. }
  159. func copyGray16(dst *image.NRGBA, src *image.Gray16) {
  160. srcMinX := src.Rect.Min.X
  161. srcMinY := src.Rect.Min.Y
  162. dstW := dst.Rect.Dx()
  163. dstH := dst.Rect.Dy()
  164. parallel(dstH, func(partStart, partEnd int) {
  165. for dstY := partStart; dstY < partEnd; dstY++ {
  166. di := dst.PixOffset(0, dstY)
  167. si := src.PixOffset(srcMinX, srcMinY+dstY)
  168. for dstX := 0; dstX < dstW; dstX++ {
  169. c := src.Pix[si]
  170. dst.Pix[di+0] = c
  171. dst.Pix[di+1] = c
  172. dst.Pix[di+2] = c
  173. dst.Pix[di+3] = 0xff
  174. di += 4
  175. si += 2
  176. }
  177. }
  178. })
  179. }
  180. func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
  181. srcMinX := src.Rect.Min.X
  182. srcMinY := src.Rect.Min.Y
  183. dstW := dst.Rect.Dx()
  184. dstH := dst.Rect.Dy()
  185. parallel(dstH, func(partStart, partEnd int) {
  186. for dstY := partStart; dstY < partEnd; dstY++ {
  187. di := dst.PixOffset(0, dstY)
  188. for dstX := 0; dstX < dstW; dstX++ {
  189. srcX := srcMinX + dstX
  190. srcY := srcMinY + dstY
  191. siy := src.YOffset(srcX, srcY)
  192. sic := src.COffset(srcX, srcY)
  193. r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
  194. dst.Pix[di+0] = r
  195. dst.Pix[di+1] = g
  196. dst.Pix[di+2] = b
  197. dst.Pix[di+3] = 0xff
  198. di += 4
  199. }
  200. }
  201. })
  202. }
  203. func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
  204. srcMinX := src.Rect.Min.X
  205. srcMinY := src.Rect.Min.Y
  206. dstW := dst.Rect.Dx()
  207. dstH := dst.Rect.Dy()
  208. plen := len(src.Palette)
  209. pnew := make([]color.NRGBA, plen)
  210. for i := 0; i < plen; i++ {
  211. pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
  212. }
  213. parallel(dstH, func(partStart, partEnd int) {
  214. for dstY := partStart; dstY < partEnd; dstY++ {
  215. di := dst.PixOffset(0, dstY)
  216. si := src.PixOffset(srcMinX, srcMinY+dstY)
  217. for dstX := 0; dstX < dstW; dstX++ {
  218. c := pnew[src.Pix[si]]
  219. dst.Pix[di+0] = c.R
  220. dst.Pix[di+1] = c.G
  221. dst.Pix[di+2] = c.B
  222. dst.Pix[di+3] = c.A
  223. di += 4
  224. si++
  225. }
  226. }
  227. })
  228. }
  229. func copyImage(dst *image.NRGBA, src image.Image) {
  230. srcMinX := src.Bounds().Min.X
  231. srcMinY := src.Bounds().Min.Y
  232. dstW := dst.Bounds().Dx()
  233. dstH := dst.Bounds().Dy()
  234. parallel(dstH, func(partStart, partEnd int) {
  235. for dstY := partStart; dstY < partEnd; dstY++ {
  236. di := dst.PixOffset(0, dstY)
  237. for dstX := 0; dstX < dstW; dstX++ {
  238. c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
  239. dst.Pix[di+0] = c.R
  240. dst.Pix[di+1] = c.G
  241. dst.Pix[di+2] = c.B
  242. dst.Pix[di+3] = c.A
  243. di += 4
  244. }
  245. }
  246. })
  247. }
  248. // toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
  249. func toNRGBA(img image.Image) *image.NRGBA {
  250. if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
  251. return img
  252. }
  253. return Clone(img)
  254. }