diff options
author | oehhar <harald.oehlmann@elmicron.de> | 2020-06-22 21:20:04 (GMT) |
---|---|---|
committer | oehhar <harald.oehlmann@elmicron.de> | 2020-06-22 21:20:04 (GMT) |
commit | b39239f7ef80426cf1583b625f0ab22f94666c2a (patch) | |
tree | 08cf6df8e0c65269b34203d44f06b5faf911dd73 /generic/tkImgPNG.c | |
parent | 3f0bcf5127f3f554341d43576f656162f4cf5101 (diff) | |
download | tk-b39239f7ef80426cf1583b625f0ab22f94666c2a.zip tk-b39239f7ef80426cf1583b625f0ab22f94666c2a.tar.gz tk-b39239f7ef80426cf1583b625f0ab22f94666c2a.tar.bz2 |
TIP529 image metadata: read png DPI and aspect metadata
Diffstat (limited to 'generic/tkImgPNG.c')
-rw-r--r-- | generic/tkImgPNG.c | 166 |
1 files changed, 165 insertions, 1 deletions
diff --git a/generic/tkImgPNG.c b/generic/tkImgPNG.c index 669bc27..af0684e 100644 --- a/generic/tkImgPNG.c +++ b/generic/tkImgPNG.c @@ -175,6 +175,15 @@ typedef struct { Tcl_Obj *thisLineObj; /* Current line of pixels to process. */ int lineSize; /* Number of bytes in a PNG line. */ int phaseSize; /* Number of bytes/line in current phase. */ + + + /* + * Physical size: pHYS chunks. + */ + + double DPI; + double aspect; + } PNGImage; /* @@ -355,6 +364,13 @@ InitPNGImage( } return TCL_ERROR; } + + /* + * Initialize physical size pHYS values + */ + + pngPtr->DPI = -1; + pngPtr->aspect = -1; return TCL_OK; } @@ -944,6 +960,7 @@ ReadChunkHeader( case CHUNK_IDAT: case CHUNK_IEND: case CHUNK_IHDR: + case CHUNK_pHYs: case CHUNK_PLTE: case CHUNK_tRNS: break; @@ -962,7 +979,6 @@ ReadChunkHeader( case CHUNK_iTXt: case CHUNK_oFFs: case CHUNK_pCAL: - case CHUNK_pHYs: case CHUNK_sBIT: case CHUNK_sCAL: case CHUNK_sPLT: @@ -1654,6 +1670,84 @@ ReadTRNS( /* *---------------------------------------------------------------------- * + * ReadPHYS -- + * + * This function reads the PHYS (physical size) chunk data from + * the PNG file and populates the fields in the PNGImage + * structure. + * + * Results: + * TCL_OK, or TCL_ERROR if an I/O error occurs or the PHYS chunk is + * invalid. + * + * Side effects: + * The access position in f advances. + * + *---------------------------------------------------------------------- + */ + +static int +ReadPHYS( + Tcl_Interp *interp, + PNGImage *pngPtr, + int chunkSz, + unsigned long crc) +{ + unsigned long PPUx, PPUy; + char unitSpecifier; + + /* + * Check chunk size equal 9 bytes + */ + + if (chunkSz != 9) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "invalid physical chunk size", -1)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_PHYS", NULL); + return TCL_ERROR; + } + + /* + * Read the chunk data + * 4 bytes: Pixels per unit, x axis + * 4 bytes: Pixels per unit, y axis + * 1 byte: unit specifier + */ + + if (ReadInt32(interp, pngPtr, &PPUx, &crc) == TCL_ERROR) { + return TCL_ERROR; + } + if (ReadInt32(interp, pngPtr, &PPUy, &crc) == TCL_ERROR) { + return TCL_ERROR; + } + if (ReadData(interp, pngPtr, &unitSpecifier, 1, &crc) == TCL_ERROR) { + return TCL_ERROR; + } + + if (CheckCRC(interp, pngPtr, crc) == TCL_ERROR) { + return TCL_ERROR; + } + + if ( PPUx > 2147483647 || PPUy > 2147483647 + || unitSpecifier > 1 ) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "invalid physical size value", -1)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_PHYS", NULL); + return TCL_ERROR; + } + + if (PPUx > 0) { + pngPtr->aspect = ((double) PPUy) / ((double) PPUx); + } + if (1 == unitSpecifier) { + pngPtr->DPI = ((double) PPUx) * 0.0254; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * Paeth -- * * Utility function for applying the Paeth filter to a pixel. The Paeth @@ -2426,6 +2520,29 @@ DecodePNG( return TCL_ERROR; } + /* + * Physical header may be present here so try to parse it + */ + + if (CHUNK_pHYs == chunkType) { + /* + * Finish parsing the PHYS chunk. + */ + + if (ReadPHYS(interp, pngPtr, chunkSz, crc) == TCL_ERROR) { + return TCL_ERROR; + } + + /* + * Begin the next chunk. + */ + + if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType, + &crc) == TCL_ERROR) { + return TCL_ERROR; + } + } + if (CHUNK_PLTE == chunkType) { /* * Finish parsing the PLTE chunk. @@ -2477,6 +2594,29 @@ DecodePNG( } /* + * Physical header may be present here so try to parse it + */ + + if (CHUNK_pHYs == chunkType) { + /* + * Finish parsing the PHYS chunk. + */ + + if (ReadPHYS(interp, pngPtr, chunkSz, crc) == TCL_ERROR) { + return TCL_ERROR; + } + + /* + * Begin the next chunk. + */ + + if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType, + &crc) == TCL_ERROR) { + return TCL_ERROR; + } + } + + /* * Other ancillary chunk types could appear here, but for now we're only * interested in IDAT. The others should have been skipped. */ @@ -2758,6 +2898,18 @@ FileReadPNG( result = DecodePNG(interp, &png, fmtObj, imageHandle, destX, destY); } + if (TCL_OK == result && metadataOutObj != NULL && png.DPI != -1) { + result = Tcl_DictObjPut(NULL, metadataOutObj, + Tcl_NewStringObj("DPI",-1), + Tcl_NewDoubleObj(png.DPI)); + } + + if (TCL_OK == result && metadataOutObj != NULL && png.aspect != -1) { + result = Tcl_DictObjPut(NULL, metadataOutObj, + Tcl_NewStringObj("aspect",-1), + Tcl_NewDoubleObj(png.aspect)); + } + CleanupPNGImage(&png); return result; } @@ -2854,6 +3006,18 @@ StringReadPNG( result = DecodePNG(interp, &png, fmtObj, imageHandle, destX, destY); } + if (TCL_OK == result && metadataOutObj != NULL && png.DPI != -1) { + result = Tcl_DictObjPut(NULL, metadataOutObj, + Tcl_NewStringObj("DPI",-1), + Tcl_NewDoubleObj(png.DPI)); + } + + if (TCL_OK == result && metadataOutObj != NULL && png.aspect != -1) { + result = Tcl_DictObjPut(NULL, metadataOutObj, + Tcl_NewStringObj("aspect",-1), + Tcl_NewDoubleObj(png.aspect)); + } + CleanupPNGImage(&png); return result; } |