diff options
author | bptato <nincsnevem662@gmail.com> | 2024-04-25 01:06:43 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-04-25 01:20:58 +0200 |
commit | 14b871eb7eaf329b67b71385597f114f8782318a (patch) | |
tree | ac7b4655124b4579ad27d56116d9a2dee63cd31e /src/img | |
parent | 62944ac7abc6e37475739a1667ed5a0240fedf66 (diff) | |
download | chawan-14b871eb7eaf329b67b71385597f114f8782318a.tar.gz |
Initial image support
* png: add missing filters, various decoder fixes * term: fix kitty response interpretation, add support for kitty image detection * buffer, pager: initial image display support Emphasis on "initial"; it only "works" with kitty output and PNG input. Also, it's excruciatingly slow, and repaints images way too often. Left undocumented intentionally it for now, until it actually becomes useful. In the meantime, adventurous users can find out themselves why: [[siteconf]] url = "https://.*" images = true
Diffstat (limited to 'src/img')
-rw-r--r-- | src/img/png.nim | 67 |
1 files changed, 49 insertions, 18 deletions
diff --git a/src/img/png.nim b/src/img/png.nim index 7f4d8493..bd7e6206 100644 --- a/src/img/png.nim +++ b/src/img/png.nim @@ -132,8 +132,7 @@ func spp(reader: PNGReader): int = of pcTrueColorWithAlpha: return 4 func scanlen(reader: PNGReader): int {.inline.} = - let w = reader.width + 1 - return (w * reader.spp * int(reader.bitDepth) + 7) div 8 + return 1 + (reader.width * reader.spp * int(reader.bitDepth) + 7) div 8 proc handleError(reader: var PNGReader; msg: string) = #TODO proper error handling? @@ -258,28 +257,55 @@ proc readtRNS(reader: var PNGReader) = for i in 0 ..< reader.palette.len: reader.palette[i].a = reader.readU8() +func paethPredictor(a, b, c: uint16): uint16 = + let pa0 = int(b) - int(c) + let pb0 = int(a) - int(c) + let pa = abs(pa0) + let pb = abs(pb0) + let pc = abs(pa0 + pb0) + return if pa <= pb and pa <= pc: a elif pb <= pc: b else: c + proc unfilter(reader: var PNGReader; irow: openArray[uint8]; bpp: int) = # none, sub, up -> replace uprow directly # average, paeth -> copy to temp array, then replace uprow - let fil = irow[0] - let w = reader.width - case fil + case irow[0] of 0u8: # none - copyMem(addr reader.uprow[0], unsafeAddr irow[1], w) + copyMem(addr reader.uprow[0], unsafeAddr irow[1], irow.len) of 1u8: # sub for i in 1 ..< irow.len: let j = i - 1 # skip filter byte - reader.uprow[j] = irow[i] - if j - bpp >= 0: - reader.uprow[j] += irow[j - bpp] + let aidx = j - bpp + let x = uint16(irow[i]) + let a = if aidx >= 0: uint16(reader.uprow[aidx]) else: 0u16 + reader.uprow[j] = uint8((x + a) and 0xFF) of 2u8: # up for i in 1 ..< irow.len: let j = i - 1 # skip filter byte - reader.uprow[j] += irow[i] + let x = uint16(irow[i]) + let b = uint16(reader.uprow[j]) + reader.uprow[j] = uint8((x + b) and 0xFF) of 3u8: # average - reader.err "average not implemented yet" + for i in 1 ..< irow.len: + let j = i - 1 # skip filter byte + let aidx = j - bpp + let x = uint16(irow[i]) + let a = if aidx >= 0: uint16(reader.uprow[aidx]) else: 0u16 + let b = uint16(reader.uprow[j]) + reader.uprow[j] = uint8((x + (a + b) div 2) and 0xFF) of 4u8: # paeth - reader.err "paeth not implemented yet" + var cmap: array[8, uint16] # max bpp is 16 bit with true color = 4 * 2 + var k = 0 + for i in 1 ..< irow.len: + let j = i - 1 # skip filter byte + let aidx = j - bpp + let x = uint16(irow[i]) + let a = if aidx >= 0: uint16(reader.uprow[aidx]) else: 0u16 + let b = uint16(reader.uprow[j]) + let kk = k mod bpp + let c = cmap[kk] + cmap[kk] = b + reader.uprow[j] = uint8((x + paethPredictor(a, b, c)) and 0xFF) + inc k else: reader.err "got invalid filter" @@ -340,11 +366,16 @@ proc writepxs(reader: var PNGReader; crow: var openArray[RGBAColor]) = crow[x] = rgba(n, n, n, a) of pcTrueColorWithAlpha: let step = int(reader.bitDepth) div 8 + var i = 0 for x in 0 ..< crow.len: - let r = reader.uprow[x * step] - let g = reader.uprow[(x + 1) * step] - let b = reader.uprow[(x + 2) * step] - let a = reader.uprow[(x + 3) * step] + let r = reader.uprow[i] + i += step + let g = reader.uprow[i] + i += step + let b = reader.uprow[i] + i += step + let a = reader.uprow[i] + i += step crow[x] = rgba(r, g, b, a) proc readPLTE(reader: var PNGReader) = @@ -404,10 +435,10 @@ proc readIDAT(reader: var PNGReader) = for y in reader.atline ..< maxline: let yi = y * sl assert yi + sl - 1 < reader.idatAt - reader.unfilter(toOpenArray(reader.idatBuf, yi, yi + sl - 1), bpp) + reader.unfilter(reader.idatBuf.toOpenArray(yi, yi + sl - 1), bpp) if unlikely(reader.bmp == nil): return let yj = y * reader.width - reader.writepxs(toOpenArray(bmp.px, yj, yj + reader.width - 1)) + reader.writepxs(bmp.px.toOpenArray(yj, yj + reader.width - 1)) proc readIEND(reader: var PNGReader) = if reader.i < reader.limit: |