|
|
@ -1,133 +1,15 @@ |
|
|
|
package dmd |
|
|
|
|
|
|
|
import ( |
|
|
|
"encoding/binary" |
|
|
|
"image" |
|
|
|
"image/color" |
|
|
|
"image/draw" |
|
|
|
"image/gif" |
|
|
|
"io" |
|
|
|
"time" |
|
|
|
) |
|
|
|
|
|
|
|
type RGBA4BitImage struct { |
|
|
|
Rect image.Rectangle |
|
|
|
Pix []byte |
|
|
|
} |
|
|
|
|
|
|
|
func (i RGBA4BitImage) At(x, y int) color.Color { |
|
|
|
if !image.Pt(x, y).In(i.Rect) { |
|
|
|
return color.Transparent |
|
|
|
} |
|
|
|
o := (y*i.Rect.Max.X + x) * 2 |
|
|
|
return RGBA16(binary.LittleEndian.Uint16(i.Pix[o:])) |
|
|
|
} |
|
|
|
|
|
|
|
func (i RGBA4BitImage) Set(x, y int, c color.Color) { |
|
|
|
if !image.Pt(x, y).In(i.Rect) { |
|
|
|
return |
|
|
|
} |
|
|
|
o := y*i.Rect.Dx()*2 + x*2 |
|
|
|
if v, ok := c.(RGBA16); ok { |
|
|
|
binary.LittleEndian.PutUint16(i.Pix[o:], uint16(v)) |
|
|
|
} else { |
|
|
|
r, g, b, a := c.RGBA() |
|
|
|
v := uint16((r>>4)&0xf)<<12 | uint16((g>>4)&0xf)<<8 | uint16((b>>4)&0xf)<<4 | uint16((a>>4)&0xf) |
|
|
|
binary.LittleEndian.PutUint16(i.Pix[o:], v) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (i RGBA4BitImage) Bounds() image.Rectangle { |
|
|
|
return i.Rect |
|
|
|
} |
|
|
|
|
|
|
|
func (RGBA4BitImage) ColorModel() color.Model { |
|
|
|
return color.RGBAModel |
|
|
|
} |
|
|
|
|
|
|
|
const rgba4BitImageMagic = "4bit" |
|
|
|
|
|
|
|
type rgba4BitImageHeader struct { |
|
|
|
Magic [4]byte |
|
|
|
Width, Height uint16 |
|
|
|
} |
|
|
|
|
|
|
|
func (i *RGBA4BitImage) ReadFrom(r io.Reader) (n int64, err error) { |
|
|
|
var header rgba4BitImageHeader |
|
|
|
if err = binary.Read(r, binary.BigEndian, &header); err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
i.Rect = image.Rect(0, 0, int(header.Width), int(header.Height)) |
|
|
|
|
|
|
|
var m int |
|
|
|
i.Pix = make([]byte, i.Rect.Dx()*i.Rect.Dy()*2) |
|
|
|
if m, err = io.ReadFull(r, i.Pix); err != nil { |
|
|
|
return int64(binary.Size(header)) + int64(m), err |
|
|
|
} |
|
|
|
return int64(binary.Size(header)) + int64(m), nil |
|
|
|
} |
|
|
|
|
|
|
|
func (i *RGBA4BitImage) WriteTo(w io.Writer) (n int64, err error) { |
|
|
|
var header rgba4BitImageHeader |
|
|
|
copy(header.Magic[:], rgba4BitImageMagic) |
|
|
|
header.Width = uint16(i.Rect.Max.X) |
|
|
|
header.Height = uint16(i.Rect.Max.Y) |
|
|
|
if err = binary.Write(w, binary.BigEndian, header); err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
var m int |
|
|
|
if m, err = w.Write(i.Pix); err != nil { |
|
|
|
return int64(binary.Size(header)) + int64(m), err |
|
|
|
} |
|
|
|
return int64(binary.Size(header)) + int64(m), nil |
|
|
|
} |
|
|
|
|
|
|
|
func NewARGB4BitImage(r image.Rectangle) *RGBA4BitImage { |
|
|
|
return &RGBA4BitImage{ |
|
|
|
Rect: r, |
|
|
|
Pix: make([]uint8, r.Dx()*r.Dy()*2), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func ToARGB4BitImage(i image.Image) *RGBA4BitImage { |
|
|
|
if v, ok := i.(*RGBA4BitImage); ok { |
|
|
|
return v |
|
|
|
} |
|
|
|
o := NewARGB4BitImage(i.Bounds()) |
|
|
|
draw.Draw(o, o.Bounds(), i, image.Point{}, draw.Src) |
|
|
|
return o |
|
|
|
} |
|
|
|
|
|
|
|
type MaskedImage struct { |
|
|
|
image.Paletted |
|
|
|
Mask []byte |
|
|
|
} |
|
|
|
|
|
|
|
func (i MaskedImage) At(x, y int) color.Color { |
|
|
|
if len(i.Palette) == 0 { |
|
|
|
return nil |
|
|
|
} |
|
|
|
if !(image.Point{X: x, Y: y}.In(i.Rect)) { |
|
|
|
return image.Transparent |
|
|
|
} |
|
|
|
o := i.PixOffset(x, y) |
|
|
|
q := o / 8 |
|
|
|
r := o % 8 |
|
|
|
if i.Mask[q]&(1<<r) == 0 { |
|
|
|
return color.Transparent |
|
|
|
} |
|
|
|
return i.Palette[i.Pix[o]] |
|
|
|
} |
|
|
|
|
|
|
|
func (i MaskedImage) HasMaskedPixels() bool { |
|
|
|
for _, v := range i.Mask { |
|
|
|
if v != 0xff { |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
return false |
|
|
|
} |
|
|
|
"maze.io/x/dmd/bitmap" |
|
|
|
) |
|
|
|
|
|
|
|
func EncodeToGIF(w io.Writer, a Animation) error { |
|
|
|
g := &gif.GIF{ |
|
|
@ -163,7 +45,7 @@ func toPaletted(i image.Image) *image.Paletted { |
|
|
|
} |
|
|
|
return i |
|
|
|
|
|
|
|
case *MaskedImage: |
|
|
|
case *bitmap.MaskedImage: |
|
|
|
if !i.HasMaskedPixels() { |
|
|
|
return toPaletted(&i.Paletted) |
|
|
|
} |
|
|
|