|
|
@ -6,6 +6,8 @@ import ( |
|
|
|
"image" |
|
|
|
"image/color" |
|
|
|
"image/draw" |
|
|
|
|
|
|
|
"maze.io/x/pixel/pixelcolor" |
|
|
|
) |
|
|
|
|
|
|
|
type Format int |
|
|
@ -14,18 +16,27 @@ const ( |
|
|
|
UnknownFormat Format = iota |
|
|
|
MHMSBFormat |
|
|
|
MVLSBFormat |
|
|
|
RGB332Format |
|
|
|
RGB565Format |
|
|
|
RGB888Format |
|
|
|
RGBA4444Format |
|
|
|
RGBA5551Format |
|
|
|
) |
|
|
|
|
|
|
|
func (f Format) ColorModel() color.Model { |
|
|
|
switch f { |
|
|
|
case MHMSBFormat, MVLSBFormat: |
|
|
|
return BitModel |
|
|
|
return pixelcolor.BitModel |
|
|
|
case RGB332Format: |
|
|
|
return pixelcolor.RGB332Model |
|
|
|
case RGB565Format: |
|
|
|
return RGB565Model |
|
|
|
return pixelcolor.RGB565Model |
|
|
|
case RGB888Format: |
|
|
|
return RGB888Model |
|
|
|
return pixelcolor.RGB888Model |
|
|
|
case RGBA4444Format: |
|
|
|
return pixelcolor.RGBA4444Model |
|
|
|
case RGBA5551Format: |
|
|
|
return pixelcolor.RGBA5551Model |
|
|
|
default: |
|
|
|
return color.RGBAModel |
|
|
|
} |
|
|
@ -68,13 +79,13 @@ func (b *Bitmap) Bounds() image.Rectangle { |
|
|
|
|
|
|
|
func (b *Bitmap) At(x, y int) color.Color { |
|
|
|
if x < 0 || y < 0 || x >= b.Rect.Max.X || y >= b.Rect.Max.Y { |
|
|
|
return Off |
|
|
|
return pixelcolor.Off |
|
|
|
} |
|
|
|
offset, mask := b.PixOffset(x, y) |
|
|
|
if offset >= len(b.Pix) { |
|
|
|
return Off |
|
|
|
return pixelcolor.Off |
|
|
|
} |
|
|
|
return Bit(b.Pix[offset]&byte(mask) != 0) |
|
|
|
return pixelcolor.Bit(b.Pix[offset]&byte(mask) != 0) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *Bitmap) PixOffset(x, y int) (int, uint) { |
|
|
@ -89,10 +100,10 @@ func (b *Bitmap) PixOffset(x, y int) (int, uint) { |
|
|
|
} |
|
|
|
|
|
|
|
func (b *Bitmap) Set(x, y int, c color.Color) { |
|
|
|
b.SetBit(x, y, toBit(c)) |
|
|
|
b.SetBit(x, y, pixelcolor.ToBit(c)) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *Bitmap) SetBit(x, y int, c Bit) { |
|
|
|
func (b *Bitmap) SetBit(x, y int, c pixelcolor.Bit) { |
|
|
|
offset, mask := b.PixOffset(x, y) |
|
|
|
if offset < 0 || offset >= len(b.Pix) { |
|
|
|
return |
|
|
@ -104,128 +115,202 @@ func (b *Bitmap) SetBit(x, y int, c Bit) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
type RGBImage struct { |
|
|
|
type RGB332 struct { |
|
|
|
Rect image.Rectangle |
|
|
|
Pix []byte |
|
|
|
Stride int |
|
|
|
} |
|
|
|
|
|
|
|
type RGB332Image struct { |
|
|
|
Rect image.Rectangle |
|
|
|
Pix []byte |
|
|
|
Stride int |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB332Image) Bounds() image.Rectangle { |
|
|
|
func (b *RGB332) Bounds() image.Rectangle { |
|
|
|
return b.Rect |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB332Image) At(x, y int) color.Color { |
|
|
|
func (b *RGB332) At(x, y int) color.Color { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return RGB332(0) |
|
|
|
return pixelcolor.RGB332(0) |
|
|
|
} |
|
|
|
return RGB332(b.Pix[y*b.Stride+x]) |
|
|
|
return pixelcolor.RGB332(b.Pix[y*b.Stride+x]) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB332Image) Set(x, y int, c color.Color) { |
|
|
|
func (b *RGB332) Set(x, y int, c color.Color) { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return |
|
|
|
} |
|
|
|
b.Pix[y*b.Stride+x] = byte(toRGB332(c)) |
|
|
|
b.Pix[y*b.Stride+x] = byte(pixelcolor.ToRGB332(c)) |
|
|
|
} |
|
|
|
|
|
|
|
func (RGB332Image) ColorModel() color.Model { |
|
|
|
return RGB332Model |
|
|
|
func (RGB332) ColorModel() color.Model { |
|
|
|
return pixelcolor.RGB332Model |
|
|
|
} |
|
|
|
|
|
|
|
func NewRGB332(w, h int) *RGB332Image { |
|
|
|
return &RGB332Image{ |
|
|
|
func NewRGB332(w, h int) *RGB332 { |
|
|
|
return &RGB332{ |
|
|
|
Rect: image.Rectangle{Max: image.Point{X: w, Y: h}}, |
|
|
|
Stride: w, |
|
|
|
Pix: make([]byte, w*h), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
type RGB565Image struct { |
|
|
|
type RGB565 struct { |
|
|
|
Rect image.Rectangle |
|
|
|
Pix []byte |
|
|
|
Stride int |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB565Image) Bounds() image.Rectangle { |
|
|
|
func (b *RGB565) Bounds() image.Rectangle { |
|
|
|
return b.Rect |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB565Image) At(x, y int) color.Color { |
|
|
|
func (b *RGB565) At(x, y int) color.Color { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return RGB565(0) |
|
|
|
return pixelcolor.RGB565(0) |
|
|
|
} |
|
|
|
return RGB565(binary.BigEndian.Uint16(b.Pix[b.OffsetOf(x, y):])) |
|
|
|
return pixelcolor.RGB565(binary.BigEndian.Uint16(b.Pix[b.OffsetOf(x, y):])) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB565Image) Set(x, y int, c color.Color) { |
|
|
|
func (b *RGB565) Set(x, y int, c color.Color) { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return |
|
|
|
} |
|
|
|
binary.BigEndian.PutUint16(b.Pix[b.OffsetOf(x, y):], uint16(toRGB565(c))) |
|
|
|
binary.BigEndian.PutUint16(b.Pix[b.OffsetOf(x, y):], uint16(pixelcolor.ToRGB565(c))) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB565Image) OffsetOf(x, y int) (offset int) { |
|
|
|
func (b *RGB565) OffsetOf(x, y int) (offset int) { |
|
|
|
return y*b.Stride + x*2 |
|
|
|
} |
|
|
|
|
|
|
|
func (RGB565Image) ColorModel() color.Model { |
|
|
|
return RGB565Model |
|
|
|
func (RGB565) ColorModel() color.Model { |
|
|
|
return pixelcolor.RGB565Model |
|
|
|
} |
|
|
|
|
|
|
|
func NewRGB565(w, h int) *RGB565Image { |
|
|
|
return &RGB565Image{ |
|
|
|
func NewRGB565(w, h int) *RGB565 { |
|
|
|
return &RGB565{ |
|
|
|
Rect: image.Rectangle{Max: image.Point{X: w, Y: h}}, |
|
|
|
Pix: make([]byte, w*h*2), |
|
|
|
Stride: w * 2, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
type RGB888Image struct { |
|
|
|
type RGB888 struct { |
|
|
|
Rect image.Rectangle |
|
|
|
Pix []byte |
|
|
|
Stride int |
|
|
|
} |
|
|
|
|
|
|
|
func NewRGB888(w, h int) *RGB888Image { |
|
|
|
return &RGB888Image{ |
|
|
|
func (b *RGB888) Bounds() image.Rectangle { |
|
|
|
return b.Rect |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888) At(x, y int) color.Color { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return color.Black |
|
|
|
} |
|
|
|
v := b.Pix[b.OffsetOf(x, y):] |
|
|
|
return pixelcolor.RGB888{v[0], v[1], v[2]} |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888) Set(x, y int, c color.Color) { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return |
|
|
|
} |
|
|
|
v := pixelcolor.ToRGB888(c) |
|
|
|
copy(b.Pix[b.OffsetOf(x, y):], []byte{v.R, v.G, v.B}) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888) OffsetOf(x, y int) (offset int) { |
|
|
|
return y*b.Stride + x*3 |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888) ColorModel() color.Model { |
|
|
|
return pixelcolor.RGB888Model |
|
|
|
} |
|
|
|
|
|
|
|
func NewRGB888(w, h int) *RGB888 { |
|
|
|
return &RGB888{ |
|
|
|
Rect: image.Rectangle{Max: image.Point{X: w, Y: h}}, |
|
|
|
Pix: make([]byte, w*h*3), |
|
|
|
Stride: w * 3, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888Image) Bounds() image.Rectangle { |
|
|
|
type RGBA4444 struct { |
|
|
|
Rect image.Rectangle |
|
|
|
Pix []byte |
|
|
|
Stride int |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGBA4444) Bounds() image.Rectangle { |
|
|
|
return b.Rect |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888Image) At(x, y int) color.Color { |
|
|
|
func (b *RGBA4444) At(x, y int) color.Color { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return color.Black |
|
|
|
} |
|
|
|
v := b.Pix[b.OffsetOf(x, y):] |
|
|
|
return RGB888{v[0], v[1], v[2]} |
|
|
|
return pixelcolor.RGBA4444(binary.BigEndian.Uint16(b.Pix[b.OffsetOf(x, y):])) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888Image) Set(x, y int, c color.Color) { |
|
|
|
func (b *RGBA4444) Set(x, y int, c color.Color) { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return |
|
|
|
} |
|
|
|
v := toRGB888(c) |
|
|
|
copy(b.Pix[b.OffsetOf(x, y):], []byte{v.R, v.G, v.B}) |
|
|
|
binary.BigEndian.PutUint16(b.Pix[b.OffsetOf(x, y):], uint16(pixelcolor.ToRGBA4444(c))) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGBA4444) OffsetOf(x, y int) (offset int) { |
|
|
|
return y*b.Stride + x*3 |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGBA4444) ColorModel() color.Model { |
|
|
|
return pixelcolor.RGBA4444Model |
|
|
|
} |
|
|
|
|
|
|
|
func NewRGBA4444(w, h int) *RGBA4444 { |
|
|
|
return &RGBA4444{ |
|
|
|
Rect: image.Rectangle{Max: image.Point{X: w, Y: h}}, |
|
|
|
Pix: make([]byte, w*h*2), |
|
|
|
Stride: w * 2, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
type RGBA5551 struct { |
|
|
|
Rect image.Rectangle |
|
|
|
Pix []byte |
|
|
|
Stride int |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGBA5551) Bounds() image.Rectangle { |
|
|
|
return b.Rect |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888Image) OffsetOf(x, y int) (offset int) { |
|
|
|
func (b *RGBA5551) At(x, y int) color.Color { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return color.Black |
|
|
|
} |
|
|
|
return pixelcolor.RGBA5551(binary.BigEndian.Uint16(b.Pix[b.OffsetOf(x, y):])) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGBA5551) Set(x, y int, c color.Color) { |
|
|
|
if !(image.Point{X: x, Y: y}).In(b.Rect) { |
|
|
|
return |
|
|
|
} |
|
|
|
binary.BigEndian.PutUint16(b.Pix[b.OffsetOf(x, y):], uint16(pixelcolor.ToRGBA5551(c))) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGBA5551) OffsetOf(x, y int) (offset int) { |
|
|
|
return y*b.Stride + x*3 |
|
|
|
} |
|
|
|
|
|
|
|
func (b *RGB888Image) ColorModel() color.Model { |
|
|
|
return RGB888Model |
|
|
|
func (b *RGBA5551) ColorModel() color.Model { |
|
|
|
return pixelcolor.RGBA5551Model |
|
|
|
} |
|
|
|
|
|
|
|
func NewRGBA5551(w, h int) *RGBA5551 { |
|
|
|
return &RGBA5551{ |
|
|
|
Rect: image.Rectangle{Max: image.Point{X: w, Y: h}}, |
|
|
|
Pix: make([]byte, w*h*2), |
|
|
|
Stride: w * 2, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func New(width, height int, format Format) (Image, error) { |
|
|
@ -234,10 +319,16 @@ func New(width, height int, format Format) (Image, error) { |
|
|
|
b := NewBitmap(width, height) |
|
|
|
b.Format = format |
|
|
|
return b, nil |
|
|
|
case RGB332Format: |
|
|
|
return NewRGB332(width, height), nil |
|
|
|
case RGB565Format: |
|
|
|
return NewRGB565(width, height), nil |
|
|
|
case RGB888Format: |
|
|
|
return NewRGB888(width, height), nil |
|
|
|
case RGBA4444Format: |
|
|
|
return NewRGBA4444(width, height), nil |
|
|
|
case RGBA5551Format: |
|
|
|
return NewRGBA5551(width, height), nil |
|
|
|
default: |
|
|
|
return nil, errors.New("framebuffer: invalid format") |
|
|
|
} |
|
|
|