mirror of https://github.com/status-im/nimPNG.git
get rid of method
This commit is contained in:
parent
27df1fe668
commit
fcbc03c724
187
nimPNG.nim
187
nimPNG.nim
|
@ -414,10 +414,7 @@ proc bitDepthAllowed(colorType: PNGColorType, bitDepth: int): bool =
|
||||||
of LCT_PALETTE: result = bitDepth in {1, 2, 4, 8}
|
of LCT_PALETTE: result = bitDepth in {1, 2, 4, 8}
|
||||||
else: result = bitDepth in {8, 16}
|
else: result = bitDepth in {8, 16}
|
||||||
|
|
||||||
method validateChunk(chunk: PNGChunk, png: PNG): bool {.base, gcsafe.} = true
|
proc validateChunk(header: PNGHeader, png: PNG): bool =
|
||||||
method parseChunk(chunk: PNGChunk, png: PNG): bool {.base, gcsafe.} = true
|
|
||||||
|
|
||||||
method validateChunk(header: PNGHeader, png: PNG): bool =
|
|
||||||
if header.width < 1 or header.width > 0x7FFFFFFF:
|
if header.width < 1 or header.width > 0x7FFFFFFF:
|
||||||
raise PNGFatal("image width not allowed: " & $header.width)
|
raise PNGFatal("image width not allowed: " & $header.width)
|
||||||
if header.height < 1 or header.height > 0x7FFFFFFF:
|
if header.height < 1 or header.height > 0x7FFFFFFF:
|
||||||
|
@ -434,7 +431,7 @@ method validateChunk(header: PNGHeader, png: PNG): bool =
|
||||||
raise PNGFatal("unsupported interlace method")
|
raise PNGFatal("unsupported interlace method")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGHeader, png: PNG): bool =
|
proc parseChunk(chunk: PNGHeader, png: PNG): bool =
|
||||||
if chunk.length != 13: return false
|
if chunk.length != 13: return false
|
||||||
chunk.width = chunk.readInt32()
|
chunk.width = chunk.readInt32()
|
||||||
chunk.height = chunk.readInt32()
|
chunk.height = chunk.readInt32()
|
||||||
|
@ -445,7 +442,7 @@ method parseChunk(chunk: PNGHeader, png: PNG): bool =
|
||||||
chunk.interlaceMethod = PNGInterlace(chunk.readByte())
|
chunk.interlaceMethod = PNGInterlace(chunk.readByte())
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGPalette, png: PNG): bool =
|
proc parseChunk(chunk: PNGPalette, png: PNG): bool =
|
||||||
let paletteSize = chunk.length div 3
|
let paletteSize = chunk.length div 3
|
||||||
if paletteSize > 256: raise PNGFatal("palette size to big")
|
if paletteSize > 256: raise PNGFatal("palette size to big")
|
||||||
newSeq(chunk.palette, paletteSize)
|
newSeq(chunk.palette, paletteSize)
|
||||||
|
@ -485,7 +482,7 @@ proc getRawSize(w, h: int, color: PNGColorMode): int =
|
||||||
#proc getRawSizeLct(w, h: int, colorType: PNGColorType, bitDepth: int): int =
|
#proc getRawSizeLct(w, h: int, colorType: PNGColorType, bitDepth: int): int =
|
||||||
# result = (w * h * LCTBPP(colorType, bitDepth) + 7) div 8
|
# result = (w * h * LCTBPP(colorType, bitDepth) + 7) div 8
|
||||||
|
|
||||||
method validateChunk(chunk: PNGData, png: PNG): bool =
|
proc validateChunk(chunk: PNGData, png: PNG): bool =
|
||||||
var header = PNGHeader(png.getChunk(IHDR))
|
var header = PNGHeader(png.getChunk(IHDR))
|
||||||
|
|
||||||
var predict = 0
|
var predict = 0
|
||||||
|
@ -507,13 +504,13 @@ method validateChunk(chunk: PNGData, png: PNG): bool =
|
||||||
if chunk.idat.len != predict: raise PNGFatal("Decompress size doesn't match predict")
|
if chunk.idat.len != predict: raise PNGFatal("Decompress size doesn't match predict")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGData, png: PNG): bool =
|
proc parseChunk(chunk: PNGData, png: PNG): bool =
|
||||||
var nz = nzInflateInit(chunk.data)
|
var nz = nzInflateInit(chunk.data)
|
||||||
nz.ignoreAdler32 = PNGDecoder(png.settings).ignoreAdler32
|
nz.ignoreAdler32 = PNGDecoder(png.settings).ignoreAdler32
|
||||||
chunk.idat = zlib_decompress(nz)
|
chunk.idat = zlib_decompress(nz)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGTrans, png: PNG): bool =
|
proc parseChunk(chunk: PNGTrans, png: PNG): bool =
|
||||||
var header = PNGHeader(png.getChunk(IHDR))
|
var header = PNGHeader(png.getChunk(IHDR))
|
||||||
if header == nil: return false
|
if header == nil: return false
|
||||||
|
|
||||||
|
@ -542,7 +539,7 @@ method parseChunk(chunk: PNGTrans, png: PNG): bool =
|
||||||
|
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGBackground, png: PNG): bool =
|
proc parseChunk(chunk: PNGBackground, png: PNG): bool =
|
||||||
var header = PNGHeader(png.getChunk(IHDR))
|
var header = PNGHeader(png.getChunk(IHDR))
|
||||||
if header.colorType == LCT_PALETTE:
|
if header.colorType == LCT_PALETTE:
|
||||||
# error: this chunk must be 1 byte for indexed color image
|
# error: this chunk must be 1 byte for indexed color image
|
||||||
|
@ -571,7 +568,7 @@ proc initChunk(chunk: PNGChunk, chunkType: PNGChunkType, data: string, crc: uint
|
||||||
chunk.data = data
|
chunk.data = data
|
||||||
chunk.pos = 0
|
chunk.pos = 0
|
||||||
|
|
||||||
method validateChunk(chunk: PNGTime, png: PNG): bool =
|
proc validateChunk(chunk: PNGTime, png: PNG): bool =
|
||||||
if chunk.year < 0 or chunk.year > 65535: raise PNGFatal("invalid year range[0..65535]")
|
if chunk.year < 0 or chunk.year > 65535: raise PNGFatal("invalid year range[0..65535]")
|
||||||
if chunk.month < 1 or chunk.month > 12: raise PNGFatal("invalid month range[1..12]")
|
if chunk.month < 1 or chunk.month > 12: raise PNGFatal("invalid month range[1..12]")
|
||||||
if chunk.day < 1 or chunk.day > 31: raise PNGFatal("invalid day range[1..32]")
|
if chunk.day < 1 or chunk.day > 31: raise PNGFatal("invalid day range[1..32]")
|
||||||
|
@ -581,7 +578,7 @@ method validateChunk(chunk: PNGTime, png: PNG): bool =
|
||||||
if chunk.second < 0 or chunk.second > 60: raise PNGFatal("invalid second range[0..60]")
|
if chunk.second < 0 or chunk.second > 60: raise PNGFatal("invalid second range[0..60]")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGTime, png: PNG): bool =
|
proc parseChunk(chunk: PNGTime, png: PNG): bool =
|
||||||
if chunk.length != 7: raise PNGFatal("tIME must be 7 bytes")
|
if chunk.length != 7: raise PNGFatal("tIME must be 7 bytes")
|
||||||
chunk.year = chunk.readInt16()
|
chunk.year = chunk.readInt16()
|
||||||
chunk.month = chunk.readByte()
|
chunk.month = chunk.readByte()
|
||||||
|
@ -591,19 +588,19 @@ method parseChunk(chunk: PNGTime, png: PNG): bool =
|
||||||
chunk.second = chunk.readByte()
|
chunk.second = chunk.readByte()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGPhys, png: PNG): bool =
|
proc parseChunk(chunk: PNGPhys, png: PNG): bool =
|
||||||
if chunk.length != 9: raise PNGFatal("pHYs must be 9 bytes")
|
if chunk.length != 9: raise PNGFatal("pHYs must be 9 bytes")
|
||||||
chunk.physX = chunk.readInt32()
|
chunk.physX = chunk.readInt32()
|
||||||
chunk.physY = chunk.readInt32()
|
chunk.physY = chunk.readInt32()
|
||||||
chunk.unit = chunk.readByte()
|
chunk.unit = chunk.readByte()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method validateChunk(chunk: PNGText, png: PNG): bool =
|
proc validateChunk(chunk: PNGText, png: PNG): bool =
|
||||||
if(chunk.keyword.len < 1) or (chunk.keyword.len > 79):
|
if(chunk.keyword.len < 1) or (chunk.keyword.len > 79):
|
||||||
raise PNGFatal("keyword too short or too long")
|
raise PNGFatal("keyword too short or too long")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGText, png: PNG): bool =
|
proc parseChunk(chunk: PNGText, png: PNG): bool =
|
||||||
var len = 0
|
var len = 0
|
||||||
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
||||||
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
||||||
|
@ -613,19 +610,19 @@ method parseChunk(chunk: PNGText, png: PNG): bool =
|
||||||
chunk.text = chunk.data.substr(textBegin)
|
chunk.text = chunk.data.substr(textBegin)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method validateChunk(chunk: PNGZtxt, png: PNG): bool =
|
proc validateChunk(chunk: PNGZtxt, png: PNG): bool =
|
||||||
if(chunk.keyword.len < 1) or (chunk.keyword.len > 79):
|
if(chunk.keyword.len < 1) or (chunk.keyword.len > 79):
|
||||||
raise PNGFatal("keyword too short or too long")
|
raise PNGFatal("keyword too short or too long")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGZtxt, png: PNG): bool =
|
proc parseChunk(chunk: PNGZtxt, png: PNG): bool =
|
||||||
var len = 0
|
var len = 0
|
||||||
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
||||||
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
||||||
chunk.keyword = chunk.data.substr(0, len)
|
chunk.keyword = chunk.data.substr(0, len)
|
||||||
|
|
||||||
var compMethod = ord(chunk.data[len + 1]) # skip keyword null terminator
|
var compproc = ord(chunk.data[len + 1]) # skip keyword null terminator
|
||||||
if compMethod != 0: raise PNGFatal("unsupported comp method")
|
if compproc != 0: raise PNGFatal("unsupported comp proc")
|
||||||
|
|
||||||
var nz = nzInflateInit(chunk.data.substr(len + 2))
|
var nz = nzInflateInit(chunk.data.substr(len + 2))
|
||||||
nz.ignoreAdler32 = PNGDecoder(png.settings).ignoreAdler32
|
nz.ignoreAdler32 = PNGDecoder(png.settings).ignoreAdler32
|
||||||
|
@ -633,12 +630,12 @@ method parseChunk(chunk: PNGZtxt, png: PNG): bool =
|
||||||
|
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method validateChunk(chunk: PNGItxt, png: PNG): bool =
|
proc validateChunk(chunk: PNGItxt, png: PNG): bool =
|
||||||
if(chunk.keyword.len < 1) or (chunk.keyword.len > 79):
|
if(chunk.keyword.len < 1) or (chunk.keyword.len > 79):
|
||||||
raise PNGFatal("keyword too short or too long")
|
raise PNGFatal("keyword too short or too long")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGItxt, png: PNG): bool =
|
proc parseChunk(chunk: PNGItxt, png: PNG): bool =
|
||||||
if chunk.length < 5: raise PNGFatal("iTXt len too short")
|
if chunk.length < 5: raise PNGFatal("iTXt len too short")
|
||||||
|
|
||||||
var len = 0
|
var len = 0
|
||||||
|
@ -649,8 +646,8 @@ method parseChunk(chunk: PNGItxt, png: PNG): bool =
|
||||||
chunk.keyword = chunk.data.substr(0, len)
|
chunk.keyword = chunk.data.substr(0, len)
|
||||||
|
|
||||||
var compressed = ord(chunk.data[len + 1]) == 1 # skip keyword null terminator
|
var compressed = ord(chunk.data[len + 1]) == 1 # skip keyword null terminator
|
||||||
var compMethod = ord(chunk.data[len + 2])
|
var compproc = ord(chunk.data[len + 2])
|
||||||
if compMethod != 0: raise PNGFatal("unsupported comp method")
|
if compproc != 0: raise PNGFatal("unsupported comp proc")
|
||||||
|
|
||||||
len = 0
|
len = 0
|
||||||
var i = len + 3
|
var i = len + 3
|
||||||
|
@ -677,12 +674,12 @@ method parseChunk(chunk: PNGItxt, png: PNG): bool =
|
||||||
chunk.text = chunk.data.substr(textBegin)
|
chunk.text = chunk.data.substr(textBegin)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGGamma, png: PNG): bool =
|
proc parseChunk(chunk: PNGGamma, png: PNG): bool =
|
||||||
if chunk.length != 4: raise PNGFatal("invalid gAMA length")
|
if chunk.length != 4: raise PNGFatal("invalid gAMA length")
|
||||||
chunk.gamma = chunk.readInt32()
|
chunk.gamma = chunk.readInt32()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGChroma, png: PNG): bool =
|
proc parseChunk(chunk: PNGChroma, png: PNG): bool =
|
||||||
if chunk.length != 32: raise PNGFatal("invalid Chroma length")
|
if chunk.length != 32: raise PNGFatal("invalid Chroma length")
|
||||||
chunk.whitePointX = chunk.readInt32()
|
chunk.whitePointX = chunk.readInt32()
|
||||||
chunk.whitePointY = chunk.readInt32()
|
chunk.whitePointY = chunk.readInt32()
|
||||||
|
@ -694,31 +691,31 @@ method parseChunk(chunk: PNGChroma, png: PNG): bool =
|
||||||
chunk.blueY = chunk.readInt32()
|
chunk.blueY = chunk.readInt32()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGStandarRGB, png: PNG): bool =
|
proc parseChunk(chunk: PNGStandarRGB, png: PNG): bool =
|
||||||
if chunk.length != 1: raise PNGFatal("invalid sRGB length")
|
if chunk.length != 1: raise PNGFatal("invalid sRGB length")
|
||||||
chunk.renderingIntent = chunk.readByte()
|
chunk.renderingIntent = chunk.readByte()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method validateChunk(chunk: PNGICCProfile, png: PNG): bool =
|
proc validateChunk(chunk: PNGICCProfile, png: PNG): bool =
|
||||||
if(chunk.profileName.len < 1) or (chunk.profileName.len > 79):
|
if(chunk.profileName.len < 1) or (chunk.profileName.len > 79):
|
||||||
raise PNGFatal("keyword too short or too long")
|
raise PNGFatal("keyword too short or too long")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGICCProfile, png: PNG): bool =
|
proc parseChunk(chunk: PNGICCProfile, png: PNG): bool =
|
||||||
var len = 0
|
var len = 0
|
||||||
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
||||||
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
||||||
chunk.profileName = chunk.data.substr(0, len)
|
chunk.profileName = chunk.data.substr(0, len)
|
||||||
|
|
||||||
var compMethod = ord(chunk.data[len + 1]) # skip keyword null terminator
|
var compproc = ord(chunk.data[len + 1]) # skip keyword null terminator
|
||||||
if compMethod != 0: raise PNGFatal("unsupported comp method")
|
if compproc != 0: raise PNGFatal("unsupported comp proc")
|
||||||
|
|
||||||
var nz = nzInflateInit(chunk.data.substr(len + 2))
|
var nz = nzInflateInit(chunk.data.substr(len + 2))
|
||||||
nz.ignoreAdler32 = PNGDecoder(png.settings).ignoreAdler32
|
nz.ignoreAdler32 = PNGDecoder(png.settings).ignoreAdler32
|
||||||
chunk.profile = zlib_decompress(nz)
|
chunk.profile = zlib_decompress(nz)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGSPalette, png: PNG): bool =
|
proc parseChunk(chunk: PNGSPalette, png: PNG): bool =
|
||||||
var len = 0
|
var len = 0
|
||||||
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
while(len < chunk.length) and (chunk.data[len] != chr(0)): inc len
|
||||||
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
if(len < 1) or (len > 79): raise PNGFatal("keyword too short or too long")
|
||||||
|
@ -751,7 +748,7 @@ method parseChunk(chunk: PNGSPalette, png: PNG): bool =
|
||||||
|
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGHist, png: PNG): bool =
|
proc parseChunk(chunk: PNGHist, png: PNG): bool =
|
||||||
if not png.hasChunk(PLTE): raise PNGFatal("Histogram need PLTE")
|
if not png.hasChunk(PLTE): raise PNGFatal("Histogram need PLTE")
|
||||||
var plte = PNGPalette(png.getChunk(PLTE))
|
var plte = PNGPalette(png.getChunk(PLTE))
|
||||||
if plte.palette.len != (chunk.length div 2): raise PNGFatal("invalid histogram length")
|
if plte.palette.len != (chunk.length div 2): raise PNGFatal("invalid histogram length")
|
||||||
|
@ -760,7 +757,7 @@ method parseChunk(chunk: PNGHist, png: PNG): bool =
|
||||||
chunk.histogram[i] = chunk.readInt16()
|
chunk.histogram[i] = chunk.readInt16()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: PNGSbit, png: PNG): bool =
|
proc parseChunk(chunk: PNGSbit, png: PNG): bool =
|
||||||
let header = PNGHEader(png.getChunk(IHDR))
|
let header = PNGHEader(png.getChunk(IHDR))
|
||||||
var expectedLen = 0
|
var expectedLen = 0
|
||||||
|
|
||||||
|
@ -778,12 +775,12 @@ method parseChunk(chunk: PNGSbit, png: PNG): bool =
|
||||||
|
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: APNGAnimationControl, png: PNG): bool =
|
proc parseChunk(chunk: APNGAnimationControl, png: PNG): bool =
|
||||||
chunk.numFrames = chunk.readInt32()
|
chunk.numFrames = chunk.readInt32()
|
||||||
chunk.numPlays = chunk.readInt32()
|
chunk.numPlays = chunk.readInt32()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method parseChunk(chunk: APNGFrameControl, png: PNG): bool =
|
proc parseChunk(chunk: APNGFrameControl, png: PNG): bool =
|
||||||
chunk.sequenceNumber = chunk.readInt32()
|
chunk.sequenceNumber = chunk.readInt32()
|
||||||
chunk.width = chunk.readInt32()
|
chunk.width = chunk.readInt32()
|
||||||
chunk.height = chunk.readInt32()
|
chunk.height = chunk.readInt32()
|
||||||
|
@ -795,7 +792,7 @@ method parseChunk(chunk: APNGFrameControl, png: PNG): bool =
|
||||||
chunk.blendOp = chunk.readByte().APNG_BLEND_OP
|
chunk.blendOp = chunk.readByte().APNG_BLEND_OP
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method validateChunk(chunk: APNGFrameControl, png: PNG): bool =
|
proc validateChunk(chunk: APNGFrameControl, png: PNG): bool =
|
||||||
let header = PNGHEader(png.getChunk(IHDR))
|
let header = PNGHEader(png.getChunk(IHDR))
|
||||||
result = true
|
result = true
|
||||||
result = result and (chunk.xOffset >= 0)
|
result = result and (chunk.xOffset >= 0)
|
||||||
|
@ -805,7 +802,7 @@ method validateChunk(chunk: APNGFrameControl, png: PNG): bool =
|
||||||
result = result and (chunk.xOffset + chunk.width <= header.width)
|
result = result and (chunk.xOffset + chunk.width <= header.width)
|
||||||
result = result and (chunk.yOffset + chunk.height <= header.height)
|
result = result and (chunk.yOffset + chunk.height <= header.height)
|
||||||
|
|
||||||
method parseChunk(chunk: APNGFrameData, png: PNG): bool =
|
proc parseChunk(chunk: APNGFrameData, png: PNG): bool =
|
||||||
chunk.sequenceNumber = chunk.readInt32()
|
chunk.sequenceNumber = chunk.readInt32()
|
||||||
chunk.frameDataPos = chunk.pos
|
chunk.frameDataPos = chunk.pos
|
||||||
result = true
|
result = true
|
||||||
|
@ -872,6 +869,42 @@ proc makePNGDecoder*(): PNGDecoder =
|
||||||
s.ignoreAdler32 = false
|
s.ignoreAdler32 = false
|
||||||
result = s
|
result = s
|
||||||
|
|
||||||
|
proc parseChunk(chunk: PNGChunk, png: PNG): bool =
|
||||||
|
case chunk.chunkType
|
||||||
|
of IHDR: result = parseChunk(PNGHeader(chunk), png)
|
||||||
|
of PLTE: result = parseChunk(PNGPalette(chunk), png)
|
||||||
|
of IDAT: result = parseChunk(PNGData(chunk), png)
|
||||||
|
of tRNS: result = parseChunk(PNGTrans(chunk), png)
|
||||||
|
of bKGD: result = parseChunk(PNGBackground(chunk), png)
|
||||||
|
of tIME: result = parseChunk(PNGTime(chunk), png)
|
||||||
|
of pHYs: result = parseChunk(PNGPhys(chunk), png)
|
||||||
|
of tEXt: result = parseChunk(PNGTExt(chunk), png)
|
||||||
|
of zTXt: result = parseChunk(PNGZtxt(chunk), png)
|
||||||
|
of iTXt: result = parseChunk(PNGItxt(chunk), png)
|
||||||
|
of gAMA: result = parseChunk(PNGGamma(chunk), png)
|
||||||
|
of cHRM: result = parseChunk(PNGChroma(chunk), png)
|
||||||
|
of iCCP: result = parseChunk(PNGICCProfile(chunk), png)
|
||||||
|
of sRGB: result = parseChunk(PNGStandarRGB(chunk), png)
|
||||||
|
of sPLT: result = parseChunk(PNGSPalette(chunk), png)
|
||||||
|
of hIST: result = parseChunk(PNGHist(chunk), png)
|
||||||
|
of sBIT: result = parseChunk(PNGSbit(chunk), png)
|
||||||
|
of acTL: result = parseChunk(APNGAnimationControl(chunk), png)
|
||||||
|
of fcTL: result = parseChunk(APNGFrameControl(chunk), png)
|
||||||
|
of fdAT: result = parseChunk(APNGFrameData(chunk), png)
|
||||||
|
else: result = true
|
||||||
|
|
||||||
|
proc validateChunk(chunk: PNGChunk, png: PNG): bool =
|
||||||
|
case chunk.chunkType
|
||||||
|
of IHDR: result = validateChunk(PNGHeader(chunk), png)
|
||||||
|
of IDAT: result = validateChunk(PNGData(chunk), png)
|
||||||
|
of tIME: result = validateChunk(PNGTime(chunk), png)
|
||||||
|
of tEXt: result = validateChunk(PNGTExt(chunk), png)
|
||||||
|
of zTXt: result = validateChunk(PNGZtxt(chunk), png)
|
||||||
|
of iTXt: result = validateChunk(PNGItxt(chunk), png)
|
||||||
|
of iCCP: result = validateChunk(PNGICCProfile(chunk), png)
|
||||||
|
of fcTL: result = validateChunk(APNGFrameControl(chunk), png)
|
||||||
|
else: result = true
|
||||||
|
|
||||||
proc parsePNG[T](s: Stream, settings: PNGDecoder): PNG[T] =
|
proc parsePNG[T](s: Stream, settings: PNGDecoder): PNG[T] =
|
||||||
var png: PNG[T]
|
var png: PNG[T]
|
||||||
new(png)
|
new(png)
|
||||||
|
@ -936,7 +969,7 @@ proc postProcessScanLines[T](png: PNG; header: PNGHeader, w, h: int; input, outp
|
||||||
# we can immediatly filter into the out buffer, no other steps needed
|
# we can immediatly filter into the out buffer, no other steps needed
|
||||||
unfilter(output, input, w, h, bpp)
|
unfilter(output, input, w, h, bpp)
|
||||||
|
|
||||||
else: # interlace_method is 1 (Adam7)
|
else: # interlace_proc is 1 (Adam7)
|
||||||
var pass: PNGPass
|
var pass: PNGPass
|
||||||
adam7PassValues(pass, w, h, bpp)
|
adam7PassValues(pass, w, h, bpp)
|
||||||
|
|
||||||
|
@ -2070,9 +2103,7 @@ proc writeInt32BE(s: Stream, value: int) =
|
||||||
bigEndian32(addr(tmp), addr(val))
|
bigEndian32(addr(tmp), addr(val))
|
||||||
s.write(tmp)
|
s.write(tmp)
|
||||||
|
|
||||||
method writeChunk(chunk: PNGChunk, png: PNG): bool {.base, gcsafe.} = true
|
proc writeChunk(chunk: PNGHeader, png: PNG): bool =
|
||||||
|
|
||||||
method writeChunk(chunk: PNGHeader, png: PNG): bool =
|
|
||||||
#estimate 13 bytes
|
#estimate 13 bytes
|
||||||
chunk.writeInt32(chunk.width)
|
chunk.writeInt32(chunk.width)
|
||||||
chunk.writeInt32(chunk.height)
|
chunk.writeInt32(chunk.height)
|
||||||
|
@ -2083,7 +2114,7 @@ method writeChunk(chunk: PNGHeader, png: PNG): bool =
|
||||||
chunk.writeByte(int(chunk.interlaceMethod))
|
chunk.writeByte(int(chunk.interlaceMethod))
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGPalette, png: PNG): bool =
|
proc writeChunk(chunk: PNGPalette, png: PNG): bool =
|
||||||
#estimate 3 * palette.len
|
#estimate 3 * palette.len
|
||||||
for px in chunk.palette:
|
for px in chunk.palette:
|
||||||
chunk.writeByte(int(px.r))
|
chunk.writeByte(int(px.r))
|
||||||
|
@ -2091,7 +2122,7 @@ method writeChunk(chunk: PNGPalette, png: PNG): bool =
|
||||||
chunk.writeByte(int(px.b))
|
chunk.writeByte(int(px.b))
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGTrans, png: PNG): bool =
|
proc writeChunk(chunk: PNGTrans, png: PNG): bool =
|
||||||
var header = PNGHeader(png.getChunk(IHDR))
|
var header = PNGHeader(png.getChunk(IHDR))
|
||||||
|
|
||||||
if header.colorType == LCT_PALETTE:
|
if header.colorType == LCT_PALETTE:
|
||||||
|
@ -2116,7 +2147,7 @@ method writeChunk(chunk: PNGTrans, png: PNG): bool =
|
||||||
raise PNGFatal("tRNS chunk not allowed for other color models")
|
raise PNGFatal("tRNS chunk not allowed for other color models")
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGBackground, png: PNG): bool =
|
proc writeChunk(chunk: PNGBackground, png: PNG): bool =
|
||||||
var header = PNGHeader(png.getChunk(IHDR))
|
var header = PNGHeader(png.getChunk(IHDR))
|
||||||
if header.colorType == LCT_PALETTE:
|
if header.colorType == LCT_PALETTE:
|
||||||
#estimate 1 bytes
|
#estimate 1 bytes
|
||||||
|
@ -2131,7 +2162,7 @@ method writeChunk(chunk: PNGBackground, png: PNG): bool =
|
||||||
chunk.writeInt16(chunk.bkgdB)
|
chunk.writeInt16(chunk.bkgdB)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGTime, png: PNG): bool =
|
proc writeChunk(chunk: PNGTime, png: PNG): bool =
|
||||||
#estimate 7 bytes
|
#estimate 7 bytes
|
||||||
chunk.writeInt16(chunk.year)
|
chunk.writeInt16(chunk.year)
|
||||||
chunk.writeByte(chunk.month)
|
chunk.writeByte(chunk.month)
|
||||||
|
@ -2141,26 +2172,26 @@ method writeChunk(chunk: PNGTime, png: PNG): bool =
|
||||||
chunk.writeByte(chunk.second)
|
chunk.writeByte(chunk.second)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGPhys, png: PNG): bool =
|
proc writeChunk(chunk: PNGPhys, png: PNG): bool =
|
||||||
#estimate 9 bytes
|
#estimate 9 bytes
|
||||||
chunk.writeInt32(chunk.physX)
|
chunk.writeInt32(chunk.physX)
|
||||||
chunk.writeInt32(chunk.physY)
|
chunk.writeInt32(chunk.physY)
|
||||||
chunk.writeByte(chunk.unit)
|
chunk.writeByte(chunk.unit)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGText, png: PNG): bool =
|
proc writeChunk(chunk: PNGText, png: PNG): bool =
|
||||||
#estimate chunk.keyword.len + chunk.text.len + 1
|
#estimate chunk.keyword.len + chunk.text.len + 1
|
||||||
chunk.writeString chunk.keyword
|
chunk.writeString chunk.keyword
|
||||||
chunk.writeByte 0 #null separator
|
chunk.writeByte 0 #null separator
|
||||||
chunk.writeString chunk.text
|
chunk.writeString chunk.text
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGGamma, png: PNG): bool =
|
proc writeChunk(chunk: PNGGamma, png: PNG): bool =
|
||||||
#estimate 4 bytes
|
#estimate 4 bytes
|
||||||
chunk.writeInt32(chunk.gamma)
|
chunk.writeInt32(chunk.gamma)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGChroma, png: PNG): bool =
|
proc writeChunk(chunk: PNGChroma, png: PNG): bool =
|
||||||
#estimate 8 * 4 bytes
|
#estimate 8 * 4 bytes
|
||||||
chunk.writeInt32(chunk.whitePointX)
|
chunk.writeInt32(chunk.whitePointX)
|
||||||
chunk.writeInt32(chunk.whitePointY)
|
chunk.writeInt32(chunk.whitePointY)
|
||||||
|
@ -2172,12 +2203,12 @@ method writeChunk(chunk: PNGChroma, png: PNG): bool =
|
||||||
chunk.writeInt32(chunk.blueY)
|
chunk.writeInt32(chunk.blueY)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGStandarRGB, png: PNG): bool =
|
proc writeChunk(chunk: PNGStandarRGB, png: PNG): bool =
|
||||||
#estimate 1 byte
|
#estimate 1 byte
|
||||||
chunk.writeByte(chunk.renderingIntent)
|
chunk.writeByte(chunk.renderingIntent)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGSPalette, png: PNG): bool =
|
proc writeChunk(chunk: PNGSPalette, png: PNG): bool =
|
||||||
#estimate chunk.paletteName.len + 2
|
#estimate chunk.paletteName.len + 2
|
||||||
#if sampleDepth == 8: estimate += chunk.palette.len * 6
|
#if sampleDepth == 8: estimate += chunk.palette.len * 6
|
||||||
#else: estimate += chunk.palette.len * 10
|
#else: estimate += chunk.palette.len * 10
|
||||||
|
@ -2202,29 +2233,27 @@ method writeChunk(chunk: PNGSPalette, png: PNG): bool =
|
||||||
chunk.writeInt16(p.frequency)
|
chunk.writeInt16(p.frequency)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGHist, png: PNG): bool =
|
proc writeChunk(chunk: PNGHist, png: PNG): bool =
|
||||||
#estimate chunk.histogram.len * 2
|
#estimate chunk.histogram.len * 2
|
||||||
for c in chunk.histogram:
|
for c in chunk.histogram:
|
||||||
chunk.writeInt16 c
|
chunk.writeInt16 c
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGData, png: PNG): bool =
|
proc writeChunk(chunk: PNGData, png: PNG): bool =
|
||||||
var nz = nzDeflateInit(chunk.idat)
|
var nz = nzDeflateInit(chunk.idat)
|
||||||
chunk.data = zlib_compress(nz)
|
chunk.data = zlib_compress(nz)
|
||||||
debugEcho "IDAT.IDAT: ", chunk.idat.len
|
|
||||||
debugEcho "IDAT.DATA: ", chunk.data.len
|
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGZtxt, png: PNG): bool =
|
proc writeChunk(chunk: PNGZtxt, png: PNG): bool =
|
||||||
#estimate chunk.keyword.len + 2
|
#estimate chunk.keyword.len + 2
|
||||||
chunk.writeString chunk.keyword
|
chunk.writeString chunk.keyword
|
||||||
chunk.writeByte 0 #null separator
|
chunk.writeByte 0 #null separator
|
||||||
chunk.writeByte 0 #compression method(0: deflate)
|
chunk.writeByte 0 #compression proc(0: deflate)
|
||||||
var nz = nzDeflateInit(chunk.text)
|
var nz = nzDeflateInit(chunk.text)
|
||||||
chunk.writeString zlib_compress(nz)
|
chunk.writeString zlib_compress(nz)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGItxt, png: PNG): bool =
|
proc writeChunk(chunk: PNGItxt, png: PNG): bool =
|
||||||
#estimate chunk.keyword.len + 2
|
#estimate chunk.keyword.len + 2
|
||||||
# + chunk.languageTag.len + chunk.translatedKeyword.len
|
# + chunk.languageTag.len + chunk.translatedKeyword.len
|
||||||
let state = PNGEncoder(png.settings)
|
let state = PNGEncoder(png.settings)
|
||||||
|
@ -2246,7 +2275,7 @@ method writeChunk(chunk: PNGItxt, png: PNG): bool =
|
||||||
chunk.writeString chunk.keyword
|
chunk.writeString chunk.keyword
|
||||||
chunk.writeByte 0 #null separator
|
chunk.writeByte 0 #null separator
|
||||||
chunk.writeByte compressed #compression flag(0: uncompressed, 1: compressed)
|
chunk.writeByte compressed #compression flag(0: uncompressed, 1: compressed)
|
||||||
chunk.writeByte 0 #compression method(0: deflate)
|
chunk.writeByte 0 #compression proc(0: deflate)
|
||||||
chunk.writeString chunk.languageTag
|
chunk.writeString chunk.languageTag
|
||||||
chunk.writeByte 0 #null separator
|
chunk.writeByte 0 #null separator
|
||||||
chunk.writeString chunk.translatedKeyword
|
chunk.writeString chunk.translatedKeyword
|
||||||
|
@ -2254,22 +2283,22 @@ method writeChunk(chunk: PNGItxt, png: PNG): bool =
|
||||||
chunk.writeString text
|
chunk.writeString text
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: PNGICCProfile, png: PNG): bool =
|
proc writeChunk(chunk: PNGICCProfile, png: PNG): bool =
|
||||||
#estimate chunk.profileName.len + 2
|
#estimate chunk.profileName.len + 2
|
||||||
chunk.writeString chunk.profileName
|
chunk.writeString chunk.profileName
|
||||||
chunk.writeByte 0 #null separator
|
chunk.writeByte 0 #null separator
|
||||||
chunk.writeByte 0 #compression method(0: deflate)
|
chunk.writeByte 0 #compression proc(0: deflate)
|
||||||
var nz = nzDeflateInit(chunk.profile)
|
var nz = nzDeflateInit(chunk.profile)
|
||||||
chunk.writeString zlib_compress(nz)
|
chunk.writeString zlib_compress(nz)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: APNGAnimationControl, png: PNG): bool =
|
proc writeChunk(chunk: APNGAnimationControl, png: PNG): bool =
|
||||||
# estimate 8 bytes
|
# estimate 8 bytes
|
||||||
chunk.writeInt32(chunk.numFrames)
|
chunk.writeInt32(chunk.numFrames)
|
||||||
chunk.writeInt32(chunk.numPlays)
|
chunk.writeInt32(chunk.numPlays)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: APNGFrameControl, png: PNG): bool =
|
proc writeChunk(chunk: APNGFrameControl, png: PNG): bool =
|
||||||
# estimate 5*4 + 2*2 + 2 = 26 bytes
|
# estimate 5*4 + 2*2 + 2 = 26 bytes
|
||||||
chunk.writeInt32(chunk.sequenceNumber)
|
chunk.writeInt32(chunk.sequenceNumber)
|
||||||
chunk.writeInt32(chunk.width)
|
chunk.writeInt32(chunk.width)
|
||||||
|
@ -2282,12 +2311,36 @@ method writeChunk(chunk: APNGFrameControl, png: PNG): bool =
|
||||||
chunk.writeByte(ord(chunk.blendOp))
|
chunk.writeByte(ord(chunk.blendOp))
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
method writeChunk(chunk: APNGFrameData, png: PNG): bool =
|
proc writeChunk(chunk: APNGFrameData, png: PNG): bool =
|
||||||
chunk.writeInt32(chunk.sequenceNumber)
|
chunk.writeInt32(chunk.sequenceNumber)
|
||||||
var nz = nzDeflateInit(png.apngPixels[chunk.frameDataPos])
|
var nz = nzDeflateInit(png.apngPixels[chunk.frameDataPos])
|
||||||
chunk.writeString zlib_compress(nz)
|
chunk.writeString zlib_compress(nz)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
proc writeChunk(chunk: PNGChunk, png: PNG): bool =
|
||||||
|
case chunk.chunkType
|
||||||
|
of IHDR: result = writeChunk(PNGHeader(chunk), png)
|
||||||
|
of PLTE: result = writeChunk(PNGPalette(chunk), png)
|
||||||
|
of IDAT: result = writeChunk(PNGData(chunk), png)
|
||||||
|
of tRNS: result = writeChunk(PNGTrans(chunk), png)
|
||||||
|
of bKGD: result = writeChunk(PNGBackground(chunk), png)
|
||||||
|
of tIME: result = writeChunk(PNGTime(chunk), png)
|
||||||
|
of pHYs: result = writeChunk(PNGPhys(chunk), png)
|
||||||
|
of tEXt: result = writeChunk(PNGTExt(chunk), png)
|
||||||
|
of zTXt: result = writeChunk(PNGZtxt(chunk), png)
|
||||||
|
of iTXt: result = writeChunk(PNGItxt(chunk), png)
|
||||||
|
of gAMA: result = writeChunk(PNGGamma(chunk), png)
|
||||||
|
of cHRM: result = writeChunk(PNGChroma(chunk), png)
|
||||||
|
of iCCP: result = writeChunk(PNGICCProfile(chunk), png)
|
||||||
|
of sRGB: result = writeChunk(PNGStandarRGB(chunk), png)
|
||||||
|
of sPLT: result = writeChunk(PNGSPalette(chunk), png)
|
||||||
|
of hIST: result = writeChunk(PNGHist(chunk), png)
|
||||||
|
of sBIT: result = writeChunk(PNGSbit(chunk), png)
|
||||||
|
of acTL: result = writeChunk(APNGAnimationControl(chunk), png)
|
||||||
|
of fcTL: result = writeChunk(APNGFrameControl(chunk), png)
|
||||||
|
of fdAT: result = writeChunk(APNGFrameData(chunk), png)
|
||||||
|
else: result = true
|
||||||
|
|
||||||
proc isGreyscaleType(mode: PNGColorMode): bool =
|
proc isGreyscaleType(mode: PNGColorMode): bool =
|
||||||
result = mode.colorType in {LCT_GREY, LCT_GREY_ALPHA}
|
result = mode.colorType in {LCT_GREY, LCT_GREY_ALPHA}
|
||||||
|
|
||||||
|
@ -2502,7 +2555,7 @@ proc autoChooseColor(png: PNG, modeOut, modeIn: PNGColorMode) =
|
||||||
modeOut.keyDefined = true
|
modeOut.keyDefined = true
|
||||||
|
|
||||||
proc filter[T](output: var openArray[T], input: openArray[T], w, h: int, modeOut: PNGColorMode, state: PNGEncoder) =
|
proc filter[T](output: var openArray[T], input: openArray[T], w, h: int, modeOut: PNGColorMode, state: PNGEncoder) =
|
||||||
# For PNG filter method 0
|
# For PNG filter proc 0
|
||||||
# out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
|
# out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
|
||||||
# the scanlines with 1 extra byte per scanline
|
# the scanlines with 1 extra byte per scanline
|
||||||
|
|
||||||
|
@ -2886,8 +2939,8 @@ proc writeChunks*[T](png: PNG[T], s: Stream) =
|
||||||
s.write PNGSignature
|
s.write PNGSignature
|
||||||
|
|
||||||
for chunk in png.chunks:
|
for chunk in png.chunks:
|
||||||
if not chunk.validateChunk(png): raise PNGFatal("combine chunk validation error")
|
if not chunk.validateChunk(png): raise PNGFatal("combine chunk validation error " & $chunk.chunkType)
|
||||||
if not chunk.writeChunk(png): raise PNGFatal("combine chunk write error")
|
if not chunk.writeChunk(png): raise PNGFatal("combine chunk write error " & $chunk.chunkType)
|
||||||
chunk.length = chunk.data.len
|
chunk.length = chunk.data.len
|
||||||
chunk.crc = crc32(crc32(0, $chunk.chunkType), chunk.data)
|
chunk.crc = crc32(crc32(0, $chunk.chunkType), chunk.data)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue