in go/heif/heif.go [759:1114]
func (img *Image) GetImage() (image.Image, error) {
var i image.Image
cf := img.GetChromaFormat()
switch cs := img.GetColorspace(); cs {
case ColorspaceYCbCr:
var subsample image.YCbCrSubsampleRatio
switch cf {
case Chroma420:
subsample = image.YCbCrSubsampleRatio420
case Chroma422:
subsample = image.YCbCrSubsampleRatio422
case Chroma444:
subsample = image.YCbCrSubsampleRatio444
default:
return nil, fmt.Errorf("Unsupported YCbCr chroma format: %v", cf)
}
y, err := img.GetPlane(ChannelY)
if err != nil {
return nil, err
}
cb, err := img.GetPlane(ChannelCb)
if err != nil {
return nil, err
}
cr, err := img.GetPlane(ChannelCr)
if err != nil {
return nil, err
}
i = &image.YCbCr{
Y: y.Plane,
Cb: cb.Plane,
Cr: cr.Plane,
YStride: y.Stride,
CStride: cb.Stride,
SubsampleRatio: subsample,
Rect: image.Rectangle{
Min: image.Point{
X: 0,
Y: 0,
},
Max: image.Point{
X: img.GetWidth(ChannelY),
Y: img.GetHeight(ChannelY),
},
},
}
case ColorspaceRGB:
switch cf {
case Chroma444:
r, err := img.GetPlane(ChannelR)
if err != nil {
return nil, err
}
g, err := img.GetPlane(ChannelG)
if err != nil {
return nil, err
}
b, err := img.GetPlane(ChannelB)
if err != nil {
return nil, err
}
width := img.GetWidth(ChannelR)
height := img.GetHeight(ChannelR)
read_pos_r := 0
read_pos_g := 0
read_pos_b := 0
write_pos := 0
var rgba []byte
var stride int
if bpp := img.GetBitsPerPixelRange(ChannelR); bpp > 8 {
// NOTE: We only support the same bits per pixel on all components.
stride = width * 8
rgba = make([]byte, height*stride)
stride_add_r := r.Stride - width*2
stride_add_g := g.Stride - width*2
stride_add_b := b.Stride - width*2
if bpp == 16 {
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
rgba[write_pos] = r.Plane[read_pos_r]
rgba[write_pos+1] = r.Plane[read_pos_r+1]
rgba[write_pos+2] = g.Plane[read_pos_g]
rgba[write_pos+3] = g.Plane[read_pos_g+1]
rgba[write_pos+4] = b.Plane[read_pos_b]
rgba[write_pos+5] = b.Plane[read_pos_b+1]
rgba[write_pos+6] = 0xff
rgba[write_pos+7] = 0xff
read_pos_r += 2
read_pos_g += 2
read_pos_b += 2
write_pos += 8
}
read_pos_r += stride_add_r
read_pos_g += stride_add_g
read_pos_b += stride_add_b
}
} else {
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r_value := (int16(r.Plane[read_pos_r+1]) << 8) | int16(r.Plane[read_pos_r])
r_value = (r_value << (16 - uint(bpp))) | (r_value >> (2*uint(bpp) - 16))
rgba[write_pos] = byte(r_value >> 8)
rgba[write_pos+1] = byte(r_value & 0xff)
g_value := (int16(g.Plane[read_pos_g+1]) << 8) | int16(g.Plane[read_pos_g])
g_value = (g_value << (16 - uint(bpp))) | (g_value >> (2*uint(bpp) - 16))
rgba[write_pos+2] = byte(g_value >> 8)
rgba[write_pos+3] = byte(g_value & 0xff)
b_value := (int16(b.Plane[read_pos_b+1]) << 8) | int16(b.Plane[read_pos_b])
b_value = (b_value << (16 - uint(bpp))) | (b_value >> (2*uint(bpp) - 16))
rgba[write_pos+4] = byte(b_value >> 8)
rgba[write_pos+5] = byte(b_value & 0xff)
rgba[write_pos+6] = 0xff
rgba[write_pos+7] = 0xff
read_pos_r += 2
read_pos_g += 2
read_pos_b += 2
write_pos += 8
}
read_pos_r += stride_add_r
read_pos_g += stride_add_g
read_pos_b += stride_add_b
}
}
i = &image.RGBA64{
Pix: rgba,
Stride: stride,
Rect: image.Rectangle{
Min: image.Point{
X: 0,
Y: 0,
},
Max: image.Point{
X: width,
Y: height,
},
},
}
} else {
stride = width * 4
rgba = make([]byte, height*stride)
stride_add_r := r.Stride - width
stride_add_g := g.Stride - width
stride_add_b := b.Stride - width
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
rgba[write_pos] = r.Plane[read_pos_r]
rgba[write_pos+1] = g.Plane[read_pos_g]
rgba[write_pos+2] = b.Plane[read_pos_b]
rgba[write_pos+3] = 0xff
read_pos_r++
read_pos_g++
read_pos_b++
write_pos += 4
}
read_pos_r += stride_add_r
read_pos_g += stride_add_g
read_pos_b += stride_add_b
}
i = &image.RGBA{
Pix: rgba,
Stride: stride,
Rect: image.Rectangle{
Min: image.Point{
X: 0,
Y: 0,
},
Max: image.Point{
X: width,
Y: height,
},
},
}
}
case ChromaInterleavedRGB:
rgb, err := img.GetPlane(ChannelInterleaved)
if err != nil {
return nil, err
}
width := img.GetWidth(ChannelInterleaved)
height := img.GetHeight(ChannelInterleaved)
rgba := make([]byte, width*height*4)
read_pos := 0
write_pos := 0
stride_add := rgb.Stride - width*3
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
rgba[write_pos] = rgb.Plane[read_pos]
rgba[write_pos+1] = rgb.Plane[read_pos+1]
rgba[write_pos+2] = rgb.Plane[read_pos+2]
rgba[write_pos+3] = 0xff
read_pos += 3
write_pos += 4
}
read_pos += stride_add
}
i = &image.RGBA{
Pix: rgba,
Stride: width * 4,
Rect: image.Rectangle{
Min: image.Point{
X: 0,
Y: 0,
},
Max: image.Point{
X: width,
Y: height,
},
},
}
case ChromaInterleavedRGBA:
rgba, err := img.GetPlane(ChannelInterleaved)
if err != nil {
return nil, err
}
i = &image.RGBA{
Pix: rgba.Plane,
Stride: rgba.Stride,
Rect: image.Rectangle{
Min: image.Point{
X: 0,
Y: 0,
},
Max: image.Point{
X: img.GetWidth(ChannelInterleaved),
Y: img.GetHeight(ChannelInterleaved),
},
},
}
case ChromaInterleavedRRGGBB_BE:
rgb, err := img.GetPlane(ChannelInterleaved)
if err != nil {
return nil, err
}
width := img.GetWidth(ChannelInterleaved)
height := img.GetHeight(ChannelInterleaved)
rgba := make([]byte, width*height*8)
read_pos := 0
write_pos := 0
stride_add := rgb.Stride - width*6
if bpp := img.GetBitsPerPixelRange(ChannelInterleaved); bpp != 16 {
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r_value := (int16(rgb.Plane[read_pos]) << 8) | int16(rgb.Plane[read_pos+1])
r_value = (r_value << (16 - uint(bpp))) | (r_value >> (2*uint(bpp) - 16))
rgba[write_pos] = byte(r_value >> 8)
rgba[write_pos+1] = byte(r_value & 0xff)
g_value := (int16(rgb.Plane[read_pos+2]) << 8) | int16(rgb.Plane[read_pos+3])
g_value = (g_value << (16 - uint(bpp))) | (g_value >> (2*uint(bpp) - 16))
rgba[write_pos+2] = byte(g_value >> 8)
rgba[write_pos+3] = byte(g_value & 0xff)
b_value := (int16(rgb.Plane[read_pos+4]) << 8) | int16(rgb.Plane[read_pos+5])
b_value = (b_value << (16 - uint(bpp))) | (b_value >> (2*uint(bpp) - 16))
rgba[write_pos+4] = byte(b_value >> 8)
rgba[write_pos+5] = byte(b_value & 0xff)
rgba[write_pos+6] = 0xff
rgba[write_pos+7] = 0xff
read_pos += 6
write_pos += 8
}
read_pos += stride_add
}
} else {
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
rgba[write_pos] = rgb.Plane[read_pos]
rgba[write_pos+1] = rgb.Plane[read_pos+1]
rgba[write_pos+2] = rgb.Plane[read_pos+2]
rgba[write_pos+3] = rgb.Plane[read_pos+3]
rgba[write_pos+4] = rgb.Plane[read_pos+4]
rgba[write_pos+5] = rgb.Plane[read_pos+5]
rgba[write_pos+6] = 0xff
rgba[write_pos+7] = 0xff
read_pos += 6
write_pos += 8
}
read_pos += stride_add
}
}
i = &image.RGBA64{
Pix: rgba,
Stride: width * 4,
Rect: image.Rectangle{
Min: image.Point{
X: 0,
Y: 0,
},
Max: image.Point{
X: width,
Y: height,
},
},
}
case ChromaInterleavedRRGGBBAA_BE:
rgba, err := img.GetPlane(ChannelInterleaved)
if err != nil {
return nil, err
}
width := img.GetWidth(ChannelInterleaved)
height := img.GetHeight(ChannelInterleaved)
var plane []byte
if bpp := img.GetBitsPerPixelRange(ChannelInterleaved); bpp != 16 {
read_pos := 0
write_pos := 0
stride_add := rgba.Stride - width*8
plane = make([]byte, width*height*8)
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r_value := (int16(rgba.Plane[read_pos]) << 8) | int16(rgba.Plane[read_pos+1])
r_value = (r_value << (16 - uint(bpp))) | (r_value >> (2*uint(bpp) - 16))
plane[write_pos] = byte(r_value >> 8)
plane[write_pos+1] = byte(r_value & 0xff)
g_value := (int16(rgba.Plane[read_pos+2]) << 8) | int16(rgba.Plane[read_pos+3])
g_value = (g_value << (16 - uint(bpp))) | (g_value >> (2*uint(bpp) - 16))
plane[write_pos+2] = byte(g_value >> 8)
plane[write_pos+3] = byte(g_value & 0xff)
b_value := (int16(rgba.Plane[read_pos+4]) << 8) | int16(rgba.Plane[read_pos+5])
b_value = (b_value << (16 - uint(bpp))) | (b_value >> (2*uint(bpp) - 16))
plane[write_pos+4] = byte(b_value >> 8)
plane[write_pos+5] = byte(b_value & 0xff)
a_value := (int16(rgba.Plane[read_pos+6]) << 8) | int16(rgba.Plane[read_pos+7])
a_value = (a_value << (16 - uint(bpp))) | (a_value >> (2*uint(bpp) - 16))
plane[write_pos+6] = byte(a_value >> 8)
plane[write_pos+7] = byte(a_value & 0xff)
read_pos += 8
write_pos += 8
}
read_pos += stride_add
}
} else {
plane = rgba.Plane
}
i = &image.RGBA64{
Pix: plane,
Stride: rgba.Stride,
Rect: image.Rectangle{
Min: image.Point{
X: 0,
Y: 0,
},
Max: image.Point{
X: width,
Y: height,
},
},
}
default:
return nil, fmt.Errorf("Unsupported RGB chroma format: %v", cf)
}
default:
return nil, fmt.Errorf("Unsupported colorspace: %v", cs)
}
return i, nil
}