tmp jpeg fix

This commit is contained in:
Ryan Oldenburg 2022-07-26 22:36:43 -05:00
parent 0ad674fc29
commit fd1b02dd24

View file

@ -59,7 +59,7 @@ type
widthCoeff, heightCoeff: int
coeff, lineBuf: seq[uint8]
blocks: seq[seq[array[64, int16]]]
channel: seq[uint8]
channel: Mask
DecoderState = object
buffer: ptr UncheckedArray[uint8]
@ -84,9 +84,46 @@ type
eobRun: int
hitEnd: bool
Mask = ref object
## Mask object that holds mask opacity data.
width*, height*: int
data*: seq[uint8]
UnsafeMask = distinct Mask
when defined(release):
{.push checks: off.}
proc newMask(width, height: int): Mask {.raises: [PixieError].} =
## Creates a new mask with the parameter dimensions.
if width <= 0 or height <= 0:
raise newException(PixieError, "Mask width and height must be > 0")
result = Mask()
result.width = width
result.height = height
result.data = newSeq[uint8](width * height)
template dataIndex(mask: Mask, x, y: int): int =
mask.width * y + x
template unsafe(src: Mask): UnsafeMask =
cast[UnsafeMask](src)
template `[]`(view: UnsafeMask, x, y: int): uint8 =
## Gets a value from (x, y) coordinates.
## * No bounds checking *
## Make sure that x, y are in bounds.
## Failure in the assumptions will case unsafe memory reads.
cast[Mask](view).data[cast[Mask](view).dataIndex(x, y)]
template `[]=`(view: UnsafeMask, x, y: int, color: uint8) =
## Sets a value from (x, y) coordinates.
## * No bounds checking *
## Make sure that x, y are in bounds.
## Failure in the assumptions will case unsafe memory writes.
cast[Mask](view).data[cast[Mask](view).dataIndex(x, y)] = color
template failInvalid(reason = "unable to load") =
## Throw exception with a reason.
raise newException(PixieError, "Invalid JPEG, " & reason)
@ -321,8 +358,7 @@ proc decodeSOF0(state: var DecoderState) =
component.widthStride = state.numMcuWide * component.yScale * 8
component.heightStride = state.numMcuHigh * component.xScale * 8
component.channel =
newSeq[uint8](component.widthStride * component.heightStride)
component.channel = newMask(component.widthStride, component.heightStride)
if state.progressive:
component.widthCoeff = component.widthStride div 8
@ -813,14 +849,14 @@ proc idctBlock(component: var Component, offset: int, data: array[64, int16]) =
x2 += 65536 + (128 shl 17)
x3 += 65536 + (128 shl 17)
component.channel[outPos + 0] = clampByte((x0 + t3) shr 17)
component.channel[outPos + 7] = clampByte((x0 - t3) shr 17)
component.channel[outPos + 1] = clampByte((x1 + t2) shr 17)
component.channel[outPos + 6] = clampByte((x1 - t2) shr 17)
component.channel[outPos + 2] = clampByte((x2 + t1) shr 17)
component.channel[outPos + 5] = clampByte((x2 - t1) shr 17)
component.channel[outPos + 3] = clampByte((x3 + t0) shr 17)
component.channel[outPos + 4] = clampByte((x3 - t0) shr 17)
component.channel.data[outPos + 0] = clampByte((x0 + t3) shr 17)
component.channel.data[outPos + 7] = clampByte((x0 - t3) shr 17)
component.channel.data[outPos + 1] = clampByte((x1 + t2) shr 17)
component.channel.data[outPos + 6] = clampByte((x1 - t2) shr 17)
component.channel.data[outPos + 2] = clampByte((x2 + t1) shr 17)
component.channel.data[outPos + 5] = clampByte((x2 - t1) shr 17)
component.channel.data[outPos + 3] = clampByte((x3 + t0) shr 17)
component.channel.data[outPos + 4] = clampByte((x3 - t0) shr 17)
{.pop.}
@ -902,59 +938,45 @@ proc quantizationAndIDCTPass(state: var DecoderState) =
data
)
template dataIndex(component: var Component, x, y: int): int =
component.widthStride * y + x
template `[]`*(component: Component, x, y: int): uint8 =
component.channel[component.dataIndex(x, y)]
proc magnifyXBy2(component: var Component) =
proc magnifyXBy2(mask: Mask): Mask =
## Smooth magnify by power of 2 only in the X direction.
var magnified =
newSeq[uint8](component.widthStride * 2 * component.heightStride)
for y in 0 ..< component.heightStride:
for x in 0 ..< component.widthStride:
let n = 3 * component[x, y].uint16
result = newMask(mask.width * 2, mask.height)
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
let n = 3 * mask.unsafe[x, y].uint16
if x == 0:
magnified[component.dataIndex(x * 2 + 0, y)] = component[x, y]
magnified[component.dataIndex(x * 2 + 1, y)] =
((n + component[x + 1, y].uint16 + 2) div 4).uint8
elif x == component.widthStride - 1:
magnified[component.dataIndex(x * 2 + 0, y)] =
((n + component[x - 1, y].uint16 + 2) div 4).uint8
magnified[component.dataIndex(x * 2 + 1, y)] = component[x, y]
result.unsafe[x * 2 + 0, y] = mask.unsafe[x, y]
result.unsafe[x * 2 + 1, y] =
((n + mask.unsafe[x + 1, y].uint16 + 2) div 4).uint8
elif x == mask.width - 1:
result.unsafe[x * 2 + 0, y] =
((n + mask.unsafe[x - 1, y].uint16 + 2) div 4).uint8
result.unsafe[x * 2 + 1, y] = mask.unsafe[x, y]
else:
magnified[component.dataIndex(x * 2 + 0, y)] =
((n + component[x - 1, y].uint16) div 4).uint8
magnified[component.dataIndex(x * 2 + 1, y)] =
((n + component[x + 1, y].uint16) div 4).uint8
result.unsafe[x * 2 + 0, y] =
((n + mask.unsafe[x - 1, y].uint16) div 4).uint8
result.unsafe[x * 2 + 1, y] =
((n + mask.unsafe[x + 1, y].uint16) div 4).uint8
component.channel = move magnified
component.widthStride *= 2
proc magnifyYBy2(component: var Component) =
proc magnifyYBy2(mask: Mask): Mask =
## Smooth magnify by power of 2 only in the Y direction.
var magnified =
newSeq[uint8](component.widthStride * component.heightStride * 2)
for y in 0 ..< component.heightStride:
for x in 0 ..< component.widthStride:
let n = 3 * component[x, y].uint16
result = newMask(mask.width, mask.height * 2)
for y in 0 ..< mask.height:
for x in 0 ..< mask.width:
let n = 3 * mask.unsafe[x, y].uint16
if y == 0:
magnified[component.dataIndex(x, y * 2 + 0)] = component[x, y]
magnified[component.dataIndex(x, y * 2 + 1)] =
((n + component[x, y + 1].uint16 + 2) div 4).uint8
elif y == component.heightStride - 1:
magnified[component.dataIndex(x, y * 2 + 0)] =
((n + component[x, y - 1].uint16 + 2) div 4).uint8
magnified[component.dataIndex(x, y * 2 + 1)] = component[x, y]
result.unsafe[x, y * 2 + 0] = mask.unsafe[x, y]
result.unsafe[x, y * 2 + 1] =
((n + mask.unsafe[x, y + 1].uint16 + 2) div 4).uint8
elif y == mask.height - 1:
result.unsafe[x, y * 2 + 0] =
((n + mask.unsafe[x, y - 1].uint16 + 2) div 4).uint8
result.unsafe[x, y * 2 + 1] = mask.unsafe[x, y]
else:
magnified[component.dataIndex(x, y * 2 + 0)] =
((n + component[x, y - 1].uint16) div 4).uint8
magnified[component.dataIndex(x, y * 2 + 1)] =
((n + component[x, y + 1].uint16) div 4).uint8
component.channel = move magnified
component.heightStride *= 2
result.unsafe[x, y * 2 + 0] =
((n + mask.unsafe[x, y - 1].uint16) div 4).uint8
result.unsafe[x, y * 2 + 1] =
((n + mask.unsafe[x, y + 1].uint16) div 4).uint8
proc yCbCrToRgbx(py, pcb, pcr: uint8): ColorRGBX =
## Takes a 3 component yCbCr outputs and populates image.
@ -989,29 +1011,33 @@ proc buildImage(state: var DecoderState): Image =
of 3:
for component in state.components.mitems:
while component.yScale < state.maxYScale:
component.magnifyXBy2()
component.channel = component.channel.magnifyXBy2()
component.yScale *= 2
while component.xScale < state.maxXScale:
component.magnifyYBy2()
component.channel = component.channel.magnifyYBy2()
component.xScale *= 2
let
cy = state.components[0].channel
cb = state.components[1].channel
cr = state.components[2].channel
for y in 0 ..< state.imageHeight:
var channelIndex = state.components[0].dataIndex(0, y)
var channelIndex = cy.dataIndex(0, y)
for x in 0 ..< state.imageWidth:
result.unsafe[x, y] = yCbCrToRgbx(
state.components[0].channel[channelIndex], # cy
state.components[1].channel[channelIndex], # cb
state.components[2].channel[channelIndex], # cr
cy.data[channelIndex],
cb.data[channelIndex],
cr.data[channelIndex],
)
inc channelIndex
of 1:
let cy = state.components[0].channel
for y in 0 ..< state.imageHeight:
var channelIndex = state.components[0].dataIndex(0, y)
var channelIndex = cy.dataIndex(0, y)
for x in 0 ..< state.imageWidth:
result.unsafe[x, y] =
grayScaleToRgbx(state.components[0].channel[channelIndex]) # cy
result.unsafe[x, y] = grayScaleToRgbx(cy.data[channelIndex])
inc channelIndex
else: