clone.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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. srcY := srcMinY + dstY
  188. di := dst.PixOffset(0, dstY)
  189. for dstX := 0; dstX < dstW; dstX++ {
  190. srcX := srcMinX + dstX
  191. siy := (srcY-srcMinY)*src.YStride + (srcX - srcMinX)
  192. var sic int
  193. switch src.SubsampleRatio {
  194. case image.YCbCrSubsampleRatio444:
  195. sic = (srcY-srcMinY)*src.CStride + (srcX - srcMinX)
  196. case image.YCbCrSubsampleRatio422:
  197. sic = (srcY-srcMinY)*src.CStride + (srcX/2 - srcMinX/2)
  198. case image.YCbCrSubsampleRatio420:
  199. sic = (srcY/2-srcMinY/2)*src.CStride + (srcX/2 - srcMinX/2)
  200. case image.YCbCrSubsampleRatio440:
  201. sic = (srcY/2-srcMinY/2)*src.CStride + (srcX - srcMinX)
  202. default:
  203. sic = src.COffset(srcX, srcY)
  204. }
  205. y := int32(src.Y[siy])
  206. cb := int32(src.Cb[sic]) - 128
  207. cr := int32(src.Cr[sic]) - 128
  208. r := (y<<16 + 91881*cr + 1<<15) >> 16
  209. if r > 255 {
  210. r = 255
  211. } else if r < 0 {
  212. r = 0
  213. }
  214. g := (y<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
  215. if g > 255 {
  216. g = 255
  217. } else if g < 0 {
  218. g = 0
  219. }
  220. b := (y<<16 + 116130*cb + 1<<15) >> 16
  221. if b > 255 {
  222. b = 255
  223. } else if b < 0 {
  224. b = 0
  225. }
  226. dst.Pix[di+0] = uint8(r)
  227. dst.Pix[di+1] = uint8(g)
  228. dst.Pix[di+2] = uint8(b)
  229. dst.Pix[di+3] = 255
  230. di += 4
  231. }
  232. }
  233. })
  234. }
  235. func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
  236. srcMinX := src.Rect.Min.X
  237. srcMinY := src.Rect.Min.Y
  238. dstW := dst.Rect.Dx()
  239. dstH := dst.Rect.Dy()
  240. plen := len(src.Palette)
  241. pnew := make([]color.NRGBA, plen)
  242. for i := 0; i < plen; i++ {
  243. pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
  244. }
  245. parallel(dstH, func(partStart, partEnd int) {
  246. for dstY := partStart; dstY < partEnd; dstY++ {
  247. di := dst.PixOffset(0, dstY)
  248. si := src.PixOffset(srcMinX, srcMinY+dstY)
  249. for dstX := 0; dstX < dstW; dstX++ {
  250. c := pnew[src.Pix[si]]
  251. dst.Pix[di+0] = c.R
  252. dst.Pix[di+1] = c.G
  253. dst.Pix[di+2] = c.B
  254. dst.Pix[di+3] = c.A
  255. di += 4
  256. si++
  257. }
  258. }
  259. })
  260. }
  261. func copyImage(dst *image.NRGBA, src image.Image) {
  262. srcMinX := src.Bounds().Min.X
  263. srcMinY := src.Bounds().Min.Y
  264. dstW := dst.Bounds().Dx()
  265. dstH := dst.Bounds().Dy()
  266. parallel(dstH, func(partStart, partEnd int) {
  267. for dstY := partStart; dstY < partEnd; dstY++ {
  268. di := dst.PixOffset(0, dstY)
  269. for dstX := 0; dstX < dstW; dstX++ {
  270. c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
  271. dst.Pix[di+0] = c.R
  272. dst.Pix[di+1] = c.G
  273. dst.Pix[di+2] = c.B
  274. dst.Pix[di+3] = c.A
  275. di += 4
  276. }
  277. }
  278. })
  279. }
  280. // toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
  281. func toNRGBA(img image.Image) *image.NRGBA {
  282. if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
  283. return img
  284. }
  285. return Clone(img)
  286. }