PageRenderTime 86ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/old-version/toropress-qbs-version-1st/helper/resize.go

https://gitlab.com/1851616111/toropress
Go | 252 lines | 188 code | 6 blank | 58 comment | 41 complexity | 11e384dcd4680b1502bee35367c3921b MD5 | raw file
  1. package helper
  2. import (
  3. "image"
  4. "image/color"
  5. )
  6. //调整传回的图像片的R米的缩放副本。
  7. //返回的图像具有宽度w和高度h。
  8. // Resize returns a scaled copy of the image slice r of m.
  9. // The returned image has width w and height h.
  10. func Resize(m image.Image, r image.Rectangle, w, h int) image.Image {
  11. if w < 0 || h < 0 {
  12. return nil
  13. }
  14. if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {
  15. return image.NewRGBA64(image.Rect(0, 0, w, h))
  16. }
  17. switch m := m.(type) {
  18. case *image.RGBA:
  19. return resizeRGBA(m, r, w, h)
  20. case *image.YCbCr:
  21. if m, ok := resizeYCbCr(m, r, w, h); ok {
  22. return m
  23. }
  24. }
  25. ww, hh := uint64(w), uint64(h)
  26. dx, dy := uint64(r.Dx()), uint64(r.Dy())
  27. // The scaling algorithm is to nearest-neighbor magnify the dx * dy source
  28. // to a (ww*dx) * (hh*dy) intermediate image and then minify the intermediate
  29. // image back down to a ww * hh destination with a simple box filter.
  30. // The intermediate image is implied, we do not physically allocate a slice
  31. // of length ww*dx*hh*dy.
  32. // For example, consider a 4*3 source image. Label its pixels from a-l:
  33. // abcd
  34. // efgh
  35. // ijkl
  36. // To resize this to a 3*2 destination image, the intermediate is 12*6.
  37. // Whitespace has been added to delineate the destination pixels:
  38. // aaab bbcc cddd
  39. // aaab bbcc cddd
  40. // eeef ffgg ghhh
  41. //
  42. // eeef ffgg ghhh
  43. // iiij jjkk klll
  44. // iiij jjkk klll
  45. // Thus, the 'b' source pixel contributes one third of its value to the
  46. // (0, 0) destination pixel and two thirds to (1, 0).
  47. // The implementation is a two-step process. First, the source pixels are
  48. // iterated over and each source pixel's contribution to 1 or more
  49. // destination pixels are summed. Second, the sums are divided by a scaling
  50. // factor to yield the destination pixels.
  51. // TODO: By interleaving the two steps, instead of doing all of
  52. // step 1 first and all of step 2 second, we could allocate a smaller sum
  53. // slice of length 4*w*2 instead of 4*w*h, although the resultant code
  54. // would become more complicated.
  55. n, sum := dx*dy, make([]uint64, 4*w*h)
  56. for y := r.Min.Y; y < r.Max.Y; y++ {
  57. for x := r.Min.X; x < r.Max.X; x++ {
  58. // Get the source pixel.
  59. r32, g32, b32, a32 := m.At(x, y).RGBA()
  60. r64 := uint64(r32)
  61. g64 := uint64(g32)
  62. b64 := uint64(b32)
  63. a64 := uint64(a32)
  64. // Spread the source pixel over 1 or more destination rows.
  65. py := uint64(y) * hh
  66. for remy := hh; remy > 0; {
  67. qy := dy - (py % dy)
  68. if qy > remy {
  69. qy = remy
  70. }
  71. // Spread the source pixel over 1 or more destination columns.
  72. px := uint64(x) * ww
  73. index := 4 * ((py/dy)*ww + (px / dx))
  74. for remx := ww; remx > 0; {
  75. qx := dx - (px % dx)
  76. if qx > remx {
  77. qx = remx
  78. }
  79. sum[index+0] += r64 * qx * qy
  80. sum[index+1] += g64 * qx * qy
  81. sum[index+2] += b64 * qx * qy
  82. sum[index+3] += a64 * qx * qy
  83. index += 4
  84. px += qx
  85. remx -= qx
  86. }
  87. py += qy
  88. remy -= qy
  89. }
  90. }
  91. }
  92. return average(sum, w, h, n*0x0101)
  93. }
  94. //平均转换平均值,并返回结果。
  95. // average convert the sums to averages and returns the result.
  96. func average(sum []uint64, w, h int, n uint64) image.Image {
  97. ret := image.NewRGBA(image.Rect(0, 0, w, h))
  98. for y := 0; y < h; y++ {
  99. for x := 0; x < w; x++ {
  100. index := 4 * (y*w + x)
  101. ret.SetRGBA(x, y, color.RGBA{
  102. uint8(sum[index+0] / n),
  103. uint8(sum[index+1] / n),
  104. uint8(sum[index+2] / n),
  105. uint8(sum[index+3] / n),
  106. })
  107. }
  108. }
  109. return ret
  110. }
  111. // resizeYCbCr的返回片的R米的RGB图像的缩放副本。
  112. // 返回的图像具有宽度w和高度h。
  113. // resizeYCbCr returns a scaled copy of the YCbCr image slice r of m.
  114. // The returned image has width w and height h.
  115. func resizeYCbCr(m *image.YCbCr, r image.Rectangle, w, h int) (image.Image, bool) {
  116. var verticalRes int
  117. switch m.SubsampleRatio {
  118. case image.YCbCrSubsampleRatio420:
  119. verticalRes = 2
  120. case image.YCbCrSubsampleRatio422:
  121. verticalRes = 1
  122. default:
  123. return nil, false
  124. }
  125. ww, hh := uint64(w), uint64(h)
  126. dx, dy := uint64(r.Dx()), uint64(r.Dy())
  127. // See comment in Resize.
  128. n, sum := dx*dy, make([]uint64, 4*w*h)
  129. for y := r.Min.Y; y < r.Max.Y; y++ {
  130. Y := m.Y[y*m.YStride:]
  131. Cb := m.Cb[y/verticalRes*m.CStride:]
  132. Cr := m.Cr[y/verticalRes*m.CStride:]
  133. for x := r.Min.X; x < r.Max.X; x++ {
  134. // Get the source pixel.
  135. r8, g8, b8 := color.YCbCrToRGB(Y[x], Cb[x/2], Cr[x/2])
  136. r64 := uint64(r8)
  137. g64 := uint64(g8)
  138. b64 := uint64(b8)
  139. // Spread the source pixel over 1 or more destination rows.
  140. py := uint64(y) * hh
  141. for remy := hh; remy > 0; {
  142. qy := dy - (py % dy)
  143. if qy > remy {
  144. qy = remy
  145. }
  146. // Spread the source pixel over 1 or more destination columns.
  147. px := uint64(x) * ww
  148. index := 4 * ((py/dy)*ww + (px / dx))
  149. for remx := ww; remx > 0; {
  150. qx := dx - (px % dx)
  151. if qx > remx {
  152. qx = remx
  153. }
  154. qxy := qx * qy
  155. sum[index+0] += r64 * qxy
  156. sum[index+1] += g64 * qxy
  157. sum[index+2] += b64 * qxy
  158. sum[index+3] += 0xFFFF * qxy
  159. index += 4
  160. px += qx
  161. remx -= qx
  162. }
  163. py += qy
  164. remy -= qy
  165. }
  166. }
  167. }
  168. return average(sum, w, h, n), true
  169. }
  170. // resizeRGBA的返回一个缩放的属于m的RGBA图像切片。
  171. // 返回的图像具有宽度w和高度h。
  172. // resizeRGBA returns a scaled copy of the RGBA image slice r of m.
  173. // The returned image has width w and height h.
  174. func resizeRGBA(m *image.RGBA, r image.Rectangle, w, h int) image.Image {
  175. ww, hh := uint64(w), uint64(h)
  176. dx, dy := uint64(r.Dx()), uint64(r.Dy())
  177. // See comment in Resize.
  178. n, sum := dx*dy, make([]uint64, 4*w*h)
  179. for y := r.Min.Y; y < r.Max.Y; y++ {
  180. pixOffset := m.PixOffset(r.Min.X, y)
  181. for x := r.Min.X; x < r.Max.X; x++ {
  182. // Get the source pixel.
  183. r64 := uint64(m.Pix[pixOffset+0])
  184. g64 := uint64(m.Pix[pixOffset+1])
  185. b64 := uint64(m.Pix[pixOffset+2])
  186. a64 := uint64(m.Pix[pixOffset+3])
  187. pixOffset += 4
  188. // Spread the source pixel over 1 or more destination rows.
  189. py := uint64(y) * hh
  190. for remy := hh; remy > 0; {
  191. qy := dy - (py % dy)
  192. if qy > remy {
  193. qy = remy
  194. }
  195. // Spread the source pixel over 1 or more destination columns.
  196. px := uint64(x) * ww
  197. index := 4 * ((py/dy)*ww + (px / dx))
  198. for remx := ww; remx > 0; {
  199. qx := dx - (px % dx)
  200. if qx > remx {
  201. qx = remx
  202. }
  203. qxy := qx * qy
  204. sum[index+0] += r64 * qxy
  205. sum[index+1] += g64 * qxy
  206. sum[index+2] += b64 * qxy
  207. sum[index+3] += a64 * qxy
  208. index += 4
  209. px += qx
  210. remx -= qx
  211. }
  212. py += qy
  213. remy -= qy
  214. }
  215. }
  216. }
  217. return average(sum, w, h, n)
  218. }
  219. // 重新取样返回一个重采样本的图像切片r的副本。
  220. // 返回的图像具有宽度w和高度h。
  221. // Resample returns a resampled copy of the image slice r of m.
  222. // The returned image has width w and height h.
  223. func Resample(m image.Image, r image.Rectangle, w, h int) image.Image {
  224. if w < 0 || h < 0 {
  225. return nil
  226. }
  227. if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {
  228. return image.NewRGBA64(image.Rect(0, 0, w, h))
  229. }
  230. curw, curh := r.Dx(), r.Dy()
  231. img := image.NewRGBA(image.Rect(0, 0, w, h))
  232. for y := 0; y < h; y++ {
  233. for x := 0; x < w; x++ {
  234. // Get a source pixel.
  235. subx := x * curw / w
  236. suby := y * curh / h
  237. r32, g32, b32, a32 := m.At(subx, suby).RGBA()
  238. r := uint8(r32 >> 8)
  239. g := uint8(g32 >> 8)
  240. b := uint8(b32 >> 8)
  241. a := uint8(a32 >> 8)
  242. img.SetRGBA(x, y, color.RGBA{r, g, b, a})
  243. }
  244. }
  245. return img
  246. }