about summary refs log tree commit diff stats
path: root/src/local
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-10-04 16:44:29 +0200
committerbptato <nincsnevem662@gmail.com>2024-10-04 16:58:42 +0200
commit62586dc23790732e66add5b27d4d37f1a56b41e0 (patch)
treeed33d758156658b93f81de6b71449a70ef69d32b /src/local
parentfaa97429d651c76d86ad0c2ab530d9f666fb6927 (diff)
downloadchawan-62586dc23790732e66add5b27d4d37f1a56b41e0.tar.gz
sixel, term: reduce half-dump special casing
Makes it slightly easier to debug image output.

Also, we stop sending dimension headers, and no longer check for the
scheme env var to make CLI invocation a bit less annoying.
Diffstat (limited to 'src/local')
-rw-r--r--src/local/container.nim2
-rw-r--r--src/local/pager.nim10
-rw-r--r--src/local/term.nim47
3 files changed, 37 insertions, 22 deletions
diff --git a/src/local/container.nim b/src/local/container.nim
index bbd90f1e..88becc71 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -124,6 +124,8 @@ type
     erry*: int # same as CanvasImage.offy % 6
     # whether the image has transparency, *disregarding the last row*
     transparent*: bool
+    # length of introducer, raster, palette data before pixel data
+    preludeLen*: int
 
   Container* = ref object of RootObj
     # note: this is not the same as source.request.url (but should be synced
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 09951082..d3b4d860 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -632,8 +632,11 @@ proc loadCachedImage(pager: Pager; container: Container; image: PosBitmap;
       cachedImage.data = blob
       cachedImage.state = cisLoaded
       cachedImage.cacheId = cacheId
-      let trns = response.headers.getOrDefault("Cha-Image-Sixel-Transparent", "0")
-      cachedImage.transparent = trns == "1"
+      cachedImage.transparent =
+        response.headers.getOrDefault("Cha-Image-Sixel-Transparent", "0") == "1"
+      let plens = response.headers.getOrDefault("Cha-Image-Sixel-Prelude-Len")
+      if (let plen = parseInt64(plens).get(0); plen <= int64(int.high)):
+        cachedImage.preludeLen = plen
     )
   )
   container.cachedImages.add(cachedImage)
@@ -665,7 +668,8 @@ proc initImages(pager: Pager; container: Container) =
     let canvasImage = pager.term.loadImage(cached.data, container.process,
       imageId, image.x - container.fromx, image.y - container.fromy,
       image.width, image.height, image.x, image.y, pager.bufWidth,
-      pager.bufHeight, erry, offx, dispw, cached.transparent, redrawNext)
+      pager.bufHeight, erry, offx, dispw, cached.preludeLen, cached.transparent,
+      redrawNext)
     if canvasImage != nil:
       newImages.add(canvasImage)
   pager.term.clearImages(pager.bufHeight)
diff --git a/src/local/term.nim b/src/local/term.nim
index 2550ca69..c984e9d8 100644
--- a/src/local/term.nim
+++ b/src/local/term.nim
@@ -73,7 +73,8 @@ type
     damaged: bool
     marked*: bool
     dead: bool
-    transparent: bool # note: this is only set in outputSixelImage
+    transparent: bool
+    preludeLen: int
     kittyId: int
     # 0 if kitty
     erry: int
@@ -760,7 +761,7 @@ proc checkImageDamage*(term: Terminal; maxw, maxh: int) =
               term.lineDamage[y] = mx
 
 proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height,
-    rx, ry, maxw, maxh, erry, offx, dispw: int; transparent: bool;
+    rx, ry, maxw, maxh, erry, offx, dispw, preludeLen: int; transparent: bool;
     redrawNext: var bool): CanvasImage =
   if (let image = term.findImage(pid, imageId, rx, ry, width, height, erry,
         offx, dispw); image != nil):
@@ -787,7 +788,8 @@ proc loadImage*(term: Terminal; data: Blob; pid, imageId, x, y, width, height,
     width: width,
     height: height,
     erry: erry,
-    transparent: transparent
+    transparent: transparent,
+    preludeLen: preludeLen
   )
   if term.positionImage(image, x, y, maxw, maxh):
     redrawNext = true
@@ -801,6 +803,23 @@ func getU32BE(data: openArray[char]; i: int): uint32 =
     (uint32(data[i + 1]) shl 16) or
     (uint32(data[i]) shl 24)
 
+proc appendSixelAttrs(outs: var string; data: openArray[char];
+    realw, realh: int) =
+  var i = 0
+  while i < data.len:
+    let c = data[i]
+    outs &= c
+    inc i
+    if c == '"': # set raster attrs
+      break
+  while i < data.len and data[i] != '#': # skip aspect ratio attrs
+    inc i
+  outs &= "1;1;" & $realw & ';' & $realh
+  if i < data.len:
+    let ol = outs.len
+    outs.setLen(ol + data.len - i)
+    copyMem(addr outs[ol], unsafeAddr data[i], data.len - i)
+
 proc outputSixelImage(term: Terminal; x, y: int; image: CanvasImage;
     data: openArray[char]) =
   let offx = image.offx
@@ -809,28 +828,18 @@ proc outputSixelImage(term: Terminal; x, y: int; image: CanvasImage;
   let disph = image.disph
   let realw = dispw - offx
   let realh = disph - offy
-  if data.len < 4: # bounds check
+  let preludeLen = image.preludeLen
+  if preludeLen > data.len or data.len < 4:
     return
-  let preludeLen = int(data.getU32BE(0))
-  if preludeLen > data.len:
+  let L = data.len - int(data.getU32BE(data.len - 4)) - 4
+  if L < 0:
     return
   var outs = term.cursorGoto(x, y)
-  # set transparency if the image has transparent sixels; omit it
-  # otherwise, for then some terminals (e.g. foot) handle the image more
-  # efficiently
-  let trans = image.transparent
-  outs &= DCS & "0;" & $int(trans) & "q"
-  # set raster attributes
-  outs &= "\"1;1;" & $realw & ';' & $realh
+  outs.appendSixelAttrs(data.toOpenArray(0, preludeLen - 1), realw, realh)
   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
   # time. Otherwise, the image is re-coded in a cropped form.
-  if preludeLen >= data.len or L < 0: # bounds check
-    term.write(ST)
-  elif realh == image.height: # don't crop
+  if realh == image.height: # don't crop
     term.write(data.toOpenArray(preludeLen, L - 1))
   else:
     let si = preludeLen + int(data.getU32BE(L + (offy div 6) * 4))