ycbcr.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2011 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 image
  5. import (
  6. "image/color"
  7. )
  8. // YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
  9. type YCbCrSubsampleRatio int
  10. const (
  11. YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
  12. YCbCrSubsampleRatio422
  13. YCbCrSubsampleRatio420
  14. YCbCrSubsampleRatio440
  15. )
  16. func (s YCbCrSubsampleRatio) String() string {
  17. switch s {
  18. case YCbCrSubsampleRatio444:
  19. return "YCbCrSubsampleRatio444"
  20. case YCbCrSubsampleRatio422:
  21. return "YCbCrSubsampleRatio422"
  22. case YCbCrSubsampleRatio420:
  23. return "YCbCrSubsampleRatio420"
  24. case YCbCrSubsampleRatio440:
  25. return "YCbCrSubsampleRatio440"
  26. }
  27. return "YCbCrSubsampleRatioUnknown"
  28. }
  29. // YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per
  30. // pixel, but each Cb and Cr sample can span one or more pixels.
  31. // YStride is the Y slice index delta between vertically adjacent pixels.
  32. // CStride is the Cb and Cr slice index delta between vertically adjacent pixels
  33. // that map to separate chroma samples.
  34. // It is not an absolute requirement, but YStride and len(Y) are typically
  35. // multiples of 8, and:
  36. // For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
  37. // For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
  38. // For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
  39. // For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
  40. type YCbCr struct {
  41. Y, Cb, Cr []uint8
  42. YStride int
  43. CStride int
  44. SubsampleRatio YCbCrSubsampleRatio
  45. Rect Rectangle
  46. }
  47. func (p *YCbCr) ColorModel() color.Model {
  48. return color.YCbCrModel
  49. }
  50. func (p *YCbCr) Bounds() Rectangle {
  51. return p.Rect
  52. }
  53. func (p *YCbCr) At(x, y int) color.Color {
  54. return p.YCbCrAt(x, y)
  55. }
  56. func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
  57. if !(Point{x, y}.In(p.Rect)) {
  58. return color.YCbCr{}
  59. }
  60. yi := p.YOffset(x, y)
  61. ci := p.COffset(x, y)
  62. return color.YCbCr{
  63. p.Y[yi],
  64. p.Cb[ci],
  65. p.Cr[ci],
  66. }
  67. }
  68. // YOffset returns the index of the first element of Y that corresponds to
  69. // the pixel at (x, y).
  70. func (p *YCbCr) YOffset(x, y int) int {
  71. return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X)
  72. }
  73. // COffset returns the index of the first element of Cb or Cr that corresponds
  74. // to the pixel at (x, y).
  75. func (p *YCbCr) COffset(x, y int) int {
  76. switch p.SubsampleRatio {
  77. case YCbCrSubsampleRatio422:
  78. return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2)
  79. case YCbCrSubsampleRatio420:
  80. return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
  81. case YCbCrSubsampleRatio440:
  82. return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
  83. }
  84. // Default to 4:4:4 subsampling.
  85. return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
  86. }
  87. // SubImage returns an image representing the portion of the image p visible
  88. // through r. The returned value shares pixels with the original image.
  89. func (p *YCbCr) SubImage(r Rectangle) Image {
  90. r = r.Intersect(p.Rect)
  91. // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
  92. // either r1 or r2 if the intersection is empty. Without explicitly checking for
  93. // this, the Pix[i:] expression below can panic.
  94. if r.Empty() {
  95. return &YCbCr{
  96. SubsampleRatio: p.SubsampleRatio,
  97. }
  98. }
  99. yi := p.YOffset(r.Min.X, r.Min.Y)
  100. ci := p.COffset(r.Min.X, r.Min.Y)
  101. return &YCbCr{
  102. Y: p.Y[yi:],
  103. Cb: p.Cb[ci:],
  104. Cr: p.Cr[ci:],
  105. SubsampleRatio: p.SubsampleRatio,
  106. YStride: p.YStride,
  107. CStride: p.CStride,
  108. Rect: r,
  109. }
  110. }
  111. func (p *YCbCr) Opaque() bool {
  112. return true
  113. }
  114. // NewYCbCr returns a new YCbCr with the given bounds and subsample ratio.
  115. func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
  116. w, h, cw, ch := r.Dx(), r.Dy(), 0, 0
  117. switch subsampleRatio {
  118. case YCbCrSubsampleRatio422:
  119. cw = (r.Max.X+1)/2 - r.Min.X/2
  120. ch = h
  121. case YCbCrSubsampleRatio420:
  122. cw = (r.Max.X+1)/2 - r.Min.X/2
  123. ch = (r.Max.Y+1)/2 - r.Min.Y/2
  124. case YCbCrSubsampleRatio440:
  125. cw = w
  126. ch = (r.Max.Y+1)/2 - r.Min.Y/2
  127. default:
  128. // Default to 4:4:4 subsampling.
  129. cw = w
  130. ch = h
  131. }
  132. b := make([]byte, w*h+2*cw*ch)
  133. return &YCbCr{
  134. Y: b[:w*h],
  135. Cb: b[w*h+0*cw*ch : w*h+1*cw*ch],
  136. Cr: b[w*h+1*cw*ch : w*h+2*cw*ch],
  137. SubsampleRatio: subsampleRatio,
  138. YStride: w,
  139. CStride: cw,
  140. Rect: r,
  141. }
  142. }