about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-04-29 19:42:17 +0200
committerbptato <nincsnevem662@gmail.com>2024-04-29 20:00:10 +0200
commit2680f598c92d99bb41b1f5b99d0baf47c6f26ac4 (patch)
tree89b8ecc1ac0eac8be757b062e75431a203f80c37
parent600974cda52ac2db4e47ca557fccf6ecf048a1bf (diff)
downloadchawan-2680f598c92d99bb41b1f5b99d0baf47c6f26ac4.tar.gz
term: add sixel background color blending
* blend bgcolor with cell color
* do not round up to 6

We don't use the sixel transparency feature because it's useless: sixel
transparency (AFAICT) only lets us respect alpha == 0, but we should
either respect *all* alpha, or no alpha at all.

Since we do color blending, we *do* respect all alpha, but only of
background color.  This sadly means that text under images gets
destroyed, but at least transparent images don't look like garbage.
-rw-r--r--src/local/term.nim28
1 files changed, 19 insertions, 9 deletions
diff --git a/src/local/term.nim b/src/local/term.nim
index 85347f49..b2cc3469 100644
--- a/src/local/term.nim
+++ b/src/local/term.nim
@@ -656,10 +656,10 @@ proc compressSixel(data: openArray[uint8]): string =
   return outs
 
 type SixelBand = object
- c: EightBitColor
+ c: uint8
  data: seq[uint8]
 
-func find(bands: seq[SixelBand]; c: EightBitColor): int =
+func find(bands: seq[SixelBand]; c: uint8): int =
   for i, band in bands:
     if band.c == c:
       return i
@@ -668,7 +668,9 @@ func find(bands: seq[SixelBand]; c: EightBitColor): int =
 proc outputSixelImage(term: Terminal; x, y, offx, offy, dispw, disph: int;
     bmp: Bitmap) =
   var outs = term.cursorGoto(x, y)
-  let hsize = ((disph - offy - 1) div 6 + 1) * 6 # round up to 6
+  #TODO hsize seems to work without rounding on XTerm, idk if it works
+  # everywhere?
+  let hsize = disph - offy
   let wsize = dispw - offx
   outs &= DCSSTART & 'q'
   # set raster attributes
@@ -678,20 +680,28 @@ proc outputSixelImage(term: Terminal; x, y, offx, offy, dispw, disph: int;
     #TODO obviously this produces sub-optimal results
     let rgb = EightBitColor(b).toRGB()
     let rgbq = RGBColor(uint32(rgb).fastmul(100))
-    # 2 is RGB
     let n = b - 15
+    # 2 is RGB
     outs &= '#' & $n & ";2;" & $rgbq.r & ';' & $rgbq.g & ';' & $rgbq.b
   let W = int(dispw) - offx
   var n = offy * int(bmp.width)
   let L = disph * int(bmp.width)
+  let cx0 = offx div term.attrs.ppc
+  let nd = int(bmp.width) * term.attrs.ppl
+  let xd = term.attrs.ppc
   while n < L:
     var bands = newSeq[SixelBand]()
     for i in 0 ..< 6:
-      if n >= bmp.px.len:
+      if n >= L:
         break
+      let cn = n * term.canvas.width div nd
       let mask = 1u8 shl i
       for x in 0 ..< W:
-        let c = RGBColor(bmp.px[n + x + offx]).toEightBit()
+        let cx = cx0 + x div xd
+        let bgcolor0 = term.canvas[cn + cx].format.bgcolor
+        let bgcolor = bgcolor0.getRGB(term.defaultBackground)
+        let c0 = bmp.px[n + x + offx]
+        let c = uint8(RGBColor(bgcolor.blend(c0)).toEightBit())
         if (let j = bands.find(c); j != -1):
           bands[j].data[x] = bands[j].data[x] or mask
         else:
@@ -700,10 +710,10 @@ proc outputSixelImage(term: Terminal; x, y, offx, offy, dispw, disph: int;
       n += int(bmp.width)
     term.write(outs)
     outs = ""
-    for i, line in bands:
+    for i, band in bands:
       let t = if i != bands.high: '$' else: '-'
-      let n = uint8(line.c) - 15
-      outs &= '#' & $n & line.data.compressSixel() & t
+      let n = band.c - 15
+      outs &= '#' & $n & band.data.compressSixel() & t
   if outs.len > 0 and outs[^1] == '-':
     outs.setLen(outs.len - 1)
   outs &= ST