about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-09-05 18:55:25 +0200
committerbptato <nincsnevem662@gmail.com>2024-09-05 19:14:40 +0200
commitef5d188e05d4895125ad059f5518f9c8ff83bef5 (patch)
treee57882c92366983491e9ba299e0366cba93c5a6a
parent3d40aced32d7c7ee1c98359ad98f43c11e72fd71 (diff)
downloadchawan-ef5d188e05d4895125ad059f5518f9c8ff83bef5.tar.gz
term: sixel sizing & output fixes
* round down to number divisible by 6 for height
* make pager's dispw match term's dispw even after width clamping
* make *BE procs actually emit/consume big-endian (lol)
* fix borked sixel set raster attributes & control string

I mixed up SRA with the device control string's parameters, so instead
of toggling transparency in the DCS, I was setting the second SRA
parameter to 0. Which, by the way, defines the aspect ratio's
denominator, and has nothing to do with transparency. Whoops.
-rw-r--r--adapter/img/sixel.nim14
-rw-r--r--src/local/pager.nim4
-rw-r--r--src/local/term.nim31
3 files changed, 29 insertions, 20 deletions
diff --git a/adapter/img/sixel.nim b/adapter/img/sixel.nim
index 7f2cdb5d..06a41a89 100644
--- a/adapter/img/sixel.nim
+++ b/adapter/img/sixel.nim
@@ -37,16 +37,16 @@ const DCSSTART = "\eP"
 const ST = "\e\\"
 
 proc setU32BE(s: var string; n: uint32; at: int) =
-  s[at] = char(n and 0xFF)
-  s[at + 1] = char((n shr 8) and 0xFF)
-  s[at + 2] = char((n shr 16) and 0xFF)
-  s[at + 3] = char((n shr 24) and 0xFF)
+  s[at] = char((n shr 24) and 0xFF)
+  s[at + 1] = char((n shr 16) and 0xFF)
+  s[at + 2] = char((n shr 8) and 0xFF)
+  s[at + 3] = char(n and 0xFF)
 
 proc putU32BE(s: var string; n: uint32) =
-  s &= char(n and 0xFF)
-  s &= char((n shr 8) and 0xFF)
-  s &= char((n shr 16) and 0xFF)
   s &= char((n shr 24) and 0xFF)
+  s &= char((n shr 16) and 0xFF)
+  s &= char((n shr 8) and 0xFF)
+  s &= char(n and 0xFF)
 
 type Node {.acyclic.} = ref object
   leaf: bool
diff --git a/src/local/pager.nim b/src/local/pager.nim
index c713d36a..035ec2d7 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -572,8 +572,8 @@ proc initImages(pager: Pager; container: Container) =
       let xpx = (image.x - container.fromx) * pager.attrs.ppc
       offx = -min(xpx, 0)
       let maxwpx = pager.bufWidth * pager.attrs.ppc
-      #TODO this is wrong if term caps sixel width
-      dispw = min(int(image.width) + xpx, maxwpx) - xpx
+      let width = min(image.width - offx, pager.term.sixelMaxWidth) + offx
+      dispw = min(width + xpx, maxwpx) - xpx
       let ypx = (image.y - container.fromy) * pager.attrs.ppl
       erry = -min(ypx, 0) mod 6
     let cached = container.findCachedImage(image, offx, erry, dispw)
diff --git a/src/local/term.nim b/src/local/term.nim
index 29046ade..62f09ac9 100644
--- a/src/local/term.nim
+++ b/src/local/term.nim
@@ -105,7 +105,7 @@ type
     defaultForeground: RGBColor
     ibuf*: string # buffer for chars when we can't process them
     sixelRegisterNum*: int
-    sixelMaxWidth: int
+    sixelMaxWidth*: int
     sixelMaxHeight: int
     kittyId: int # counter for kitty image (*not* placement) ids.
     cursorx: int
@@ -604,6 +604,9 @@ proc applyConfigDimensions(term: Terminal) =
       term.sixelMaxWidth = term.attrs.widthPx
     if term.sixelMaxHeight == 0:
       term.sixelMaxHeight = term.attrs.heightPx
+    # xterm acts weird even if I don't fill in the missing rows, so
+    # just round down instead.
+    term.sixelMaxHeight = (term.sixelMaxHeight div 6) * 6
 
 proc applyConfig(term: Terminal) =
   # colors, formatting
@@ -747,10 +750,10 @@ proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height,
   return nil
 
 func getU32BE(data: openArray[char]; i: int): uint32 =
-  return uint32(data[i]) or
-    (uint32(data[i + 1]) shl 8) or
-    (uint32(data[i + 2]) shl 16) or
-    (uint32(data[i + 3]) shl 24)
+  return uint32(data[i + 3]) or
+    (uint32(data[i + 2]) shl 8) or
+    (uint32(data[i + 1]) shl 16) or
+    (uint32(data[i]) shl 24)
 
 proc outputSixelImage(term: Terminal; x, y: int; image: CanvasImage;
     data: openArray[char]) =
@@ -759,21 +762,27 @@ proc outputSixelImage(term: Terminal; x, y: int; image: CanvasImage;
   let dispw = image.dispw
   let disph = image.disph
   var outs = term.cursorGoto(x, y)
-  outs &= DCSSTART & 'q'
-  # set raster attributes
   let realw = dispw - offx
   let realh = disph - offy
-  # transparent if we want to draw a non-6-divisible number of rows
+  # set transparency if we want to draw a non-6-divisible number
+  # of rows; omit it otherwise, for then some terminals (e.g. foot)
+  # handle the image more efficiently
   let trans = realh mod 6 != 0
-  outs &= "\"1;" & $int(trans) & ";" & $realw & ';' & $realh
+  outs &= DCSSTART & "0;" & $int(trans) & 'q'
+  # set raster attributes
+  outs &= "\"1;1;" & $realw & ';' & $realh
   if data.len < 4: # bounds check
     outs &= ST
     term.write(outs)
     return
-  term.write(outs)
   let sraLen = int(data.getU32BE(0))
   let preludeLen = sraLen + 4
-  term.write(data.toOpenArray(4, 4 + sraLen - 1))
+  if preludeLen > data.len:
+    outs &= ST
+    term.write(outs)
+    return
+  term.write(outs)
+  term.write(data.toOpenArray(4, preludeLen - 1))
   let lookupTableLen = int(data.getU32BE(data.len - 4))
   let L = data.len - lookupTableLen - 4
   # Note: we only crop images when it is possible to do so in near constant