diff options
Diffstat (limited to 'thumbnailer.go')
| -rw-r--r-- | thumbnailer.go | 159 |
1 files changed, 9 insertions, 150 deletions
diff --git a/thumbnailer.go b/thumbnailer.go index c0d7c9e..cd14316 100644 --- a/thumbnailer.go +++ b/thumbnailer.go @@ -6,8 +6,6 @@ import ( "flag" "fmt" "image" - "image/color" - "image/color/palette" _ "image/gif" _ "image/jpeg" _ "image/png" @@ -24,6 +22,7 @@ import ( _ "golang.org/x/image/tiff" _ "golang.org/x/image/webp" "golang.org/x/sys/unix" + "roseh.moe/pkg/sixel" ) var ( @@ -126,140 +125,14 @@ func load(filename string) (image.Image, error) { return img, nil } -type xtermColor int8 - -func (c xtermColor) RGBA() (r, g, b, a uint32) { - var col color.RGBA - switch c { - 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 { - fmt.Fprintln(w) - } - for x := 0; x < img.Bounds().Dx(); x++ { - hi := img.At(x, y) - if hi == color.Transparent { - fmt.Fprint(w, "\033[49m ") - } else { - lo := 9 - if y+1 < img.Bounds().Dy() && img.At(x, y+1) != color.Transparent { - lo = int(img.At(x, y+1).(xtermColor)) - } - fmt.Fprintf(w, "\033[%dm\033[%dm▀", 30+hi.(xtermColor), 40+lo) - } - } - fmt.Fprint(w, "\033[39m\033[49m") - } -} - -func isFullyTransparent(c color.Color) bool { - _, _, _, a := c.RGBA() - return a == 0 -} - -func printImgBlock24(w io.Writer, img image.Image) { - for y := 0; y < img.Bounds().Dy(); y += 2 { - if y > 0 { - fmt.Fprintln(w) - } - for x := 0; x < img.Bounds().Dx(); x++ { - hi := img.At(x, y) - if isFullyTransparent(hi) { - fmt.Fprint(w, "\033[49m ") - } else { - if y+1 < img.Bounds().Dy() && !isFullyTransparent(img.At(x, y+1)) { - r, g, b, _ := img.At(x, y+1).RGBA() - fmt.Fprintf(w, "\033[48;2;%d;%d;%dm", r>>8, g>>8, b>>8) - } else { - fmt.Fprint(w, "\033[49m") - } - r, g, b, _ := hi.RGBA() - fmt.Fprintf(w, "\033[38;2;%d;%d;%dm▀", r>>8, g>>8, b>>8) - } - } - fmt.Fprint(w, "\033[39m\033[49m") - } -} - -func scale100(c uint32) int { - return int(c) * 100 / 0xffff -} - -func printImgSixel(w io.Writer, img image.PalettedImage) { - fmt.Fprint(w, "\033P7;1q") - 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)) - } - for y := 0; y < img.Bounds().Dy(); y++ { - if y > 0 { - if y%6 == 0 { - fmt.Fprint(w, "-") - } else { - fmt.Fprint(w, "$") - } - } - for x := 0; x < img.Bounds().Dx(); x++ { - c := img.ColorIndexAt(x, y) - if c == 0 { - fmt.Fprint(w, "?") - } else { - char := '?' + 1<<(y%6) - fmt.Fprintf(w, "#%d%c", c-1, char) - } - } - } - fmt.Fprint(w, "\033\\") -} - func printImg(w io.Writer, img image.Image) { switch *m { case modeBlock: - printImgXterm(w, img) + sixel.PrintXTerm16(w, img) case modeBlock24: - printImgBlock24(w, img) + sixel.PrintBlock(w, img) case modeSixel: - printImgSixel(w, img.(image.PalettedImage)) + sixel.Print(w, img) default: panic("invalid mode") } @@ -269,30 +142,19 @@ type pixelAspectRatio struct { x, y int } -func compositeImageRow(images []image.Image, width, padding int, aspectRatio pixelAspectRatio, palette color.Palette) image.Image { +func compositeImageRow(images []image.Image, width, padding int, aspectRatio pixelAspectRatio) image.Image { resultWidth := width*len(images) + padding*(len(images)-1) maxHeight := 0 for _, img := range images { maxHeight = max(maxHeight, img.Bounds().Dy()*width/(img.Bounds().Dx()*aspectRatio.y/aspectRatio.x)) } bounds := image.Rect(0, 0, resultWidth, maxHeight) - var result draw.Image - if len(palette) > 0 { - result = image.NewPaletted(bounds, append([]color.Color{color.Transparent}, palette...)) - } else { - result = image.NewRGBA(bounds) - } + result := image.NewRGBA(bounds) offset := 0 for _, img := range images { height := img.Bounds().Dy() * width / (img.Bounds().Dx() * aspectRatio.y / aspectRatio.x) dstBounds := image.Rect(offset, (maxHeight-height)/2, offset+width, (maxHeight-height)/2+height) - if len(palette) > 0 { - tmp := image.NewRGBA(image.Rect(0, 0, width, height)) - draw.BiLinear.Scale(tmp, tmp.Bounds(), img, img.Bounds(), draw.Src, nil) - draw.FloydSteinberg.Draw(result, dstBounds, tmp, image.Point{}) - } else { - draw.BiLinear.Scale(result, dstBounds, img, img.Bounds(), draw.Src, nil) - } + draw.BiLinear.Scale(result, dstBounds, img, img.Bounds(), draw.Src, nil) offset += width + padding } return result @@ -306,25 +168,22 @@ type img struct { func compositeImages(w io.Writer, images []img, width, imagesPerRow, cellX, cellY int) { imageWidth := width padding := 1 - var colorPalette color.Palette aspectRatio := pixelAspectRatio{1, 1} switch *m { case modeBlock: - colorPalette = xtermPalette - aspectRatio = pixelAspectRatio{2 * cellX, cellY} + aspectRatio = pixelAspectRatio{cellX, cellY} case modeBlock24: aspectRatio = pixelAspectRatio{2 * cellX, cellY} case modeSixel: imageWidth = width * cellX padding = cellX - colorPalette = palette.WebSafe } for row := range slices.Chunk(images, imagesPerRow) { images := make([]image.Image, len(row)) for i, img := range row { images[i] = img.i } - rowImage := compositeImageRow(images, imageWidth, padding, aspectRatio, colorPalette) + rowImage := compositeImageRow(images, imageWidth, padding, aspectRatio) printImg(w, rowImage) names := make([][]string, len(row)) maxLen := 0 |
