| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package nycbcra provides non-alpha-premultiplied Y'CbCr-with-alpha image and |
| // color types. |
| // |
| // Deprecated: as of Go 1.6. Use the standard image and image/color packages |
| // instead. |
| package nycbcra // import "golang.org/x/image/webp/nycbcra" |
| |
| import ( |
| "image" |
| "image/color" |
| ) |
| |
| func init() { |
| println("The golang.org/x/image/webp/nycbcra package is deprecated, as of Go 1.6. " + |
| "Use the standard image and image/color packages instead.") |
| } |
| |
| // TODO: move this to the standard image and image/color packages, so that the |
| // image/draw package can have fast-path code. Moving would rename: |
| // nycbcra.Color to color.NYCbCrA |
| // nycbcra.ColorModel to color.NYCbCrAModel |
| // nycbcra.Image to image.NYCbCrA |
| |
| // Color represents a non-alpha-premultiplied Y'CbCr-with-alpha color, having |
| // 8 bits each for one luma, two chroma and one alpha component. |
| type Color struct { |
| color.YCbCr |
| A uint8 |
| } |
| |
| func (c Color) RGBA() (r, g, b, a uint32) { |
| r8, g8, b8 := color.YCbCrToRGB(c.Y, c.Cb, c.Cr) |
| a = uint32(c.A) * 0x101 |
| r = uint32(r8) * 0x101 * a / 0xffff |
| g = uint32(g8) * 0x101 * a / 0xffff |
| b = uint32(b8) * 0x101 * a / 0xffff |
| return |
| } |
| |
| // ColorModel is the Model for non-alpha-premultiplied Y'CbCr-with-alpha colors. |
| var ColorModel color.Model = color.ModelFunc(nYCbCrAModel) |
| |
| func nYCbCrAModel(c color.Color) color.Color { |
| switch c := c.(type) { |
| case Color: |
| return c |
| case color.YCbCr: |
| return Color{c, 0xff} |
| } |
| r, g, b, a := c.RGBA() |
| |
| // Convert from alpha-premultiplied to non-alpha-premultiplied. |
| if a != 0 { |
| r = (r * 0xffff) / a |
| g = (g * 0xffff) / a |
| b = (b * 0xffff) / a |
| } |
| |
| y, u, v := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8)) |
| return Color{color.YCbCr{Y: y, Cb: u, Cr: v}, uint8(a >> 8)} |
| } |
| |
| // Image is an in-memory image of non-alpha-premultiplied Y'CbCr-with-alpha |
| // colors. A and AStride are analogous to the Y and YStride fields of the |
| // embedded YCbCr. |
| type Image struct { |
| image.YCbCr |
| A []uint8 |
| AStride int |
| } |
| |
| func (p *Image) ColorModel() color.Model { |
| return ColorModel |
| } |
| |
| func (p *Image) At(x, y int) color.Color { |
| return p.NYCbCrAAt(x, y) |
| } |
| |
| func (p *Image) NYCbCrAAt(x, y int) Color { |
| if !(image.Point{X: x, Y: y}.In(p.Rect)) { |
| return Color{} |
| } |
| yi := p.YOffset(x, y) |
| ci := p.COffset(x, y) |
| ai := p.AOffset(x, y) |
| return Color{ |
| color.YCbCr{ |
| Y: p.Y[yi], |
| Cb: p.Cb[ci], |
| Cr: p.Cr[ci], |
| }, |
| p.A[ai], |
| } |
| } |
| |
| // AOffset returns the index of the first element of A that corresponds to |
| // the pixel at (x, y). |
| func (p *Image) AOffset(x, y int) int { |
| return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X) |
| } |
| |
| // SubImage returns an image representing the portion of the image p visible |
| // through r. The returned value shares pixels with the original image. |
| func (p *Image) SubImage(r image.Rectangle) image.Image { |
| // TODO: share code with image.NewYCbCr when this type moves into the |
| // standard image package. |
| r = r.Intersect(p.Rect) |
| // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside |
| // either r1 or r2 if the intersection is empty. Without explicitly checking for |
| // this, the Pix[i:] expression below can panic. |
| if r.Empty() { |
| return &Image{ |
| YCbCr: image.YCbCr{ |
| SubsampleRatio: p.SubsampleRatio, |
| }, |
| } |
| } |
| yi := p.YOffset(r.Min.X, r.Min.Y) |
| ci := p.COffset(r.Min.X, r.Min.Y) |
| ai := p.AOffset(r.Min.X, r.Min.Y) |
| return &Image{ |
| YCbCr: image.YCbCr{ |
| Y: p.Y[yi:], |
| Cb: p.Cb[ci:], |
| Cr: p.Cr[ci:], |
| SubsampleRatio: p.SubsampleRatio, |
| YStride: p.YStride, |
| CStride: p.CStride, |
| Rect: r, |
| }, |
| A: p.A[ai:], |
| AStride: p.AStride, |
| } |
| } |
| |
| // Opaque scans the entire image and reports whether it is fully opaque. |
| func (p *Image) Opaque() bool { |
| if p.Rect.Empty() { |
| return true |
| } |
| i0, i1 := 0, p.Rect.Dx() |
| for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { |
| for _, a := range p.A[i0:i1] { |
| if a != 0xff { |
| return false |
| } |
| } |
| i0 += p.AStride |
| i1 += p.AStride |
| } |
| return true |
| } |
| |
| // New returns a new Image with the given bounds and subsample ratio. |
| func New(r image.Rectangle, subsampleRatio image.YCbCrSubsampleRatio) *Image { |
| // TODO: share code with image.NewYCbCr when this type moves into the |
| // standard image package. |
| w, h, cw, ch := r.Dx(), r.Dy(), 0, 0 |
| switch subsampleRatio { |
| case image.YCbCrSubsampleRatio422: |
| cw = (r.Max.X+1)/2 - r.Min.X/2 |
| ch = h |
| case image.YCbCrSubsampleRatio420: |
| cw = (r.Max.X+1)/2 - r.Min.X/2 |
| ch = (r.Max.Y+1)/2 - r.Min.Y/2 |
| case image.YCbCrSubsampleRatio440: |
| cw = w |
| ch = (r.Max.Y+1)/2 - r.Min.Y/2 |
| default: |
| // Default to 4:4:4 subsampling. |
| cw = w |
| ch = h |
| } |
| b := make([]byte, 2*w*h+2*cw*ch) |
| // TODO: use s[i:j:k] notation to set the cap. |
| return &Image{ |
| YCbCr: image.YCbCr{ |
| Y: b[:w*h], |
| Cb: b[w*h+0*cw*ch : w*h+1*cw*ch], |
| Cr: b[w*h+1*cw*ch : w*h+2*cw*ch], |
| SubsampleRatio: subsampleRatio, |
| YStride: w, |
| CStride: cw, |
| Rect: r, |
| }, |
| A: b[w*h+2*cw*ch:], |
| AStride: w, |
| } |
| } |