aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2026-05-28 12:50:46 -0700
committerRose Hogenson <rosehogenson@posteo.net>2026-05-28 12:50:46 -0700
commit4cb5012ca2bdac8451cd2d9f27e06fc5e222fddd (patch)
tree32545aca712db54432742423aa57e2b2658114bf
parent9bf6dbe233bfb73fbdd762fee3896a7ea60ad961 (diff)
downloadimgutil-4cb5012ca2bdac8451cd2d9f27e06fc5e222fddd.tar.zst
Better palette support
-rw-r--r--thumbnailer.go115
1 files changed, 45 insertions, 70 deletions
diff --git a/thumbnailer.go b/thumbnailer.go
index 89f9fed..6c69fc1 100644
--- a/thumbnailer.go
+++ b/thumbnailer.go
@@ -126,66 +126,51 @@ func load(filename string) (image.Image, error) {
return img, nil
}
-var (
- xtermBlack = color.RGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff}
- xtermRed = color.RGBA{R: 0xcd, G: 0x00, B: 0x00, A: 0xff}
- xtermGreen = color.RGBA{R: 0x00, G: 0xcd, B: 0x00, A: 0xff}
- xtermYellow = color.RGBA{R: 0xcd, G: 0xcd, B: 0x00, A: 0xff}
- xtermBlue = color.RGBA{R: 0x00, G: 0x00, B: 0xee, A: 0xff}
- xtermMagenta = color.RGBA{R: 0xcd, G: 0x00, B: 0xcd, A: 0xff}
- xtermCyan = color.RGBA{R: 0x00, G: 0xcd, B: 0xcd, A: 0xff}
- xtermWhite = color.RGBA{R: 0xe5, G: 0xe5, B: 0xe5, A: 0xff}
- xtermGray = color.RGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff}
- xtermBrightRed = color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff}
- xtermBrightGreen = color.RGBA{R: 0x00, G: 0xff, B: 0x00, A: 0xff}
- xtermBrightYellow = color.RGBA{R: 0xff, G: 0xff, B: 0x00, A: 0xff}
- xtermBrightBlue = color.RGBA{R: 0x5c, G: 0x5c, B: 0xff, A: 0xff}
- xtermBrightMagenta = color.RGBA{R: 0xff, G: 0x00, B: 0xff, A: 0xff}
- xtermBrightCyan = color.RGBA{R: 0x00, G: 0xff, B: 0xff, A: 0xff}
- xtermBrightWhite = color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}
-)
+type xtermColor int8
-var xtermPalette = color.Palette{xtermBlack, xtermRed, xtermGreen, xtermYellow, xtermBlue, xtermMagenta, xtermCyan, xtermWhite, xtermGray, xtermBrightRed, xtermBrightGreen, xtermBrightYellow, xtermBrightBlue, xtermBrightMagenta, xtermBrightCyan, xtermBrightWhite}
-
-func xtermColorCode(c color.Color) int {
+func (c xtermColor) RGBA() (r, g, b, a uint32) {
+ var col color.RGBA
switch c {
- case xtermBlack:
- return 0
- case xtermRed:
- return 1
- case xtermGreen:
- return 2
- case xtermYellow:
- return 3
- case xtermBlue:
- return 4
- case xtermMagenta:
- return 5
- case xtermCyan:
- return 6
- case xtermWhite:
- return 7
- case xtermGray:
- return 60
- case xtermBrightRed:
- return 61
- case xtermBrightGreen:
- return 62
- case xtermBrightYellow:
- return 63
- case xtermBrightBlue:
- return 64
- case xtermBrightMagenta:
- return 65
- case xtermBrightCyan:
- return 66
- case xtermBrightWhite:
- return 67
+ case 0:
+ col = color.RGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff}
+ case 1:
+ col = color.RGBA{R: 0xcd, G: 0x00, B: 0x00, A: 0xff}
+ case 2:
+ col = color.RGBA{R: 0x00, G: 0xcd, B: 0x00, A: 0xff}
+ case 3:
+ col = color.RGBA{R: 0xcd, G: 0xcd, B: 0x00, A: 0xff}
+ case 4:
+ col = color.RGBA{R: 0x00, G: 0x00, B: 0xee, A: 0xff}
+ case 5:
+ col = color.RGBA{R: 0xcd, G: 0x00, B: 0xcd, A: 0xff}
+ case 6:
+ col = color.RGBA{R: 0x00, G: 0xcd, B: 0xcd, A: 0xff}
+ case 7:
+ col = color.RGBA{R: 0xe5, G: 0xe5, B: 0xe5, A: 0xff}
+ case 60:
+ col = color.RGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff}
+ case 61:
+ col = color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff}
+ case 62:
+ col = color.RGBA{R: 0x00, G: 0xff, B: 0x00, A: 0xff}
+ case 63:
+ col = color.RGBA{R: 0xff, G: 0xff, B: 0x00, A: 0xff}
+ case 64:
+ col = color.RGBA{R: 0x5c, G: 0x5c, B: 0xff, A: 0xff}
+ case 65:
+ col = color.RGBA{R: 0xff, G: 0x00, B: 0xff, A: 0xff}
+ case 66:
+ col = color.RGBA{R: 0x00, G: 0xff, B: 0xff, A: 0xff}
+ case 67:
+ col = color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}
default:
panic("not an xterm color")
}
+ return col.RGBA()
}
+var xtermPalette = color.Palette{xtermColor(0), xtermColor(1), xtermColor(2), xtermColor(3), xtermColor(4), xtermColor(5), xtermColor(6), xtermColor(7), xtermColor(60), xtermColor(61), xtermColor(62), xtermColor(63), xtermColor(64), xtermColor(65), xtermColor(66), xtermColor(67)}
+
func printImgXterm(w io.Writer, img image.Image) {
for y := 0; y < img.Bounds().Dy(); y += 2 {
if y > 0 {
@@ -201,9 +186,9 @@ func printImgXterm(w io.Writer, img image.Image) {
} else {
lo := 9
if y+1 < img.Bounds().Dy() && img.At(x, y+1) != color.Transparent {
- lo = xtermColorCode(img.At(x, y+1))
+ lo = int(img.At(x, y+1).(xtermColor))
}
- fmt.Fprintf(w, "\033[%dm\033[%dm▀", 30+xtermColorCode(hi), 40+lo)
+ fmt.Fprintf(w, "\033[%dm\033[%dm▀", 30+hi.(xtermColor), 40+lo)
}
}
fmt.Fprint(w, "\033[39m\033[49m")
@@ -237,23 +222,13 @@ func printImgBlock24(w io.Writer, img image.Image) {
}
}
-func makePlan9ColorMap() map[color.Color]int {
- m := make(map[color.Color]int)
- for i, c := range palette.Plan9 {
- m[c] = i
- }
- return m
-}
-
-var plan9ColorMap = makePlan9ColorMap()
-
func scale100(c uint32) int {
return int(c) * 100 / 0xffff
}
-func printImgSixel(w io.Writer, img image.Image) {
+func printImgSixel(w io.Writer, img image.PalettedImage) {
fmt.Fprint(w, "\033P7;1q")
- for i, c := range palette.Plan9 {
+ for i, c := range img.ColorModel().(color.Palette)[1:] {
r, g, b, _ := c.RGBA()
fmt.Fprintf(w, "#%d;2;%d;%d;%d", i, scale100(r), scale100(g), scale100(b))
}
@@ -270,7 +245,7 @@ func printImgSixel(w io.Writer, img image.Image) {
fmt.Fprint(w, "?")
} else {
char := '?' + 1<<(y%6)
- fmt.Fprintf(w, "#%d%c", plan9ColorMap[img.At(x, y)], char)
+ fmt.Fprintf(w, "#%d%c", img.ColorIndexAt(x, y)-1, char)
}
}
}
@@ -284,7 +259,7 @@ func printImg(w io.Writer, img image.Image) {
case modeBlock24:
printImgBlock24(w, img)
case modeSixel:
- printImgSixel(w, img)
+ printImgSixel(w, img.(image.PalettedImage))
default:
panic("invalid mode")
}
@@ -342,7 +317,7 @@ func compositeImages(w io.Writer, images []img, width, imagesPerRow, cellX, cell
case modeSixel:
imageWidth = width * cellX
padding = cellX
- colorPalette = palette.Plan9
+ colorPalette = palette.WebSafe
}
for row := range slices.Chunk(images, imagesPerRow) {
images := make([]image.Image, len(row))