diff options
author | Ben Clayton <bclayton@google.com> | 2015-02-19 19:05:11 +0000 |
---|---|---|
committer | Ben Clayton <bclayton@google.com> | 2015-02-20 11:25:07 +0000 |
commit | 3195f9fb7bc5339f32d46282564f8d7dcb3d5f48 (patch) | |
tree | 2b5a87ddcb351eef282e165c6dca1fbc9d545c91 /image | |
parent | d197b3a0e8a95bb9710e847b682709f8371302ca (diff) | |
download | gpu-3195f9fb7bc5339f32d46282564f8d7dcb3d5f48.tar.gz |
Initial drop of the image package.
Package image provides functions for converting between various image
formats.
Change-Id: Id98cb492414225b44a412d78385db46b9b715a22
Diffstat (limited to 'image')
-rw-r--r-- | image/alpha.go | 38 | ||||
-rw-r--r-- | image/atc.go | 153 | ||||
-rw-r--r-- | image/convert.go | 69 | ||||
-rw-r--r-- | image/doc.go | 17 | ||||
-rw-r--r-- | image/etc1.go | 108 | ||||
-rw-r--r-- | image/format.go | 44 | ||||
-rw-r--r-- | image/lum.go | 40 | ||||
-rw-r--r-- | image/lum_alpha.go | 40 | ||||
-rw-r--r-- | image/png.go | 49 | ||||
-rw-r--r-- | image/rgb.go | 40 | ||||
-rw-r--r-- | image/utils.go | 41 |
11 files changed, 639 insertions, 0 deletions
diff --git a/image/alpha.go b/image/alpha.go new file mode 100644 index 000000000..66a3eb87a --- /dev/null +++ b/image/alpha.go @@ -0,0 +1,38 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +type fmtAlpha struct{} + +func (fmtAlpha) String() string { return "Alpha" } +func (fmtAlpha) Check(d []byte, w, h int) error { return checkSize(d, w, h, 8) } + +// Alpha returns a format containing a single 8-bit alpha channel per pixel. +func Alpha() Format { return fmtAlpha{} } + +func init() { + RegisterConverter(Alpha(), RGBA(), + func(src []byte, width, height int) ([]byte, error) { + dst, i, j := make([]byte, width*height*4), 0, 0 + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + dst[j+0], dst[j+1], dst[j+2], dst[j+3] = 255, 255, 255, src[i] + i++ + j += 4 + } + } + return dst, nil + }) +} diff --git a/image/atc.go b/image/atc.go new file mode 100644 index 000000000..fa8fcc260 --- /dev/null +++ b/image/atc.go @@ -0,0 +1,153 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +import "android.googlesource.com/platform/tools/gpu/binary" + +type fmtATC_RGB_AMD struct{} + +func (fmtATC_RGB_AMD) String() string { return "ATC_RGB_AMD" } +func (fmtATC_RGB_AMD) Check(d []byte, w, h int) error { + return checkSize(d, max(w, 4), max(h, 4), 4) +} + +type fmtATC_RGBA_EXPLICIT_ALPHA_AMD struct{} + +func (fmtATC_RGBA_EXPLICIT_ALPHA_AMD) String() string { return "ATC_RGBA_EXPLICIT_ALPHA_AMD" } +func (fmtATC_RGBA_EXPLICIT_ALPHA_AMD) Check(d []byte, w, h int) error { + return checkSize(d, max(w, 4), max(h, 4), 8) +} + +// ATC_RGB_AMD returns a format representing the texture compression format with +// the same name. +func ATC_RGB_AMD() Format { return fmtATC_RGB_AMD{} } + +// ATC_RGBA_EXPLICIT_ALPHA_AMD returns a format representing the texture +// compression format with the same name. +func ATC_RGBA_EXPLICIT_ALPHA_AMD() Format { return fmtATC_RGBA_EXPLICIT_ALPHA_AMD{} } + +func init() { + RegisterConverter(ATC_RGB_AMD(), RGBA(), + func(src []byte, width, height int) ([]byte, error) { + dst, j := make([]byte, width*height*4), 0 + + block_width := max(width/4, 1) + block_height := max(height/4, 1) + + bs := binary.BitStream{Data: src} + + c := [4][3]uint32{ + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + } + + for by := 0; by < block_height; by++ { + for bx := 0; bx < block_width; bx++ { + c[0][2] = bs.Read(5) << 3 + c[0][1] = bs.Read(5) << 3 + c[0][0] = bs.Read(5) << 3 + alt := bs.ReadBit() != 0 + c[3][2] = bs.Read(5) << 3 + c[3][1] = bs.Read(6) << 2 + c[3][0] = bs.Read(5) << 3 + for i := 0; i < 3; i++ { + if alt { + c[2][i] = c[0][i] + c[1][i] = c[0][i] - c[3][i]/4 + c[0][i] = 0 + } else { + c[1][i] = (c[0][i]*2 + c[3][i]*1) / 3 + c[2][i] = (c[0][i]*1 + c[3][i]*2) / 3 + } + } + for y := by * 4; y < (by+1)*4; y++ { + for x := bx * 4; x < (bx+1)*4; x++ { + idx := bs.Read(2) + if x < width && y < height { + j = 4 * (y*width + x) + dst[j+0] = uint8(c[idx][0]) + dst[j+1] = uint8(c[idx][1]) + dst[j+2] = uint8(c[idx][2]) + dst[j+3] = 255 + } + } + } + } + } + + return dst, nil + }) + + RegisterConverter(ATC_RGBA_EXPLICIT_ALPHA_AMD(), RGBA(), + func(src []byte, width, height int) ([]byte, error) { + dst, j := make([]byte, width*height*4), 0 + + block_width := max(width/4, 1) + block_height := max(height/4, 1) + + bs := binary.BitStream{Data: src} + + a := [16]uint8{ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + } + + c := [4][3]uint32{ + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + } + + for by := 0; by < block_height; by++ { + for bx := 0; bx < block_width; bx++ { + for i := 0; i < 16; i++ { + a[i] = uint8(bs.Read(4) << 4) + } + c[0][2] = bs.Read(5) << 3 + c[0][1] = bs.Read(5) << 3 + c[0][0] = bs.Read(5) << 3 + bs.ReadBit() + c[3][2] = bs.Read(5) << 3 + c[3][1] = bs.Read(6) << 2 + c[3][0] = bs.Read(5) << 3 + for i := 0; i < 3; i++ { + c[1][i] = (c[0][i]*2 + c[3][i]*1) / 3 + c[2][i] = (c[0][i]*1 + c[3][i]*2) / 3 + } + p := 0 + for y := by * 4; y < (by+1)*4; y++ { + for x := bx * 4; x < (bx+1)*4; x++ { + idx := bs.Read(2) + if x < width && y < height { + j = 4 * (y*width + x) + dst[j+0] = uint8(c[idx][0]) + dst[j+1] = uint8(c[idx][1]) + dst[j+2] = uint8(c[idx][2]) + dst[j+3] = a[p] + p++ + } + } + } + } + } + + return dst, nil + }) +} diff --git a/image/convert.go b/image/convert.go new file mode 100644 index 000000000..b5e6ad21b --- /dev/null +++ b/image/convert.go @@ -0,0 +1,69 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +import "fmt" + +// Converter is used to convert the the image formed from the parameters data, +// width and height into another format. If the conversion succeeds then the +// converted image data is returned, otherwise an error is returned. +type Converter func(data []byte, width int, height int) ([]byte, error) + +type srcDstFmt struct{ src, dst Format } + +var registeredConverters = make(map[srcDstFmt]Converter) + +// RegisterConverter registers the Converter for converting from src to dst +// formats. If a converter already exists for converting from src to dst, then +// this function panics. +func RegisterConverter(src, dst Format, c Converter) { + key := srcDstFmt{src, dst} + if _, found := registeredConverters[key]; found { + panic(fmt.Errorf("Converter from %s to %s already registered", src, dst)) + } + registeredConverters[key] = c +} + +// Convert uses the registered Converters to convert the image formed from the +// parameters data, width and height from srcFmt to dstFmt. If the conversion +// succeeds then the converted image data is returned, otherwise an error is +// returned. +// If no direct converter has been registered to convert from srcFmt to dstFmt, +// then Convert may try converting via an intermediate format. +func Convert(data []byte, width int, height int, srcFmt Format, dstFmt Format) ([]byte, error) { + if srcFmt == dstFmt { + return data, nil // No conversion required. + } + + if err := srcFmt.Check(data, width, height); err != nil { + return nil, fmt.Errorf("Source data of format %s is invalid: %s", srcFmt, err) + } + + if conv, found := registeredConverters[srcDstFmt{srcFmt, dstFmt}]; found { + return conv(data, width, height) + } + + // Try going via RGBA + if convA, found := registeredConverters[srcDstFmt{srcFmt, RGBA()}]; found { + if convB, found := registeredConverters[srcDstFmt{RGBA(), dstFmt}]; found { + if data, err := convA(data, width, height); err != nil { + return convB(data, width, height) + } + } + } + + return nil, fmt.Errorf("No converter registered that can convert from format '%s' to '%s'\n", + srcFmt, dstFmt) +} diff --git a/image/doc.go b/image/doc.go new file mode 100644 index 000000000..14b17f7b6 --- /dev/null +++ b/image/doc.go @@ -0,0 +1,17 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package image provides functions for converting between various image +// formats. +package image diff --git a/image/etc1.go b/image/etc1.go new file mode 100644 index 000000000..8c4a1bf6f --- /dev/null +++ b/image/etc1.go @@ -0,0 +1,108 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +type fmtETC1_RGB8_OES struct{} + +func (fmtETC1_RGB8_OES) String() string { return "ETC1_RGB8_OES" } +func (fmtETC1_RGB8_OES) Check(d []byte, w, h int) error { + return checkSize(d, max(w, 4), max(h, 4), 4) +} + +// ETC1_RGB8_OES returns a format representing the texture compression format +// with the same name. +func ETC1_RGB8_OES() Format { return fmtETC1_RGB8_OES{} } + +func init() { + RegisterConverter(ETC1_RGB8_OES(), RGBA(), func(src []byte, width, height int) ([]byte, error) { + dst := make([]byte, width*height*4) + + block_width := max(width/4, 1) + block_height := max(height/4, 1) + + c := [2][3]int32{} + codes := [2][4]int32{} + modTbl := [8][4]int32{ + {2, 8, -2, -8}, + {5, 17, -5, -17}, + {9, 29, -9, -29}, + {13, 42, -13, -42}, + {18, 60, -18, -60}, + {24, 80, -24, -80}, + {33, 106, -33, -106}, + {47, 183, -47, -183}, + } + diffTbl := [8]int32{0, 1, 2, 3, -4, -3, -2, -1} + flipTbl := [2][16]int32{ + {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}, + } + for by := 0; by < block_height; by++ { + for bx := 0; bx < block_width; bx++ { + u64 := uint64(src[0]) + u64 = (u64 << 8) | uint64(src[1]) + u64 = (u64 << 8) | uint64(src[2]) + u64 = (u64 << 8) | uint64(src[3]) + u64 = (u64 << 8) | uint64(src[4]) + u64 = (u64 << 8) | uint64(src[5]) + u64 = (u64 << 8) | uint64(src[6]) + u64 = (u64 << 8) | uint64(src[7]) + src = src[8:] + flip := (u64 >> 32) & 1 + diff := (u64 >> 33) & 1 + + codes[0] = modTbl[(u64>>37)&7] + codes[1] = modTbl[(u64>>34)&7] + + for i := uint(0); i < 3; i++ { + if diff == 0 { + a := (u64 >> (44 + i*8)) & 15 + b := (u64 >> (40 + i*8)) & 15 + c[0][i] = int32((a << 4) | a) + c[1][i] = int32((b << 4) | b) + } else { + a := (u64 >> (43 + i*8)) & 31 + b := (u64 >> (40 + i*8)) & 7 + d := int32(int32(a) + diffTbl[b]) + c[0][i] = int32((a << 3) | (a >> 2)) + c[1][i] = int32((d << 3) | (d >> 2)) + } + } + + blockTbl := flipTbl[flip] + + i := uint(0) + for x := bx * 4; x < (bx+1)*4; x++ { + for y := by * 4; y < (by+1)*4; y++ { + if x < width && y < height { + block := blockTbl[i] + base := c[block] + k := 4 * (y*width + x) + idx := ((u64 >> i) & 1) | ((u64 >> (15 + i)) & 2) + shift := codes[block][idx] + dst[k+0] = toByte(base[2] + shift) + dst[k+1] = toByte(base[1] + shift) + dst[k+2] = toByte(base[0] + shift) + dst[k+3] = 255 + i++ + } + } + } + } + } + + return dst, nil + }) +} diff --git a/image/format.go b/image/format.go new file mode 100644 index 000000000..279f7e11b --- /dev/null +++ b/image/format.go @@ -0,0 +1,44 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +import "fmt" + +// Format is the interface for an image and/or pixel format. +// +// Check returns an error if the combination of data, image width and image +// height is invalid for the given format, otherwise Check returns nil. +type Format interface { + Check(data []byte, width, height int) error +} + +func checkSize(data []byte, width, height int, bpp int) error { + expected := width * height * bpp / 8 + actual := len(data) + if expected != actual { + return fmt.Errorf("Image data size (0x%x) did not match expected (0x%x) for dimensions %dx%d\n", + actual, expected, width, height) + } + return nil +} + +type fmtRGBA struct{} + +func (fmtRGBA) String() string { return "RGBA" } +func (fmtRGBA) Check(d []byte, w, h int) error { return checkSize(d, w, h, 32) } + +// RGBA returns a format containing an 8-bit red, green, blue and alpha channel +// per pixel. +func RGBA() Format { return fmtRGBA{} } diff --git a/image/lum.go b/image/lum.go new file mode 100644 index 000000000..2bac04343 --- /dev/null +++ b/image/lum.go @@ -0,0 +1,40 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +type fmtLuminance struct{} + +func (fmtLuminance) String() string { return "Luminance" } +func (fmtLuminance) Check(d []byte, w, h int) error { return checkSize(d, w, h, 8) } + +// Luminance returns a format containing a single 8-bit luminance channel per +// pixel. +func Luminance() Format { return fmtLuminance{} } + +func init() { + RegisterConverter(Luminance(), RGBA(), + func(src []byte, width, height int) ([]byte, error) { + dst, i, j := make([]byte, width*height*4), 0, 0 + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + dst[j+0], dst[j+1], dst[j+2], dst[j+3] = src[i], src[i], src[i], 255 + i++ + j += 4 + } + } + + return dst, nil + }) +} diff --git a/image/lum_alpha.go b/image/lum_alpha.go new file mode 100644 index 000000000..7d9686a36 --- /dev/null +++ b/image/lum_alpha.go @@ -0,0 +1,40 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +type fmtLuminanceAlpha struct{} + +func (fmtLuminanceAlpha) String() string { return "LuminanceAlpha" } +func (fmtLuminanceAlpha) Check(d []byte, w, h int) error { return checkSize(d, w, h, 16) } + +// LuminanceAlpha returns a format containing an 8-bit luminance and alpha +// channel per pixel. +func LuminanceAlpha() Format { return fmtLuminanceAlpha{} } + +func init() { + RegisterConverter(LuminanceAlpha(), RGBA(), + func(src []byte, width, height int) ([]byte, error) { + dst, i, j := make([]byte, width*height*4), 0, 0 + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + dst[j+0], dst[j+1], dst[j+2], dst[j+3] = src[i+0], src[i+0], src[i+0], src[i+1] + i += 2 + j += 4 + } + } + + return dst, nil + }) +} diff --git a/image/png.go b/image/png.go new file mode 100644 index 000000000..b8d0f4412 --- /dev/null +++ b/image/png.go @@ -0,0 +1,49 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +import ( + "bytes" + "image" + "image/color" + "image/png" +) + +type fmtPNG struct{} + +func (fmtPNG) String() string { return "PNG" } +func (fmtPNG) Check(d []byte, w, h int) error { return nil } + +// PNG returns a format representing the the texture compression format with the +// same name. +func PNG() Format { return fmtPNG{} } + +func init() { + RegisterConverter(RGBA(), PNG(), + func(src []byte, width, height int) ([]byte, error) { + img := image.NewRGBA(image.Rect(0, 0, width, height)) + i := 0 + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + img.Set(x, y, color.RGBA{src[i+0], src[i+1], src[i+2], src[i+3]}) + i += 4 + } + } + + buffer := bytes.Buffer{} + png.Encode(&buffer, img) + return buffer.Bytes(), nil + }) +} diff --git a/image/rgb.go b/image/rgb.go new file mode 100644 index 000000000..3d607f20e --- /dev/null +++ b/image/rgb.go @@ -0,0 +1,40 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +type fmtRGB struct{} + +func (fmtRGB) String() string { return "RGB" } +func (fmtRGB) Check(d []byte, w, h int) error { return checkSize(d, w, h, 24) } + +// RGB returns a format containing an 8-bit red, green and blue channel per +// pixel. +func RGB() Format { return fmtRGB{} } + +func init() { + RegisterConverter(RGB(), RGBA(), + func(src []byte, width, height int) ([]byte, error) { + dst, i, j := make([]byte, width*height*4), 0, 0 + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + dst[j+0], dst[j+1], dst[j+2], dst[j+3] = src[i+0], src[i+1], src[i+2], 255 + i += 3 + j += 4 + } + } + + return dst, nil + }) +} diff --git a/image/utils.go b/image/utils.go new file mode 100644 index 000000000..0b838bed8 --- /dev/null +++ b/image/utils.go @@ -0,0 +1,41 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +func min(a, b int) int { + if a < b { + return a + } else { + return b + } +} + +func max(a, b int) int { + if a > b { + return a + } else { + return b + } +} + +func toByte(i int32) byte { + if i < 0 { + return 0 + } + if i > 255 { + return 255 + } + return byte(i) +} |