1/*
2 * << Haru Free PDF Library >> -- hpdf_image.c
3 *
4 * URL: http://libharu.org
5 *
6 * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
7 * Copyright (c) 2007-2009 Antony Dovgal <tony@daylessday.org>
8 *
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.
15 *
16 */
17
18#include "hpdf_conf.h"
19#include "hpdf_utils.h"
20#include "hpdf.h"
21
22static const char *COL_CMYK = "DeviceCMYK";
23static const char *COL_RGB = "DeviceRGB";
24static const char *COL_GRAY = "DeviceGray";
25
26static HPDF_STATUS
27LoadJpegHeader (HPDF_Image image,
28 HPDF_Stream stream);
29
30
31/*---------------------------------------------------------------------------*/
32
33static HPDF_STATUS
34LoadJpegHeader (HPDF_Image image,
35 HPDF_Stream stream)
36{
37 HPDF_UINT16 tag;
38 HPDF_UINT16 height;
39 HPDF_UINT16 width;
40 HPDF_BYTE precision;
41 HPDF_BYTE num_components;
42 const char *color_space_name;
43 HPDF_UINT len;
44 HPDF_STATUS ret;
45 HPDF_Array array;
46
47 HPDF_PTRACE ((" HPDF_Image_LoadJpegHeader\n"));
48
49 len = 2;
50 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&tag, &len) != HPDF_OK)
51 return HPDF_Error_GetCode (stream->error);
52
53 HPDF_UInt16Swap (&tag);
54 if (tag != 0xFFD8)
55 return HPDF_INVALID_JPEG_DATA;
56
57 /* find SOF record */
58 for (;;) {
59 HPDF_UINT16 size;
60
61 len = 2;
62 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&tag, &len) != HPDF_OK)
63 return HPDF_Error_GetCode (stream->error);
64
65 HPDF_UInt16Swap (&tag);
66
67 len = 2;
68 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&size, &len) != HPDF_OK)
69 return HPDF_Error_GetCode (stream->error);
70
71 HPDF_UInt16Swap (&size);
72
73 HPDF_PTRACE (("tag=%04X size=%u\n", tag, size));
74
75 if (tag == 0xFFC0 || tag == 0xFFC1 ||
76 tag == 0xFFC2 || tag == 0xFFC9) {
77
78 len = 1;
79 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&precision, &len) !=
80 HPDF_OK)
81 return HPDF_Error_GetCode (stream->error);
82
83 len = 2;
84 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&height, &len) !=
85 HPDF_OK)
86 return HPDF_Error_GetCode (stream->error);
87
88 HPDF_UInt16Swap (&height);
89
90 len = 2;
91 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&width, &len) != HPDF_OK)
92 return HPDF_Error_GetCode (stream->error);
93
94 HPDF_UInt16Swap (&width);
95
96 len = 1;
97 if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&num_components, &len) !=
98 HPDF_OK)
99 return HPDF_Error_GetCode (stream->error);
100
101 break;
102 } else if ((tag | 0x00FF) != 0xFFFF)
103 /* lost marker */
104 return HPDF_SetError (image->error, HPDF_UNSUPPORTED_JPEG_FORMAT,
105 0);
106
107 if (HPDF_Stream_Seek (stream, size - 2, HPDF_SEEK_CUR) != HPDF_OK)
108 return HPDF_Error_GetCode (stream->error);
109 }
110
111 if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
112 return HPDF_Error_GetCode (stream->error);
113
114 if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
115 return HPDF_Error_GetCode (stream->error);
116
117 /* classification of RGB and CMYK is less than perfect
118 * YCbCr and YCCK are classified into RGB or CMYK.
119 *
120 * It is necessary to read APP14 data to distinguish colorspace perfectly.
121
122 */
123 switch (num_components) {
124 case 1:
125 color_space_name = COL_GRAY;
126 break;
127 case 3:
128 color_space_name = COL_RGB;
129 break;
130 case 4:
131 array = HPDF_Array_New (image->mmgr);
132 if (!array)
133 return HPDF_Error_GetCode (stream->error);
134
135 ret = HPDF_Dict_Add (image, "Decode", array);
136 if (ret != HPDF_OK)
137 return HPDF_Error_GetCode (stream->error);
138
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));
147
148 if (ret != HPDF_OK)
149 return HPDF_Error_GetCode (stream->error);
150
151 color_space_name = COL_CMYK;
152
153 break;
154 default:
155 return HPDF_SetError (image->error, HPDF_UNSUPPORTED_JPEG_FORMAT,
156 0);
157 }
158
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);
162
163 if (HPDF_Dict_Add (image, "BitsPerComponent",
164 HPDF_Number_New (image->mmgr, precision)) != HPDF_OK)
165 return HPDF_Error_GetCode (stream->error);
166
167 return HPDF_OK;
168}
169
170HPDF_Image
171HPDF_Image_LoadJpegImage (HPDF_MMgr mmgr,
172 HPDF_Stream jpeg_data,
173 HPDF_Xref xref)
174{
175 HPDF_Dict image;
176 HPDF_STATUS ret = HPDF_OK;
177
178 HPDF_PTRACE ((" HPDF_Image_LoadJpegImage\n"));
179
180 image = HPDF_DictStream_New (mmgr, xref);
181 if (!image)
182 return NULL;
183
184 image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
185
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");
190 if (ret != HPDF_OK)
191 return NULL;
192
193 if (LoadJpegHeader (image, jpeg_data) != HPDF_OK)
194 return NULL;
195
196 if (HPDF_Stream_Seek (jpeg_data, 0, HPDF_SEEK_SET) != HPDF_OK)
197 return NULL;
198
199 for (;;) {
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,
203 &len);
204
205 if (ret != HPDF_OK) {
206 if (ret == HPDF_STREAM_EOF) {
207 if (len > 0) {
208 ret = HPDF_Stream_Write (image->stream, buf, len);
209 if (ret != HPDF_OK)
210 return NULL;
211 }
212 break;
213 } else
214 return NULL;
215 }
216
217 if (HPDF_Stream_Write (image->stream, buf, len) != HPDF_OK)
218 return NULL;
219 }
220
221 return image;
222}
223
224HPDF_Image
225HPDF_Image_LoadJpegImageFromMem (HPDF_MMgr mmgr,
226 const HPDF_BYTE *buf,
227 HPDF_UINT size,
228 HPDF_Xref xref)
229{
230 HPDF_Stream jpeg_data;
231 HPDF_Image image;
232
233 HPDF_PTRACE ((" HPDF_Image_LoadJpegImageFromMem\n"));
234
235 jpeg_data = HPDF_MemStream_New(mmgr,size);
236 if (!HPDF_Stream_Validate (jpeg_data)) {
237 HPDF_RaiseError (mmgr->error, HPDF_INVALID_STREAM, 0);
238 return NULL;
239 }
240
241 if (HPDF_Stream_Write (jpeg_data, buf, size) != HPDF_OK) {
242 HPDF_Stream_Free (jpeg_data);
243 return NULL;
244 }
245
246 image = HPDF_Image_LoadJpegImage(mmgr,jpeg_data,xref);
247
248 /* destroy file stream */
249 HPDF_Stream_Free (jpeg_data);
250
251 return image;
252}
253
254
255HPDF_Image
256HPDF_Image_LoadRawImage (HPDF_MMgr mmgr,
257 HPDF_Stream raw_data,
258 HPDF_Xref xref,
259 HPDF_UINT width,
260 HPDF_UINT height,
261 HPDF_ColorSpace color_space)
262{
263 HPDF_Dict image;
264 HPDF_STATUS ret = HPDF_OK;
265 HPDF_UINT size;
266
267 HPDF_PTRACE ((" HPDF_Image_LoadRawImage\n"));
268
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);
273 return NULL;
274 }
275
276 image = HPDF_DictStream_New (mmgr, xref);
277 if (!image)
278 return NULL;
279
280 image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
281 ret += HPDF_Dict_AddName (image, "Type", "XObject");
282 ret += HPDF_Dict_AddName (image, "Subtype", "Image");
283 if (ret != HPDF_OK)
284 return NULL;
285
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);
292 } else {
293 size = width * height * 3;
294 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_RGB);
295 }
296
297 if (ret != HPDF_OK)
298 return NULL;
299
300 if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
301 return NULL;
302
303 if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
304 return NULL;
305
306 if (HPDF_Dict_AddNumber (image, "BitsPerComponent", 8) != HPDF_OK)
307 return NULL;
308
309 if (HPDF_Stream_WriteToStream (raw_data, image->stream, 0, NULL) != HPDF_OK)
310 return NULL;
311
312 if (image->stream->size != size) {
313 HPDF_SetError (image->error, HPDF_INVALID_IMAGE, 0);
314 return NULL;
315 }
316
317 return image;
318}
319
320
321HPDF_Image
322HPDF_Image_LoadRawImageFromMem (HPDF_MMgr mmgr,
323 const HPDF_BYTE *buf,
324 HPDF_Xref xref,
325 HPDF_UINT width,
326 HPDF_UINT height,
327 HPDF_ColorSpace color_space,
328 HPDF_UINT bits_per_component)
329{
330 HPDF_Dict image;
331 HPDF_STATUS ret = HPDF_OK;
332 HPDF_UINT size=0;
333
334 HPDF_PTRACE ((" HPDF_Image_LoadRawImageFromMem\n"));
335
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);
340 return NULL;
341 }
342
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);
346 return NULL;
347 }
348
349 image = HPDF_DictStream_New (mmgr, xref);
350 if (!image)
351 return NULL;
352
353 image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
354 ret += HPDF_Dict_AddName (image, "Type", "XObject");
355 ret += HPDF_Dict_AddName (image, "Subtype", "Image");
356 if (ret != HPDF_OK)
357 return NULL;
358
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);
363 break;
364 case HPDF_CS_DEVICE_RGB:
365 size = (HPDF_UINT)((HPDF_DOUBLE)width * height / (8 / bits_per_component) + 0.876);
366 size *= 3;
367 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_RGB);
368 break;
369 case HPDF_CS_DEVICE_CMYK:
370 size = (HPDF_UINT)((HPDF_DOUBLE)width * height / (8 / bits_per_component) + 0.876);
371 size *= 4;
372 ret = HPDF_Dict_AddName (image, "ColorSpace", COL_CMYK);
373 break;
374 default:;
375 }
376
377 if (ret != HPDF_OK)
378 return NULL;
379
380 if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
381 return NULL;
382
383 if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
384 return NULL;
385
386 if (HPDF_Dict_AddNumber (image, "BitsPerComponent", bits_per_component)
387 != HPDF_OK)
388 return NULL;
389
390 if (HPDF_Stream_Write (image->stream, buf, size) != HPDF_OK)
391 return NULL;
392
393 return image;
394}
395
396
397HPDF_BOOL
398HPDF_Image_Validate (HPDF_Image image)
399{
400 HPDF_Name subtype;
401
402 HPDF_PTRACE ((" HPDF_Image_Validate\n"));
403
404 if (!image)
405 return HPDF_FALSE;
406
407 if (image->header.obj_class != (HPDF_OSUBCLASS_XOBJECT |
408 HPDF_OCLASS_DICT)) {
409 HPDF_RaiseError (image->error, HPDF_INVALID_IMAGE, 0);
410 return HPDF_FALSE;
411 }
412
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);
416 return HPDF_FALSE;
417 }
418
419 return HPDF_TRUE;
420}
421
422
423HPDF_EXPORT(HPDF_Point)
424HPDF_Image_GetSize (HPDF_Image image)
425{
426 HPDF_Number width;
427 HPDF_Number height;
428 HPDF_Point ret = {0, 0};
429
430 HPDF_PTRACE ((" HPDF_Image_GetSize\n"));
431
432 if (!HPDF_Image_Validate (image))
433 return ret;
434
435 width = HPDF_Dict_GetItem (image, "Width", HPDF_OCLASS_NUMBER);
436 height = HPDF_Dict_GetItem (image, "Height", HPDF_OCLASS_NUMBER);
437
438 if (width && height) {
439 ret.x = (HPDF_REAL)width->value;
440 ret.y = (HPDF_REAL)height->value;
441 }
442
443 return ret;
444}
445
446HPDF_EXPORT(HPDF_STATUS)
447HPDF_Image_GetSize2 (HPDF_Image image, HPDF_Point *size)
448{
449 HPDF_Number width;
450 HPDF_Number height;
451 size->x = 0;
452 size->y = 0;
453
454 HPDF_PTRACE ((" HPDF_Image_GetSize\n"));
455
456 if (!HPDF_Image_Validate (image))
457 return HPDF_INVALID_IMAGE;
458
459 width = HPDF_Dict_GetItem (image, "Width", HPDF_OCLASS_NUMBER);
460 height = HPDF_Dict_GetItem (image, "Height", HPDF_OCLASS_NUMBER);
461
462 if (width && height) {
463 size->x = (HPDF_REAL)width->value;
464 size->y = (HPDF_REAL)height->value;
465 }
466
467 return HPDF_OK;
468}
469
470HPDF_EXPORT(HPDF_UINT)
471HPDF_Image_GetBitsPerComponent (HPDF_Image image)
472{
473 HPDF_Number n;
474
475 HPDF_PTRACE ((" HPDF_Image_GetBitsPerComponent\n"));
476
477 if (!HPDF_Image_Validate (image))
478 return 0;
479
480 n = HPDF_Dict_GetItem (image, "BitsPerComponent", HPDF_OCLASS_NUMBER);
481
482 if (!n)
483 return 0;
484
485 return n->value;
486}
487
488HPDF_EXPORT(const char*)
489HPDF_Image_GetColorSpace (HPDF_Image image)
490{
491 HPDF_Name n;
492
493 HPDF_PTRACE ((" HPDF_Image_GetColorSpace\n"));
494
495 n = HPDF_Dict_GetItem (image, "ColorSpace", HPDF_OCLASS_NAME);
496
497 if (!n) {
498 HPDF_Array a;
499
500 HPDF_Error_Reset(image->error);
501
502 a = HPDF_Dict_GetItem (image, "ColorSpace", HPDF_OCLASS_ARRAY);
503
504 if (a) {
505 n = HPDF_Array_GetItem (a, 0, HPDF_OCLASS_NAME);
506 }
507 }
508
509 if (!n) {
510 HPDF_CheckError (image->error);
511 return NULL;
512 }
513
514 return n->value;
515}
516
517HPDF_EXPORT(HPDF_UINT)
518HPDF_Image_GetWidth (HPDF_Image image)
519{
520 return (HPDF_UINT)HPDF_Image_GetSize (image).x;
521}
522
523HPDF_EXPORT(HPDF_UINT)
524HPDF_Image_GetHeight (HPDF_Image image)
525{
526 return (HPDF_UINT)HPDF_Image_GetSize (image).y;
527}
528
529HPDF_STATUS
530HPDF_Image_SetMask (HPDF_Image image,
531 HPDF_BOOL mask)
532{
533 HPDF_Boolean image_mask;
534
535 if (!HPDF_Image_Validate (image))
536 return HPDF_INVALID_IMAGE;
537
538 if (mask && HPDF_Image_GetBitsPerComponent (image) != 1)
539 return HPDF_SetError (image->error, HPDF_INVALID_BIT_PER_COMPONENT,
540 0);
541
542 image_mask = HPDF_Dict_GetItem (image, "ImageMask", HPDF_OCLASS_BOOLEAN);
543 if (!image_mask) {
544 HPDF_STATUS ret;
545 image_mask = HPDF_Boolean_New (image->mmgr, HPDF_FALSE);
546
547 if ((ret = HPDF_Dict_Add (image, "ImageMask", image_mask)) != HPDF_OK)
548 return ret;
549 }
550
551 image_mask->value = mask;
552 return HPDF_OK;
553}
554
555
556HPDF_EXPORT(HPDF_STATUS)
557HPDF_Image_SetMaskImage (HPDF_Image image,
558 HPDF_Image mask_image)
559{
560 if (!HPDF_Image_Validate (image))
561 return HPDF_INVALID_IMAGE;
562
563 if (!HPDF_Image_Validate (mask_image))
564 return HPDF_INVALID_IMAGE;
565
566 if (HPDF_Image_SetMask (mask_image, HPDF_TRUE) != HPDF_OK)
567 return HPDF_CheckError (image->error);
568
569 return HPDF_Dict_Add (image, "Mask", mask_image);
570}
571
572
573HPDF_EXPORT(HPDF_STATUS)
574HPDF_Image_SetColorMask (HPDF_Image image,
575 HPDF_UINT rmin,
576 HPDF_UINT rmax,
577 HPDF_UINT gmin,
578 HPDF_UINT gmax,
579 HPDF_UINT bmin,
580 HPDF_UINT bmax)
581{
582 HPDF_Array array;
583 const char *name;
584 HPDF_STATUS ret = HPDF_OK;
585
586 if (!HPDF_Image_Validate (image))
587 return HPDF_INVALID_IMAGE;
588
589 if (HPDF_Dict_GetItem (image, "ImageMask", HPDF_OCLASS_BOOLEAN))
590 return HPDF_RaiseError (image->error, HPDF_INVALID_OPERATION, 0);
591
592 if (HPDF_Image_GetBitsPerComponent (image) != 8)
593 return HPDF_RaiseError (image->error, HPDF_INVALID_BIT_PER_COMPONENT,
594 0);
595
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);
599
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);
603
604 array = HPDF_Array_New (image->mmgr);
605 if (!array)
606 return HPDF_CheckError (image->error);
607
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);
615
616 if (ret != HPDF_OK)
617 return HPDF_CheckError (image->error);
618
619 return HPDF_OK;
620}
621
622HPDF_EXPORT(HPDF_STATUS)
623HPDF_Image_AddSMask (HPDF_Image image,
624 HPDF_Image smask)
625{
626
627 const char *name;
628
629 if (!HPDF_Image_Validate (image))
630 return HPDF_INVALID_IMAGE;
631 if (!HPDF_Image_Validate (smask))
632 return HPDF_INVALID_IMAGE;
633
634 if (HPDF_Dict_GetItem (image, "SMask", HPDF_OCLASS_BOOLEAN))
635 return HPDF_RaiseError (image->error, HPDF_INVALID_OPERATION, 0);
636
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);
640
641 return HPDF_Dict_Add (image, "SMask", smask);
642}
643
644HPDF_STATUS
645HPDF_Image_SetColorSpace (HPDF_Image image,
646 HPDF_Array colorspace)
647{
648 if (!HPDF_Image_Validate (image))
649 return HPDF_INVALID_IMAGE;
650
651 return HPDF_Dict_Add (image, "ColorSpace", colorspace);
652}
653
654
655HPDF_STATUS
656HPDF_Image_SetRenderingIntent (HPDF_Image image,
657 const char* intent)
658{
659 if (!HPDF_Image_Validate (image))
660 return HPDF_INVALID_IMAGE;
661
662 return HPDF_Dict_AddName (image, "Intent", intent);
663}
664
665