summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tkImgPNG.c166
-rw-r--r--tests/imgPNG.test15
2 files changed, 179 insertions, 2 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;
}
diff --git a/tests/imgPNG.test b/tests/imgPNG.test
index 4900e9c..537ea9e 100644
--- a/tests/imgPNG.test
+++ b/tests/imgPNG.test
@@ -1056,7 +1056,10 @@ duFtaSrZF3pfCpiGjN2imToJJ39m6BjG1XZRwrkAI8YUKSZWlEZQDAIrNArHnyvpXtmM/B7wJeAbwO
fBcxKuQMrzfLdBoz29fX9led5v6u1XnBJW7vnr/YlrXEoNo22LRYOYlxZ1S6rkOfDcLvPAY/hGmWC7
H68uFI+x0oSPg2MAN/L5/M/vtqSED/T5cMu9J4Wf7HMGsB/4TEv/DFwe3Y/NPN57VXh+5BWApwFLlh
r661tV1eju/ne8YJrkWtES0tmRe2VOviv2j2aBp5nHihiRaz/A4oCnsAsje/+AAAAAElFTkSuQmCC"
- }
+ dpi100aspect2
+"iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAA9hAAAewgEw8YEEAAAA
+FklEQVR4nGP4+vXrP11lJgYGhj9xSQAzOwXsETZ69QAAAABJRU5ErkJggg=="
+ }
# $encoded(basn0g08), $encoded(basn2c08), $encoded(basn3p08), $encoded(basn6a08)
test imgPNG-1.1 {reading basic images; grayscale} -setup {
@@ -1114,6 +1117,16 @@ test imgPNG-3.1 {reading image with unknown ancillary chunk - bug [1c659ef0f1]}
} -cleanup {
image delete $i
} -result {0}
+
+test imgPNG-4.1 {reading image with unknown ancillary chunk - bug [1c659ef0f1]} -setup {
+
+} -body {
+ image create photo i1 -data $encoded(dpi100aspect2)
+ i1 cget -metadata
+} -cleanup {
+ image delete i1
+} -result {DPI 99.9998 aspect 2.0}
+
}
namespace delete png