2 * << Haru Free PDF Library >> -- hpdf_image.c
4 * URL: http://libharu.org
6 * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
7 * Copyright (c) 2007-2009 Antony Dovgal <tony@daylessday.org>
9 * Permission to use, copy, modify, distribute and sell this software
10 * and its documentation for any purpose is hereby granted without fee,
11 * provided that the above copyright notice appear in all copies and
12 * that both that copyright notice and this permission notice appear
13 * in supporting documentation.
14 * It is provided "as is" without express or implied warranty.
18 #include "hpdf_conf.h"
19 #include "hpdf_utils.h"
22 static const char *COL_CMYK = "DeviceCMYK";
23 static const char *COL_RGB = "DeviceRGB";
24 static const char *COL_GRAY = "DeviceGray";
27 LoadJpegHeader (HPDF_Image image,
31 /*---------------------------------------------------------------------------*/
34 LoadJpegHeader (HPDF_Image image,
41 HPDF_BYTE num_components;
42 const char *color_space_name;
47 HPDF_PTRACE ((" HPDF_Image_LoadJpegHeader\n"));
50 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&tag, &len) != HPDF_OK)
51 return HPDF_Error_GetCode (stream->error);
53 HPDF_UInt16Swap (&tag);
55 return HPDF_INVALID_JPEG_DATA;
62 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&tag, &len) != HPDF_OK)
63 return HPDF_Error_GetCode (stream->error);
65 HPDF_UInt16Swap (&tag);
68 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&size, &len) != HPDF_OK)
69 return HPDF_Error_GetCode (stream->error);
71 HPDF_UInt16Swap (&size);
73 HPDF_PTRACE (("tag=%04X size=%u\n", tag, size));
75 if (tag == 0xFFC0 || tag == 0xFFC1 ||
76 tag == 0xFFC2 || tag == 0xFFC9) {
79 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&precision, &len) !=
81 return HPDF_Error_GetCode (stream->error);
84 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&height, &len) !=
86 return HPDF_Error_GetCode (stream->error);
88 HPDF_UInt16Swap (&height);
91 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&width, &len) != HPDF_OK)
92 return HPDF_Error_GetCode (stream->error);
94 HPDF_UInt16Swap (&width);
97 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&num_components, &len) !=
99 return HPDF_Error_GetCode (stream->error);
102 } else if ((tag | 0x00FF) != 0xFFFF)
104 return HPDF_SetError (image->error, HPDF_UNSUPPORTED_JPEG_FORMAT,
107 if (HPDF_Stream_Seek (stream, size - 2, HPDF_SEEK_CUR) != HPDF_OK)
108 return HPDF_Error_GetCode (stream->error);
111 if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
112 return HPDF_Error_GetCode (stream->error);
114 if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
115 return HPDF_Error_GetCode (stream->error);
117 /* classification of RGB and CMYK is less than perfect
118 * YCbCr and YCCK are classified into RGB or CMYK.
120 * It is necessary to read APP14 data to distinguish colorspace perfectly.
123 switch (num_components) {
125 color_space_name = COL_GRAY;
128 color_space_name = COL_RGB;
131 array = HPDF_Array_New (image->mmgr);
133 return HPDF_Error_GetCode (stream->error);
135 ret = HPDF_Dict_Add (image, "Decode", array);
137 return HPDF_Error_GetCode (stream->error);
139 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
140 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
141 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
142 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
143 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
144 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
145 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
146 ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
149 return HPDF_Error_GetCode (stream->error);
151 color_space_name = COL_CMYK;
155 return HPDF_SetError (image->error, HPDF_UNSUPPORTED_JPEG_FORMAT,
159 if (HPDF_Dict_Add (image, "ColorSpace",
160 HPDF_Name_New (image->mmgr, color_space_name)) != HPDF_OK)
161 return HPDF_Error_GetCode (stream->error);
163 if (HPDF_Dict_Add (image, "BitsPerComponent",
164 HPDF_Number_New (image->mmgr, precision)) != HPDF_OK)
165 return HPDF_Error_GetCode (stream->error);
171 HPDF_Image_LoadJpegImage (HPDF_MMgr mmgr,
172 HPDF_Stream jpeg_data,
176 HPDF_STATUS ret = HPDF_OK;
178 HPDF_PTRACE ((" HPDF_Image_LoadJpegImage\n"));
180 image = HPDF_DictStream_New (mmgr, xref);
184 image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
186 /* add requiered elements */
187 image->filter = HPDF_STREAM_FILTER_DCT_DECODE;
188 ret += HPDF_Dict_AddName (image, "Type", "XObject");
189 ret += HPDF_Dict_AddName (image, "Subtype", "Image");
193 if (LoadJpegHeader (image, jpeg_data) != HPDF_OK)
196 if (HPDF_Stream_Seek (jpeg_data, 0, HPDF_SEEK_SET) != HPDF_OK)
200 HPDF_BYTE buf[HPDF_STREAM_BUF_SIZ];
201 HPDF_UINT len = HPDF_STREAM_BUF_SIZ;
202 HPDF_STATUS ret = HPDF_Stream_Read (jpeg_data, buf,
205 if (ret != HPDF_OK) {
206 if (ret == HPDF_STREAM_EOF) {
208 ret = HPDF_Stream_Write (image->stream, buf, len);
217 if (HPDF_Stream_Write (image->stream, buf, len) != HPDF_OK)
225 HPDF_Image_LoadJpegImageFromMem (HPDF_MMgr mmgr,
226 const HPDF_BYTE *buf,
230 HPDF_Stream jpeg_data;
233 HPDF_PTRACE ((" HPDF_Image_LoadJpegImageFromMem\n"));
235 jpeg_data = HPDF_MemStream_New(mmgr,size);
236 if (!HPDF_Stream_Validate (jpeg_data)) {
237 HPDF_RaiseError (mmgr->error, HPDF_INVALID_STREAM, 0);
241 if (HPDF_Stream_Write (jpeg_data, buf, size) != HPDF_OK) {
242 HPDF_Stream_Free (jpeg_data);
246 image = HPDF_Image_LoadJpegImage(mmgr,jpeg_data,xref);
248 /* destroy file stream */
249 HPDF_Stream_Free (jpeg_data);
256 HPDF_Image_LoadRawImage (HPDF_MMgr mmgr,
257 HPDF_Stream raw_data,
261 HPDF_ColorSpace color_space)
264 HPDF_STATUS ret = HPDF_OK;
267 HPDF_PTRACE ((" HPDF_Image_LoadRawImage\n"));
269 if (color_space != HPDF_CS_DEVICE_GRAY &&
270 color_space != HPDF_CS_DEVICE_RGB &&
271 color_space != HPDF_CS_DEVICE_CMYK) {
272 HPDF_SetError (mmgr->error, HPDF_INVALID_COLOR_SPACE, 0);
276 image = HPDF_DictStream_New (mmgr, xref);
280 image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
281 ret += HPDF_Dict_AddName (image, "Type", "XObject");
282 ret += HPDF_Dict_AddName (image, "Subtype", "Image");
286 if (color_space == HPDF_CS_DEVICE_GRAY) {
287 size = width * height;
288 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_GRAY);
289 } else if (color_space == HPDF_CS_DEVICE_CMYK) {
290 size = width * height * 4;
291 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_CMYK);
293 size = width * height * 3;
294 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_RGB);
300 if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
303 if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
306 if (HPDF_Dict_AddNumber (image, "BitsPerComponent", 8) != HPDF_OK)
309 if (HPDF_Stream_WriteToStream (raw_data, image->stream, 0, NULL) != HPDF_OK)
312 if (image->stream->size != size) {
313 HPDF_SetError (image->error, HPDF_INVALID_IMAGE, 0);
322 HPDF_Image_LoadRawImageFromMem (HPDF_MMgr mmgr,
323 const HPDF_BYTE *buf,
327 HPDF_ColorSpace color_space,
328 HPDF_UINT bits_per_component)
331 HPDF_STATUS ret = HPDF_OK;
334 HPDF_PTRACE ((" HPDF_Image_LoadRawImageFromMem\n"));
336 if (color_space != HPDF_CS_DEVICE_GRAY &&
337 color_space != HPDF_CS_DEVICE_RGB &&
338 color_space != HPDF_CS_DEVICE_CMYK) {
339 HPDF_SetError (mmgr->error, HPDF_INVALID_COLOR_SPACE, 0);
343 if (bits_per_component != 1 && bits_per_component != 2 &&
344 bits_per_component != 4 && bits_per_component != 8) {
345 HPDF_SetError (mmgr->error, HPDF_INVALID_IMAGE, 0);
349 image = HPDF_DictStream_New (mmgr, xref);
353 image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
354 ret += HPDF_Dict_AddName (image, "Type", "XObject");
355 ret += HPDF_Dict_AddName (image, "Subtype", "Image");
359 switch (color_space) {
360 case HPDF_CS_DEVICE_GRAY:
361 size = (HPDF_UINT)((HPDF_DOUBLE)width * height / (8 / bits_per_component) + 0.876);
362 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_GRAY);
364 case HPDF_CS_DEVICE_RGB:
365 size = (HPDF_UINT)((HPDF_DOUBLE)width * height / (8 / bits_per_component) + 0.876);
367 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_RGB);
369 case HPDF_CS_DEVICE_CMYK:
370 size = (HPDF_UINT)((HPDF_DOUBLE)width * height / (8 / bits_per_component) + 0.876);
372 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_CMYK);
380 if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
383 if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
386 if (HPDF_Dict_AddNumber (image, "BitsPerComponent", bits_per_component)
390 if (HPDF_Stream_Write (image->stream, buf, size) != HPDF_OK)
398 HPDF_Image_Validate (HPDF_Image image)
402 HPDF_PTRACE ((" HPDF_Image_Validate\n"));
407 if (image->header.obj_class != (HPDF_OSUBCLASS_XOBJECT |
409 HPDF_RaiseError (image->error, HPDF_INVALID_IMAGE, 0);
413 subtype = HPDF_Dict_GetItem (image, "Subtype", HPDF_OCLASS_NAME);
414 if (!subtype || HPDF_StrCmp (subtype->value, "Image") != 0) {
415 HPDF_RaiseError (image->error, HPDF_INVALID_IMAGE, 0);
423 HPDF_EXPORT(HPDF_Point)
424 HPDF_Image_GetSize (HPDF_Image image)
428 HPDF_Point ret = {0, 0};
430 HPDF_PTRACE ((" HPDF_Image_GetSize\n"));
432 if (!HPDF_Image_Validate (image))
435 width = HPDF_Dict_GetItem (image, "Width", HPDF_OCLASS_NUMBER);
436 height = HPDF_Dict_GetItem (image, "Height", HPDF_OCLASS_NUMBER);
438 if (width && height) {
439 ret.x = (HPDF_REAL)width->value;
440 ret.y = (HPDF_REAL)height->value;
446 HPDF_EXPORT(HPDF_STATUS)
447 HPDF_Image_GetSize2 (HPDF_Image image, HPDF_Point *size)
454 HPDF_PTRACE ((" HPDF_Image_GetSize\n"));
456 if (!HPDF_Image_Validate (image))
457 return HPDF_INVALID_IMAGE;
459 width = HPDF_Dict_GetItem (image, "Width", HPDF_OCLASS_NUMBER);
460 height = HPDF_Dict_GetItem (image, "Height", HPDF_OCLASS_NUMBER);
462 if (width && height) {
463 size->x = (HPDF_REAL)width->value;
464 size->y = (HPDF_REAL)height->value;
470 HPDF_EXPORT(HPDF_UINT)
471 HPDF_Image_GetBitsPerComponent (HPDF_Image image)
475 HPDF_PTRACE ((" HPDF_Image_GetBitsPerComponent\n"));
477 if (!HPDF_Image_Validate (image))
480 n = HPDF_Dict_GetItem (image, "BitsPerComponent", HPDF_OCLASS_NUMBER);
488 HPDF_EXPORT(const char*)
489 HPDF_Image_GetColorSpace (HPDF_Image image)
493 HPDF_PTRACE ((" HPDF_Image_GetColorSpace\n"));
495 n = HPDF_Dict_GetItem (image, "ColorSpace", HPDF_OCLASS_NAME);
500 HPDF_Error_Reset(image->error);
502 a = HPDF_Dict_GetItem (image, "ColorSpace", HPDF_OCLASS_ARRAY);
505 n = HPDF_Array_GetItem (a, 0, HPDF_OCLASS_NAME);
510 HPDF_CheckError (image->error);
517 HPDF_EXPORT(HPDF_UINT)
518 HPDF_Image_GetWidth (HPDF_Image image)
520 return (HPDF_UINT)HPDF_Image_GetSize (image).x;
523 HPDF_EXPORT(HPDF_UINT)
524 HPDF_Image_GetHeight (HPDF_Image image)
526 return (HPDF_UINT)HPDF_Image_GetSize (image).y;
530 HPDF_Image_SetMask (HPDF_Image image,
533 HPDF_Boolean image_mask;
535 if (!HPDF_Image_Validate (image))
536 return HPDF_INVALID_IMAGE;
538 if (mask && HPDF_Image_GetBitsPerComponent (image) != 1)
539 return HPDF_SetError (image->error, HPDF_INVALID_BIT_PER_COMPONENT,
542 image_mask = HPDF_Dict_GetItem (image, "ImageMask", HPDF_OCLASS_BOOLEAN);
545 image_mask = HPDF_Boolean_New (image->mmgr, HPDF_FALSE);
547 if ((ret = HPDF_Dict_Add (image, "ImageMask", image_mask)) != HPDF_OK)
551 image_mask->value = mask;
556 HPDF_EXPORT(HPDF_STATUS)
557 HPDF_Image_SetMaskImage (HPDF_Image image,
558 HPDF_Image mask_image)
560 if (!HPDF_Image_Validate (image))
561 return HPDF_INVALID_IMAGE;
563 if (!HPDF_Image_Validate (mask_image))
564 return HPDF_INVALID_IMAGE;
566 if (HPDF_Image_SetMask (mask_image, HPDF_TRUE) != HPDF_OK)
567 return HPDF_CheckError (image->error);
569 return HPDF_Dict_Add (image, "Mask", mask_image);
573 HPDF_EXPORT(HPDF_STATUS)
574 HPDF_Image_SetColorMask (HPDF_Image image,
584 HPDF_STATUS ret = HPDF_OK;
586 if (!HPDF_Image_Validate (image))
587 return HPDF_INVALID_IMAGE;
589 if (HPDF_Dict_GetItem (image, "ImageMask", HPDF_OCLASS_BOOLEAN))
590 return HPDF_RaiseError (image->error, HPDF_INVALID_OPERATION, 0);
592 if (HPDF_Image_GetBitsPerComponent (image) != 8)
593 return HPDF_RaiseError (image->error, HPDF_INVALID_BIT_PER_COMPONENT,
596 name = HPDF_Image_GetColorSpace (image);
597 if (!name || HPDF_StrCmp (COL_RGB, name) != 0)
598 return HPDF_RaiseError (image->error, HPDF_INVALID_COLOR_SPACE, 0);
600 /* Each integer must be in the range 0 to 2^BitsPerComponent - 1 */
601 if (rmax > 255 || gmax > 255 || bmax > 255)
602 return HPDF_RaiseError (image->error, HPDF_INVALID_PARAMETER, 0);
604 array = HPDF_Array_New (image->mmgr);
606 return HPDF_CheckError (image->error);
608 ret += HPDF_Dict_Add (image, "Mask", array);
609 ret += HPDF_Array_AddNumber (array, rmin);
610 ret += HPDF_Array_AddNumber (array, rmax);
611 ret += HPDF_Array_AddNumber (array, gmin);
612 ret += HPDF_Array_AddNumber (array, gmax);
613 ret += HPDF_Array_AddNumber (array, bmin);
614 ret += HPDF_Array_AddNumber (array, bmax);
617 return HPDF_CheckError (image->error);
622 HPDF_EXPORT(HPDF_STATUS)
623 HPDF_Image_AddSMask (HPDF_Image image,
629 if (!HPDF_Image_Validate (image))
630 return HPDF_INVALID_IMAGE;
631 if (!HPDF_Image_Validate (smask))
632 return HPDF_INVALID_IMAGE;
634 if (HPDF_Dict_GetItem (image, "SMask", HPDF_OCLASS_BOOLEAN))
635 return HPDF_RaiseError (image->error, HPDF_INVALID_OPERATION, 0);
637 name = HPDF_Image_GetColorSpace (smask);
638 if (!name || HPDF_StrCmp (COL_GRAY, name) != 0)
639 return HPDF_RaiseError (smask->error, HPDF_INVALID_COLOR_SPACE, 0);
641 return HPDF_Dict_Add (image, "SMask", smask);
645 HPDF_Image_SetColorSpace (HPDF_Image image,
646 HPDF_Array colorspace)
648 if (!HPDF_Image_Validate (image))
649 return HPDF_INVALID_IMAGE;
651 return HPDF_Dict_Add (image, "ColorSpace", colorspace);
656 HPDF_Image_SetRenderingIntent (HPDF_Image image,
659 if (!HPDF_Image_Validate (image))
660 return HPDF_INVALID_IMAGE;
662 return HPDF_Dict_AddName (image, "Intent", intent);