Implement calibrated color support, including constants for a few standard

color spaces and a new color patch test page.

The grayscale test image from CUPS wasn't actually grayscale.
This commit is contained in:
Michael R Sweet 2021-05-31 09:31:00 -04:00
parent 627b04d9f0
commit c4e0421f62
No known key found for this signature in database
GPG Key ID: 999559A027815955
4 changed files with 532 additions and 93 deletions

View File

@ -16,6 +16,21 @@
#include <math.h> #include <math.h>
//
// Global constants...
//
const double pdfioAdobeRGBGamma = 2.2;
const double pdfioAdobeRGBMatrix[3][3] = { { 0.57667, 0.18556, 0.18823 }, { 0.29734, 0.62736, 0.07529 }, { 0.02703, 0.07069, 0.99134 } };
const double pdfioAdobeRGBWhitePoint[3] = { 0.9505, 1.0, 1.0890 };
const double pdfioDisplayP3Gamma = 2.2;
const double pdfioDisplayP3Matrix[3][3] = { { 0.48657, 0.26567, 0.19822 }, {
0.22897, 0.69174, 0.07929 }, { 0.00000, 0.04511, 1.04394 } };
const double pdfioDisplayP3WhitePoint[3] = { 0.9505, 1.0, 1.0890 };
const double pdfioSRGBGamma = 2.2;
const double pdfioSRGBMatrix[3][3] = { { 0.4124, 0.3576, 0.1805 }, { 0.2126, 0.7152, 0.0722 }, { 0.0193, 0.1192, 0.9505 } };
const double pdfioSRGBWhitePoint[3] = { 0.9505, 1.0, 1.0890 };
// //
// Local types... // Local types...
// //
@ -29,6 +44,7 @@ typedef pdfio_obj_t *(*_pdfio_image_func_t)(pdfio_dict_t *dict, int fd);
static pdfio_obj_t *copy_jpeg(pdfio_dict_t *dict, int fd); static pdfio_obj_t *copy_jpeg(pdfio_dict_t *dict, int fd);
static pdfio_obj_t *copy_png(pdfio_dict_t *dict, int fd); static pdfio_obj_t *copy_png(pdfio_dict_t *dict, int fd);
static pdfio_array_t *create_calcolor(pdfio_file_t *pdf, size_t num_colors, double gamma, const double matrix[3][3], const double white_point[3]);
static bool write_string(pdfio_stream_t *st, const char *s); static bool write_string(pdfio_stream_t *st, const char *s);
@ -68,12 +84,12 @@ bool // O - `true` on success, `false` on failure
pdfioContentDrawImage( pdfioContentDrawImage(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
const char *name, // I - Image name const char *name, // I - Image name
double x, // I - X offset of image double x, // I - X offset of image
double y, // I - Y offset of image double y, // I - Y offset of image
double w, // I - Width of image double width, // I - Width of image
double h) // I - Height of image double height) // I - Height of image
{ {
return (pdfioStreamPrintf(st, "q %g 0 0 %g %g %g cm/%s Do Q\n", w, h, x, y, name)); return (pdfioStreamPrintf(st, "q %g 0 0 %g %g %g cm/%s Do Q\n", width, height, x, y, name));
} }
@ -135,7 +151,7 @@ pdfioContentMatrixConcat(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentMatrixRotate( pdfioContentMatrixRotate(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double degrees) // I - Rotation angle in degrees counter-clockwise double degrees) // I - Rotation angle in degrees counter-clockwise
{ {
double dcos = cos(degrees / M_PI); // Cosine double dcos = cos(degrees / M_PI); // Cosine
double dsin = sin(degrees / M_PI); // Sine double dsin = sin(degrees / M_PI); // Sine
@ -151,8 +167,8 @@ pdfioContentMatrixRotate(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentMatrixScale( pdfioContentMatrixScale(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double sx, // I - X scale double sx, // I - X scale
double sy) // I - Y scale double sy) // I - Y scale
{ {
return (pdfioStreamPrintf(st, "%g 0 0 %g 0 0 cm\n", sx, sy)); return (pdfioStreamPrintf(st, "%g 0 0 %g 0 0 cm\n", sx, sy));
} }
@ -165,8 +181,8 @@ pdfioContentMatrixScale(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentMatrixTranslate( pdfioContentMatrixTranslate(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double tx, // I - X offset double tx, // I - X offset
double ty) // I - Y offset double ty) // I - Y offset
{ {
return (pdfioStreamPrintf(st, "1 0 0 1 %g %g cm\n", tx, ty)); return (pdfioStreamPrintf(st, "1 0 0 1 %g %g cm\n", tx, ty));
} }
@ -191,12 +207,12 @@ pdfioContentPathClose(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentPathCurve( pdfioContentPathCurve(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double x1, // I - X position 1 double x1, // I - X position 1
double y1, // I - Y position 1 double y1, // I - Y position 1
double x2, // I - X position 2 double x2, // I - X position 2
double y2, // I - Y position 2 double y2, // I - Y position 2
double x3, // I - X position 3 double x3, // I - X position 3
double y3) // I - Y position 3 double y3) // I - Y position 3
{ {
return (pdfioStreamPrintf(st, "%g %g %g %g %g %g c\n", x1, y1, x2, y2, x3, y3)); return (pdfioStreamPrintf(st, "%g %g %g %g %g %g c\n", x1, y1, x2, y2, x3, y3));
} }
@ -209,10 +225,10 @@ pdfioContentPathCurve(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentPathCurve13( pdfioContentPathCurve13(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double x1, // I - X position 1 double x1, // I - X position 1
double y1, // I - Y position 1 double y1, // I - Y position 1
double x3, // I - X position 3 double x3, // I - X position 3
double y3) // I - Y position 3 double y3) // I - Y position 3
{ {
return (pdfioStreamPrintf(st, "%g %g %g %g v\n", x1, y1, x3, y3)); return (pdfioStreamPrintf(st, "%g %g %g %g v\n", x1, y1, x3, y3));
} }
@ -225,10 +241,10 @@ pdfioContentPathCurve13(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentPathCurve23( pdfioContentPathCurve23(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double x2, // I - X position 2 double x2, // I - X position 2
double y2, // I - Y position 2 double y2, // I - Y position 2
double x3, // I - X position 3 double x3, // I - X position 3
double y3) // I - Y position 3 double y3) // I - Y position 3
{ {
return (pdfioStreamPrintf(st, "%g %g %g %g y\n", x2, y2, x3, y3)); return (pdfioStreamPrintf(st, "%g %g %g %g y\n", x2, y2, x3, y3));
} }
@ -241,8 +257,8 @@ pdfioContentPathCurve23(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentPathLineTo( pdfioContentPathLineTo(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double x, // I - X position double x, // I - X position
double y) // I - Y position double y) // I - Y position
{ {
return (pdfioStreamPrintf(st, "%g %g l\n", x, y)); return (pdfioStreamPrintf(st, "%g %g l\n", x, y));
} }
@ -255,8 +271,8 @@ pdfioContentPathLineTo(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentPathMoveTo( pdfioContentPathMoveTo(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double x, // I - X position double x, // I - X position
double y) // I - Y position double y) // I - Y position
{ {
return (pdfioStreamPrintf(st, "%g %g m\n", x, y)); return (pdfioStreamPrintf(st, "%g %g m\n", x, y));
} }
@ -269,9 +285,12 @@ pdfioContentPathMoveTo(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentPathRect( pdfioContentPathRect(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
pdfio_rect_t *rect) // I - Rectangle double x, // I - X offset
double y, // I - Y offset
double width, // I - Width
double height) // I - Height
{ {
return (pdfioStreamPrintf(st, "%g %g %g %g re\n", rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1)); return (pdfioStreamPrintf(st, "%g %g %g %g re\n", x, y, width, height));
} }
@ -320,10 +339,10 @@ pdfioContentSetDashPattern(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetFillColorDeviceCMYK( pdfioContentSetFillColorDeviceCMYK(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double c, // I - Cyan value (0.0 to 1.0) double c, // I - Cyan value (0.0 to 1.0)
double m, // I - Magenta value (0.0 to 1.0) double m, // I - Magenta value (0.0 to 1.0)
double y, // I - Yellow value (0.0 to 1.0) double y, // I - Yellow value (0.0 to 1.0)
double k) // I - Black value (0.0 to 1.0) double k) // I - Black value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g %g %g %g k\n", c, m, y, k)); return (pdfioStreamPrintf(st, "%g %g %g %g k\n", c, m, y, k));
} }
@ -336,7 +355,7 @@ pdfioContentSetFillColorDeviceCMYK(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetFillColorDeviceGray( pdfioContentSetFillColorDeviceGray(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double g) // I - Gray value (0.0 to 1.0) double g) // I - Gray value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g g\n", g)); return (pdfioStreamPrintf(st, "%g g\n", g));
} }
@ -349,9 +368,9 @@ pdfioContentSetFillColorDeviceGray(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetFillColorDeviceRGB( pdfioContentSetFillColorDeviceRGB(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double r, // I - Red value (0.0 to 1.0) double r, // I - Red value (0.0 to 1.0)
double g, // I - Green value (0.0 to 1.0) double g, // I - Green value (0.0 to 1.0)
double b) // I - Blue value (0.0 to 1.0) double b) // I - Blue value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g %g %g rg\n", r, g, b)); return (pdfioStreamPrintf(st, "%g %g %g rg\n", r, g, b));
} }
@ -364,7 +383,7 @@ pdfioContentSetFillColorDeviceRGB(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetFillColorGray( pdfioContentSetFillColorGray(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double g) // I - Gray value (0.0 to 1.0) double g) // I - Gray value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g sc\n", g)); return (pdfioStreamPrintf(st, "%g sc\n", g));
} }
@ -377,9 +396,9 @@ pdfioContentSetFillColorGray(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetFillColorRGB( pdfioContentSetFillColorRGB(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double r, // I - Red value (0.0 to 1.0) double r, // I - Red value (0.0 to 1.0)
double g, // I - Green value (0.0 to 1.0) double g, // I - Green value (0.0 to 1.0)
double b) // I - Blue value (0.0 to 1.0) double b) // I - Blue value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g %g %g sc\n", r, g, b)); return (pdfioStreamPrintf(st, "%g %g %g sc\n", r, g, b));
} }
@ -405,7 +424,7 @@ pdfioContentSetFillColorSpace(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetFlatness( pdfioContentSetFlatness(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double flatness) // I - Flatness value (0.0 to 100.0) double flatness) // I - Flatness value (0.0 to 100.0)
{ {
return (pdfioStreamPrintf(st, "%g i\n", flatness)); return (pdfioStreamPrintf(st, "%g i\n", flatness));
} }
@ -444,7 +463,7 @@ pdfioContentSetLineJoin(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetLineWidth( pdfioContentSetLineWidth(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double width) // I - Line width value double width) // I - Line width value
{ {
return (pdfioStreamPrintf(st, "%g w\n", width)); return (pdfioStreamPrintf(st, "%g w\n", width));
} }
@ -457,7 +476,7 @@ pdfioContentSetLineWidth(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetMiterLimit( pdfioContentSetMiterLimit(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double limit) // I - Miter limit value double limit) // I - Miter limit value
{ {
return (pdfioStreamPrintf(st, "%g M\n", limit)); return (pdfioStreamPrintf(st, "%g M\n", limit));
} }
@ -470,10 +489,10 @@ pdfioContentSetMiterLimit(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetStrokeColorDeviceCMYK( pdfioContentSetStrokeColorDeviceCMYK(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double c, // I - Cyan value (0.0 to 1.0) double c, // I - Cyan value (0.0 to 1.0)
double m, // I - Magenta value (0.0 to 1.0) double m, // I - Magenta value (0.0 to 1.0)
double y, // I - Yellow value (0.0 to 1.0) double y, // I - Yellow value (0.0 to 1.0)
double k) // I - Black value (0.0 to 1.0) double k) // I - Black value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g %g %g %g K\n", c, m, y, k)); return (pdfioStreamPrintf(st, "%g %g %g %g K\n", c, m, y, k));
} }
@ -486,7 +505,7 @@ pdfioContentSetStrokeColorDeviceCMYK(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetStrokeColorDeviceGray( pdfioContentSetStrokeColorDeviceGray(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double g) // I - Gray value (0.0 to 1.0) double g) // I - Gray value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g G\n", g)); return (pdfioStreamPrintf(st, "%g G\n", g));
} }
@ -499,9 +518,9 @@ pdfioContentSetStrokeColorDeviceGray(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetStrokeColorDeviceRGB( pdfioContentSetStrokeColorDeviceRGB(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double r, // I - Red value (0.0 to 1.0) double r, // I - Red value (0.0 to 1.0)
double g, // I - Green value (0.0 to 1.0) double g, // I - Green value (0.0 to 1.0)
double b) // I - Blue value (0.0 to 1.0) double b) // I - Blue value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g %g %g RG\n", r, g, b)); return (pdfioStreamPrintf(st, "%g %g %g RG\n", r, g, b));
} }
@ -514,7 +533,7 @@ pdfioContentSetStrokeColorDeviceRGB(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetStrokeColorGray( pdfioContentSetStrokeColorGray(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double g) // I - Gray value (0.0 to 1.0) double g) // I - Gray value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g SC\n", g)); return (pdfioStreamPrintf(st, "%g SC\n", g));
} }
@ -527,9 +546,9 @@ pdfioContentSetStrokeColorGray(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetStrokeColorRGB( pdfioContentSetStrokeColorRGB(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double r, // I - Red value (0.0 to 1.0) double r, // I - Red value (0.0 to 1.0)
double g, // I - Green value (0.0 to 1.0) double g, // I - Green value (0.0 to 1.0)
double b) // I - Blue value (0.0 to 1.0) double b) // I - Blue value (0.0 to 1.0)
{ {
return (pdfioStreamPrintf(st, "%g %g %g SC\n", r, g, b)); return (pdfioStreamPrintf(st, "%g %g %g SC\n", r, g, b));
} }
@ -555,7 +574,7 @@ pdfioContentSetStrokeColorSpace(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetTextCharacterSpacing( pdfioContentSetTextCharacterSpacing(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double spacing) // I - Character spacing double spacing) // I - Character spacing
{ {
return (pdfioStreamPrintf(st, "%g Tc\n", spacing)); return (pdfioStreamPrintf(st, "%g Tc\n", spacing));
} }
@ -569,7 +588,7 @@ bool // O - `true` on success, `false` on failure
pdfioContentSetTextFont( pdfioContentSetTextFont(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
const char *name, // I - Font name const char *name, // I - Font name
double size) // I - Font size double size) // I - Font size
{ {
return (pdfioStreamPrintf(st, "/%s %g Tf\n", name, size)); return (pdfioStreamPrintf(st, "/%s %g Tf\n", name, size));
} }
@ -582,7 +601,7 @@ pdfioContentSetTextFont(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetTextLeading( pdfioContentSetTextLeading(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double leading) // I - Leading (line height) value double leading) // I - Leading (line height) value
{ {
return (pdfioStreamPrintf(st, "%g TL\n", leading)); return (pdfioStreamPrintf(st, "%g TL\n", leading));
} }
@ -621,7 +640,7 @@ pdfioContentSetTextRenderingMode(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetTextRise( pdfioContentSetTextRise(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double rise) // I - Y offset double rise) // I - Y offset
{ {
return (pdfioStreamPrintf(st, "%g Ts\n", rise)); return (pdfioStreamPrintf(st, "%g Ts\n", rise));
} }
@ -634,7 +653,7 @@ pdfioContentSetTextRise(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetTextWordSpacing( pdfioContentSetTextWordSpacing(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double spacing) // I - Spacing between words double spacing) // I - Spacing between words
{ {
return (pdfioStreamPrintf(st, "%g Tw\n", spacing)); return (pdfioStreamPrintf(st, "%g Tw\n", spacing));
} }
@ -647,7 +666,7 @@ pdfioContentSetTextWordSpacing(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentSetTextXScaling( pdfioContentSetTextXScaling(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double percent) // I - Horizontal scaling in percent double percent) // I - Horizontal scaling in percent
{ {
return (pdfioStreamPrintf(st, "%g Tz\n", percent)); return (pdfioStreamPrintf(st, "%g Tz\n", percent));
} }
@ -671,8 +690,8 @@ pdfioContentStroke(pdfio_stream_t *st) // I - Stream
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentTextMoveLine( pdfioContentTextMoveLine(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double tx, // I - X offset double tx, // I - X offset
double ty) // I - Y offset double ty) // I - Y offset
{ {
return (pdfioStreamPrintf(st, "%g %g TD\n", tx, ty)); return (pdfioStreamPrintf(st, "%g %g TD\n", tx, ty));
} }
@ -685,8 +704,8 @@ pdfioContentTextMoveLine(
bool // O - `true` on success, `false` on failure bool // O - `true` on success, `false` on failure
pdfioContentTextMoveTo( pdfioContentTextMoveTo(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
double tx, // I - X offset double tx, // I - X offset
double ty) // I - Y offset double ty) // I - Y offset
{ {
return (pdfioStreamPrintf(st, "%g %g Td\n", tx, ty)); return (pdfioStreamPrintf(st, "%g %g Td\n", tx, ty));
} }
@ -731,7 +750,7 @@ bool // O - `true` on success, `false` on failure
pdfioContentTextShowJustified( pdfioContentTextShowJustified(
pdfio_stream_t *st, // I - Stream pdfio_stream_t *st, // I - Stream
size_t num_fragments, // I - Number of text fragments size_t num_fragments, // I - Number of text fragments
const double *offsets, // I - Text offsets before fragments const double *offsets, // I - Text offsets before fragments
const char * const *fragments) // I - Text fragments const char * const *fragments) // I - Text fragments
{ {
size_t i; // Looping var size_t i; // Looping var
@ -789,16 +808,39 @@ pdfioPageDictAddCalibratedColorSpace(
pdfio_dict_t *dict, // I - Page dictionary pdfio_dict_t *dict, // I - Page dictionary
const char *name, // I - Color space name const char *name, // I - Color space name
size_t num_colors, // I - Number of color components size_t num_colors, // I - Number of color components
const double *white_point, // I - CIE XYZ white point double gamma, // I - Gamma value
double gamma) // I - Gamma value const double matrix[3][3], // I - Color transform matrix
const double white_point[3]) // I - CIE XYZ white point
{ {
(void)dict; pdfio_dict_t *resources; // Resource dictionary
(void)name; pdfio_dict_t *colorspace; // ColorSpace dictionary
(void)num_colors;
(void)white_point;
(void)gamma;
return (false);
// Range check input...
if (!dict || !name || !num_colors || gamma <= 0.0)
return (false);
// Get the ColorSpace dictionary...
if ((resources = pdfioDictGetDict(dict, "Resources")) == NULL)
{
if ((resources = pdfioDictCreate(dict->pdf)) == NULL)
return (false);
if (!pdfioDictSetDict(dict, "Resources", resources))
return (false);
}
if ((colorspace = pdfioDictGetDict(resources, "ColorSpace")) == NULL)
{
if ((colorspace = pdfioDictCreate(dict->pdf)) == NULL)
return (false);
if (!pdfioDictSetDict(resources, "ColorSpace", colorspace))
return (false);
}
// Now set the color space reference and return...
return (pdfioDictSetArray(colorspace, name, create_calcolor(dict->pdf, num_colors, gamma, matrix, white_point)));
} }
@ -838,7 +880,7 @@ pdfioPageDictAddImage(
if (!dict || !name || !obj) if (!dict || !name || !obj)
return (false); return (false);
// Get the images dictionary... // Get the Resources dictionary...
if ((resources = pdfioDictGetDict(dict, "Resources")) == NULL) if ((resources = pdfioDictGetDict(dict, "Resources")) == NULL)
{ {
if ((resources = pdfioDictCreate(dict->pdf)) == NULL) if ((resources = pdfioDictCreate(dict->pdf)) == NULL)
@ -848,6 +890,7 @@ pdfioPageDictAddImage(
return (false); return (false);
} }
// Get the XObject dictionary...
if ((xobject = pdfioDictGetDict(resources, "XObject")) == NULL) if ((xobject = pdfioDictGetDict(resources, "XObject")) == NULL)
{ {
if ((xobject = pdfioDictCreate(dict->pdf)) == NULL) if ((xobject = pdfioDictCreate(dict->pdf)) == NULL)
@ -857,7 +900,7 @@ pdfioPageDictAddImage(
return (false); return (false);
} }
// Now set the image reference in the images resource dictionary and return... // Now set the image reference in the XObject resource dictionary and return...
return (pdfioDictSetObject(xobject, name, obj)); return (pdfioDictSetObject(xobject, name, obj));
} }
@ -1064,6 +1107,12 @@ copy_jpeg(pdfio_dict_t *dict, // I - Dictionary
if ((*bufptr >= 0xc0 && *bufptr <= 0xc3) || (*bufptr >= 0xc5 && *bufptr <= 0xc7) || (*bufptr >= 0xc9 && *bufptr <= 0xcb) || (*bufptr >= 0xcd && *bufptr <= 0xcf)) if ((*bufptr >= 0xc0 && *bufptr <= 0xc3) || (*bufptr >= 0xc5 && *bufptr <= 0xc7) || (*bufptr >= 0xc9 && *bufptr <= 0xcb) || (*bufptr >= 0xcd && *bufptr <= 0xcf))
{ {
// SOFn marker, look for dimensions... // SOFn marker, look for dimensions...
if (bufptr[3] != 8)
{
_pdfioFileError(dict->pdf, "Unable to load %d-bit JPEG image.", bufptr[3]);
return (NULL);
}
width = (unsigned)((bufptr[6] << 8) | bufptr[7]); width = (unsigned)((bufptr[6] << 8) | bufptr[7]);
height = (unsigned)((bufptr[4] << 8) | bufptr[5]); height = (unsigned)((bufptr[4] << 8) | bufptr[5]);
num_colors = bufptr[8]; num_colors = bufptr[8];
@ -1100,7 +1149,7 @@ copy_jpeg(pdfio_dict_t *dict, // I - Dictionary
pdfioDictSetNumber(dict, "Height", height); pdfioDictSetNumber(dict, "Height", height);
pdfioDictSetNumber(dict, "BitsPerComponent", 8); pdfioDictSetNumber(dict, "BitsPerComponent", 8);
// TODO: Add proper JPEG CalRGB/Gray color spaces // TODO: Add proper JPEG CalRGB/Gray color spaces
pdfioDictSetName(dict, "ColorSpace", num_colors == 3 ? "DeviceRGB" : "DeviceGray"); pdfioDictSetArray(dict, "ColorSpace", create_calcolor(dict->pdf, num_colors, pdfioSRGBGamma, pdfioSRGBMatrix, pdfioSRGBWhitePoint));
pdfioDictSetName(dict, "Filter", "DCTDecode"); pdfioDictSetName(dict, "Filter", "DCTDecode");
obj = pdfioFileCreateObject(dict->pdf, dict); obj = pdfioFileCreateObject(dict->pdf, dict);
@ -1137,6 +1186,88 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
} }
//
// 'create_calcolor()' - Create a CalGray or CalRGB color array.
//
static pdfio_array_t * // O - Array
create_calcolor(
pdfio_file_t *pdf, // I - PDF file
size_t num_colors, // I - Number of colors (1 or 3)
double gamma, // I - Gamma value
const double matrix[3][3], // I - XYZ transform
const double white_point[3]) // I - White point
{
size_t i; // Looping var
pdfio_array_t *calcolor; // Array to hold calibrated color space
pdfio_dict_t *dict; // Dictionary to hold color values
pdfio_array_t *value; // Value for white point, matrix, and gamma
// Create the array with two values - a name and a dictionary...
if ((calcolor = pdfioArrayCreate(pdf)) == NULL)
return (NULL);
if (num_colors == 1)
pdfioArrayAppendName(calcolor, "CalGray");
else
pdfioArrayAppendName(calcolor, "CalRGB");
if ((dict = pdfioDictCreate(pdf)) == NULL)
return (NULL);
pdfioArrayAppendDict(calcolor, dict);
// Then add the values...
if (num_colors == 1)
{
pdfioDictSetNumber(dict, "Gamma", gamma);
}
else
{
if ((value = pdfioArrayCreate(pdf)) == NULL)
return (NULL);
for (i = 0; i < num_colors; i ++)
pdfioArrayAppendNumber(value, gamma);
pdfioDictSetArray(dict, "Gamma", value);
}
if (white_point)
{
if ((value = pdfioArrayCreate(pdf)) == NULL)
return (NULL);
pdfioArrayAppendNumber(value, white_point[0]);
pdfioArrayAppendNumber(value, white_point[1]);
pdfioArrayAppendNumber(value, white_point[2]);
pdfioDictSetArray(dict, "WhitePoint", value);
}
if (num_colors > 1 && matrix)
{
if ((value = pdfioArrayCreate(pdf)) == NULL)
return (NULL);
pdfioArrayAppendNumber(value, matrix[0][0]);
pdfioArrayAppendNumber(value, matrix[1][0]);
pdfioArrayAppendNumber(value, matrix[2][0]);
pdfioArrayAppendNumber(value, matrix[0][1]);
pdfioArrayAppendNumber(value, matrix[1][1]);
pdfioArrayAppendNumber(value, matrix[2][1]);
pdfioArrayAppendNumber(value, matrix[0][2]);
pdfioArrayAppendNumber(value, matrix[1][2]);
pdfioArrayAppendNumber(value, matrix[2][2]);
pdfioDictSetArray(dict, "Matrix", value);
}
return (calcolor);
}
// //
// 'write_string()' - Write a PDF string. // 'write_string()' - Write a PDF string.
// //

View File

@ -59,16 +59,23 @@ typedef enum pdfio_textrendering_e // Text rendering modes
PDFIO_TEXTRENDERING_TEXT_PATH // Add text to path (invisible) PDFIO_TEXTRENDERING_TEXT_PATH // Add text to path (invisible)
} pdfio_textrendering_t; } pdfio_textrendering_t;
extern const double pdfioAdobeRGBGamma; extern const double pdfioAdobeRGBGamma PDFIO_PUBLIC;
// AdobeRGB gamma // AdobeRGB gamma
extern const double pdfioAdobeRGBWhitePoint[]; extern const double pdfioAdobeRGBMatrix[3][3] PDFIO_PUBLIC;
// AdobeRGB matrix
extern const double pdfioAdobeRGBWhitePoint[3] PDFIO_PUBLIC;
// AdobeRGB white point // AdobeRGB white point
extern const double pdfioDisplayP3Gamma; extern const double pdfioDisplayP3Gamma PDFIO_PUBLIC;
// Display P3 gamma // Display P3 gamma
extern const double pdfioDisplayP3WhitePoint[]; extern const double pdfioDisplayP3Matrix[3][3] PDFIO_PUBLIC;
// Display P3 matrix
extern const double pdfioDisplayP3WhitePoint[3] PDFIO_PUBLIC;
// Display P3 white point // Display P3 white point
extern const double pdfioSRGBGamma; // sRGB gamma extern const double pdfioSRGBGamma PDFIO_PUBLIC;
extern const double pdfioSRGBWhitePoint[]; // sRGB gamma
extern const double pdfioSRGBMatrix[3][3] PDFIO_PUBLIC;
// sRGB matrix
extern const double pdfioSRGBWhitePoint[3] PDFIO_PUBLIC;
// sRGB white point // sRGB white point
@ -93,7 +100,7 @@ extern bool pdfioContentPathCurve13(pdfio_stream_t *st, double x1, double y1, d
extern bool pdfioContentPathCurve23(pdfio_stream_t *st, double x2, double y2, double x3, double y3) PDFIO_PUBLIC; extern bool pdfioContentPathCurve23(pdfio_stream_t *st, double x2, double y2, double x3, double y3) PDFIO_PUBLIC;
extern bool pdfioContentPathLineTo(pdfio_stream_t *st, double x, double y) PDFIO_PUBLIC; extern bool pdfioContentPathLineTo(pdfio_stream_t *st, double x, double y) PDFIO_PUBLIC;
extern bool pdfioContentPathMoveTo(pdfio_stream_t *st, double x, double y) PDFIO_PUBLIC; extern bool pdfioContentPathMoveTo(pdfio_stream_t *st, double x, double y) PDFIO_PUBLIC;
extern bool pdfioContentPathRect(pdfio_stream_t *st, pdfio_rect_t *rect) PDFIO_PUBLIC; extern bool pdfioContentPathRect(pdfio_stream_t *st, double x, double y, double width, double height) PDFIO_PUBLIC;
extern bool pdfioContentRestore(pdfio_stream_t *st) PDFIO_PUBLIC; extern bool pdfioContentRestore(pdfio_stream_t *st) PDFIO_PUBLIC;
extern bool pdfioContentSave(pdfio_stream_t *st) PDFIO_PUBLIC; extern bool pdfioContentSave(pdfio_stream_t *st) PDFIO_PUBLIC;
extern bool pdfioContentSetDashPattern(pdfio_stream_t *st, int phase, int on, int off) PDFIO_PUBLIC; extern bool pdfioContentSetDashPattern(pdfio_stream_t *st, int phase, int on, int off) PDFIO_PUBLIC;
@ -140,7 +147,7 @@ extern double pdfioImageGetWidth(pdfio_obj_t *obj) PDFIO_PUBLIC;
// Page dictionary helpers... // Page dictionary helpers...
extern bool pdfioPageDictAddICCColorSpace(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) PDFIO_PUBLIC; extern bool pdfioPageDictAddICCColorSpace(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) PDFIO_PUBLIC;
extern bool pdfioPageDictAddCalibratedColorSpace(pdfio_dict_t *dict, const char *name, size_t num_colors, const double *white_point, double gamma) PDFIO_PUBLIC; extern bool pdfioPageDictAddCalibratedColorSpace(pdfio_dict_t *dict, const char *name, size_t num_colors, double gamma, const double matrix[3][3], const double white_point[3]) PDFIO_PUBLIC;
extern bool pdfioPageDictAddFont(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) PDFIO_PUBLIC; extern bool pdfioPageDictAddFont(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) PDFIO_PUBLIC;
extern bool pdfioPageDictAddImage(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) PDFIO_PUBLIC; extern bool pdfioPageDictAddImage(pdfio_dict_t *dict, const char *name, pdfio_obj_t *obj) PDFIO_PUBLIC;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 126 KiB

View File

@ -13,6 +13,7 @@
#include "pdfio-private.h" #include "pdfio-private.h"
#include "pdfio-content.h" #include "pdfio-content.h"
#include <math.h>
// //
@ -24,6 +25,8 @@ static int do_unit_tests(void);
static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error); static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error);
static ssize_t token_consume_cb(const char **s, size_t bytes); static ssize_t token_consume_cb(const char **s, size_t bytes);
static ssize_t token_peek_cb(const char **s, char *buffer, size_t bytes); static ssize_t token_peek_cb(const char **s, char *buffer, size_t bytes);
static int write_color_patch(pdfio_stream_t *st, bool device);
static int write_color_test(pdfio_file_t *pdf, int number);
static int write_page(pdfio_file_t *pdf, int number, pdfio_obj_t *image); static int write_page(pdfio_file_t *pdf, int number, pdfio_obj_t *image);
@ -227,12 +230,9 @@ do_unit_tests(void)
else else
return (1); return (1);
// Write a few pages... // Write a page with a color image...
for (i = 1; i < 16; i ++) if (write_page(outpdf, 2, color_jpg))
{ return (1);
if (write_page(outpdf, i, (i & 1) ? color_jpg : gray_jpg))
return (1);
}
// Copy the third page from the test PDF file... // Copy the third page from the test PDF file...
fputs("pdfioFileGetPage(2): ", stdout); fputs("pdfioFileGetPage(2): ", stdout);
@ -247,6 +247,14 @@ do_unit_tests(void)
else else
return (1); return (1);
// Write a page with a grayscale image...
if (write_page(outpdf, 4, gray_jpg))
return (1);
// Write a page that tests multiple color spaces...
if (write_color_test(outpdf, 5))
return (1);
// Close the test PDF file... // Close the test PDF file...
fputs("pdfioFileClose(\"testfiles/testpdfio.pdf\": ", stdout); fputs("pdfioFileClose(\"testfiles/testpdfio.pdf\": ", stdout);
if (pdfioFileClose(pdf)) if (pdfioFileClose(pdf))
@ -337,6 +345,299 @@ token_peek_cb(const char **s, // IO - Test string
} }
//
// 'write_color_patch()' - Write a color patch...
//
static int // O - 1 on failure, 0 on success
write_color_patch(pdfio_stream_t *st, // I - Content stream
bool device)// I - Use device color?
{
int col, // Current column
row; // Current row
double x, y, // Relative position
r, // Radius
hue, // Hue angle
sat, // Saturation
cc, // Computed color
red, // Red value
green, // Green value
blue; // Blue value
// Draw an 11x11 patch...
for (col = 0; col < 21; col ++)
{
for (row = 0; row < 21; row ++)
{
// Compute color in patch...
x = 0.1 * (col - 10);
y = 0.1 * (row - 10);
r = sqrt(x * x + y * y);
if (r == 0.0)
{
red = green = blue = 1.0;
}
else
{
if ((sat = fabs(x)) < fabs(y))
sat = fabs(y);
sat = pow(sat, 1.5);
x /= r;
y /= r;
hue = 3.0 * atan2(y, x) / M_PI;
if (hue < 0.0)
hue += 6.0;
cc = sat * (1.0 - fabs(fmod(hue, 2.0) - 1.0)) + 1.0 - sat;
if (hue < 1.0)
{
red = 1.0;
green = cc;
blue = 1.0 - sat;
}
else if (hue < 2.0)
{
red = cc;
green = 1.0;
blue = 1.0 - sat;
}
else if (hue < 3.0)
{
red = 1.0 - sat;
green = 1.0;
blue = cc;
}
else if (hue < 4.0)
{
red = 1.0 - sat;
green = cc;
blue = 1.0;
}
else if (hue < 5.0)
{
red = cc;
green = 1.0 - sat;
blue = 1.0;
}
else
{
red = 1.0;
green = 1.0 - sat;
blue = cc;
}
}
// Draw it...
if (device)
{
// Use device CMYK color instead of a calibrated RGB space...
double cyan = 1.0 - red; // Cyan color
double magenta = 1.0 - green; // Magenta color
double yellow = 1.0 - blue; // Yellow color
double black = cyan; // Black color
if (black > magenta)
black = magenta;
if (black > yellow)
black = yellow;
cyan -= black;
magenta -= black;
yellow -= black;
printf("pdfioContentSetFillColorDeviceCMYK(c=%g, m=%g, y=%g, k=%g): ", cyan, magenta, yellow, black);
if (pdfioContentSetFillColorDeviceCMYK(st, cyan, magenta, yellow, black))
puts("PASS");
else
return (1);
}
else
{
// Use calibrate RGB space...
printf("pdfioContentSetFillColorRGB(r=%g, g=%g, b=%g): ", red, green, blue);
if (pdfioContentSetFillColorRGB(st, red, green, blue))
puts("PASS");
else
return (1);
}
printf("pdfioContentPathRect(x=%g, y=%g, w=%g, h=%g): ", col * 9.0, row * 9.0, 9.0, 9.0);
if (pdfioContentPathRect(st, col * 9.0, row * 9.0, 9.0, 9.0))
puts("PASS");
else
return (1);
fputs("pdfioContentFill(even_odd=false): ", stdout);
if (pdfioContentFill(st, false))
puts("PASS");
else
return (1);
}
}
return (0);
}
//
// 'write_color_test()' - Write a color test page...
//
static int // O - 1 on failure, 0 on success
write_color_test(pdfio_file_t *pdf, // I - PDF file
int number) // I - Page number
{
pdfio_dict_t *dict; // Page dictionary
pdfio_stream_t *st; // Page contents stream
fputs("pdfioDictCreate: ", stdout);
if ((dict = pdfioDictCreate(pdf)) != NULL)
puts("PASS");
else
return (1);
fputs("pdfioPageDictAddCalibratedColorSpace(AdobeRGB): ", stdout);
if (pdfioPageDictAddCalibratedColorSpace(dict, "AdobeRGB", 3, pdfioAdobeRGBGamma, pdfioAdobeRGBMatrix, pdfioAdobeRGBWhitePoint))
puts("PASS");
else
return (1);
fputs("pdfioPageDictAddCalibratedColorSpace(DisplayP3): ", stdout);
if (pdfioPageDictAddCalibratedColorSpace(dict, "DisplayP3", 3, pdfioDisplayP3Gamma, pdfioDisplayP3Matrix, pdfioDisplayP3WhitePoint))
puts("PASS");
else
return (1);
fputs("pdfioPageDictAddCalibratedColorSpace(sRGB): ", stdout);
if (pdfioPageDictAddCalibratedColorSpace(dict, "sRGB", 3, pdfioSRGBGamma, pdfioSRGBMatrix, pdfioSRGBWhitePoint))
puts("PASS");
else
return (1);
printf("pdfioFileCreatePage(%d): ", number);
if ((st = pdfioFileCreatePage(pdf, dict)) != NULL)
puts("PASS");
else
return (1);
fputs("pdfioContentSave(): ", stdout);
if (pdfioContentSave(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSetFillColorSpace(AdobeRGB): ", stdout);
if (pdfioContentSetFillColorSpace(st, "AdobeRGB"))
puts("PASS");
else
return (1);
fputs("pdfioContentMatrixTranslate(82, 180): ", stdout);
if (pdfioContentMatrixTranslate(st, 82, 180))
puts("PASS");
else
return (1);
if (write_color_patch(st, false))
return (1);
fputs("pdfioContentRestore(): ", stdout);
if (pdfioContentRestore(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSave(): ", stdout);
if (pdfioContentSave(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSetFillColorSpace(DisplayP3): ", stdout);
if (pdfioContentSetFillColorSpace(st, "DisplayP3"))
puts("PASS");
else
return (1);
fputs("pdfioContentMatrixTranslate(316, 180): ", stdout);
if (pdfioContentMatrixTranslate(st, 316, 180))
puts("PASS");
else
return (1);
if (write_color_patch(st, false))
return (1);
fputs("pdfioContentRestore(): ", stdout);
if (pdfioContentRestore(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSave(): ", stdout);
if (pdfioContentSave(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSetFillColorSpace(sRGB): ", stdout);
if (pdfioContentSetFillColorSpace(st, "sRGB"))
puts("PASS");
else
return (1);
fputs("pdfioContentMatrixTranslate(82, 414): ", stdout);
if (pdfioContentMatrixTranslate(st, 82, 414))
puts("PASS");
else
return (1);
if (write_color_patch(st, false))
return (1);
fputs("pdfioContentRestore(): ", stdout);
if (pdfioContentRestore(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSave(): ", stdout);
if (pdfioContentSave(st))
puts("PASS");
else
return (1);
fputs("pdfioContentMatrixTranslate(316, 414): ", stdout);
if (pdfioContentMatrixTranslate(st, 316, 414))
puts("PASS");
else
return (1);
if (write_color_patch(st, true))
return (1);
fputs("pdfioContentRestore(): ", stdout);
if (pdfioContentRestore(st))
puts("PASS");
else
return (1);
fputs("pdfioStreamClose: ", stdout);
if (pdfioStreamClose(st))
puts("PASS");
else
return (1);
return (0);
}
// //
// 'write_page()' - Write a page to a PDF file. // 'write_page()' - Write a page to a PDF file.
// //