From caf398d72cc3cb32267b36fbdf36947bf05b01d8 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Fri, 4 Jun 2021 10:33:39 -0400 Subject: [PATCH] Add pdfioImageGetBytesPerLine API, document its use for image streams. --- pdfio-content.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++--- pdfio-content.h | 1 + pdfio-stream.c | 6 ++++- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/pdfio-content.c b/pdfio-content.c index 191ff68..0e960c2 100644 --- a/pdfio-content.c +++ b/pdfio-content.c @@ -1134,6 +1134,62 @@ pdfioFileCreateImageObject( } +// +// 'pdfioImageGetBytesPerLine()' - Get the number of bytes to read for each line. +// + +size_t // O - Number of bytes per line +pdfioImageGetBytesPerLine( + pdfio_obj_t *obj) // I - Image object +{ + pdfio_dict_t *params; // DecodeParms value + int width, // Width of image + height, // Height of image + bpc, // BitsPerComponent of image + colors; // Number of colors in image + + + if (!obj || obj->value.type != PDFIO_VALTYPE_DICT) + return (0); + + params = pdfioDictGetDict(obj->value.value.dict, "DecodeParms"); + bpc = (int)pdfioDictGetNumber(params, "BitsPerComponent"); + colors = (int)pdfioDictGetNumber(params, "Colors"); + width = (int)pdfioDictGetNumber(params, "Columns"); + height = (int)pdfioDictGetNumber(obj->value.value.dict, "Height"); + + if (width == 0) + width = (int)pdfioDictGetNumber(obj->value.value.dict, "Width"); + + if (bpc == 0) + { + if ((bpc = (int)pdfioDictGetNumber(obj->value.value.dict, "BitsPerComponent")) == 0) + bpc = 8; + } + + if (colors == 0) + { + const char *cs_name; // ColorSpace name + pdfio_array_t *cs_array; // ColorSpace array + + if ((cs_name = pdfioDictGetName(obj->value.value.dict, "ColorSpace")) == NULL) + { + if ((cs_array = pdfioDictGetArray(obj->value.value.dict, "ColorSpace")) != NULL) + cs_name = pdfioArrayGetName(cs_array, 0); + } + + if (!cs_name || strstr(cs_name, "RGB")) + colors = 3; + else if (strstr(cs_name, "CMYK")) + colors = 4; + else + colors = 1; + } + + return ((size_t)((width * colors * bpc + 7) / 8)); +} + + // // 'pdfioImageGetHeight()' - Get the height of an image object. // @@ -1141,7 +1197,10 @@ pdfioFileCreateImageObject( double // O - Height in lines pdfioImageGetHeight(pdfio_obj_t *obj) // I - Image object { - return (pdfioDictGetNumber(obj->value.value.dict, "Height")); + if (obj) + return (pdfioDictGetNumber(obj->value.value.dict, "Height")); + else + return (0.0); } @@ -1152,7 +1211,10 @@ pdfioImageGetHeight(pdfio_obj_t *obj) // I - Image object double // O - Width in columns pdfioImageGetWidth(pdfio_obj_t *obj) // I - Image object { - return (pdfioDictGetNumber(obj->value.value.dict, "Width")); + if (obj) + return (pdfioDictGetNumber(obj->value.value.dict, "Width")); + else + return (0.0); } @@ -1267,7 +1329,6 @@ copy_jpeg(pdfio_dict_t *dict, // I - Dictionary pdfioDictSetNumber(dict, "Width", width); pdfioDictSetNumber(dict, "Height", height); pdfioDictSetNumber(dict, "BitsPerComponent", 8); - // TODO: Add proper JPEG CalRGB/Gray color spaces pdfioDictSetArray(dict, "ColorSpace", create_calcolor(dict->pdf, num_colors, pdfioSRGBGamma, pdfioSRGBMatrix, pdfioSRGBWhitePoint)); pdfioDictSetName(dict, "Filter", "DCTDecode"); diff --git a/pdfio-content.h b/pdfio-content.h index 7323111..1aa8a55 100644 --- a/pdfio-content.h +++ b/pdfio-content.h @@ -144,6 +144,7 @@ extern pdfio_obj_t *pdfioFileCreateICCProfileObject(pdfio_file_t *pdf, const cha extern pdfio_obj_t *pdfioFileCreateImageObject(pdfio_file_t *pdf, const char *filename, bool interpolate) PDFIO_PUBLIC; // Image object helpers... +extern size_t pdfioImageGetBytesPerLine(pdfio_obj_t *obj) PDFIO_PUBLIC; extern double pdfioImageGetHeight(pdfio_obj_t *obj) PDFIO_PUBLIC; extern double pdfioImageGetWidth(pdfio_obj_t *obj) PDFIO_PUBLIC; diff --git a/pdfio-stream.c b/pdfio-stream.c index 1816f18..130d5da 100644 --- a/pdfio-stream.c +++ b/pdfio-stream.c @@ -571,6 +571,11 @@ pdfioStreamPuts(pdfio_stream_t *st, // I - Stream // // 'pdfioStreamRead()' - Read data from a stream. // +// This function reads data from a stream. When reading decoded image data +// from a stream, you *must* read whole scanlines. The +// @link pdfioImageGetBytesPerLine@ function can be used to determine the +// proper read length. +// ssize_t // O - Number of bytes read or `-1` on error pdfioStreamRead( @@ -860,7 +865,6 @@ stream_read(pdfio_stream_t *st, // I - Stream if (bytes < (st->pbsize - 1)) { - // TODO: Support partial reads of PNG-encoded streams? _pdfioFileError(st->pdf, "Read buffer too small for stream."); return (-1); }