1 /******************************************************************************
2 images.c
3
4 Change Control: DDMMYYYY
5 Michael Still File created 29072000
6
7 Purpose:
8 Image insertion is all handled by one fuction, which then goes off and
9 calls the functions that know about particular image types...
10
11 Copyright (C) Michael Still 2000 - 2002
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 ******************************************************************************/
27
28 #if defined _WINDOWS
29 #include "stdafx.h"
30
31 #include "contrib/libtiff/tiffio.h"
32 #include "contrib/libjpeg/jpeglib.h"
33 #include "contrib/libpng/png.h"
34
35 #include <windows.h>
36
37 HANDLE winmutex;
38 #else
39 #include <panda/constants.h>
40 #include <panda/functions.h>
41
42 #if defined HAVE_LIBTIFF
43 #include <tiffio.h>
44 #endif
45
46 #if defined HAVE_LIBJPEG
47 #include <jpeglib.h>
48 #endif
49
50 #if defined HAVE_LIBPNG
51 #include <png.h>
52 #endif
53
54 #include <unistd.h>
55 #include <pthread.h>
56
57 pthread_mutex_t convMutex = PTHREAD_MUTEX_INITIALIZER;
58 #endif
59
60 #include <math.h>
61 #include <sys/stat.h>
62
63 static tsize_t libtiffDummyReadProc (thandle_t fd, tdata_t buf, tsize_t size);
64 static tsize_t libtiffDummyWriteProc (thandle_t fd, tdata_t buf,
65 tsize_t size);
66 static toff_t libtiffDummySeekProc (thandle_t fd, toff_t off, int i);
67 static int libtiffDummyCloseProc (thandle_t fd);
68
69 void libpngDummyWriteProc (png_structp png, png_bytep data, png_uint_32 len);
70 void libpngDummyFlushProc (png_structp png);
71
72 char *globalImageBuffer;
73 unsigned long globalImageBufferOffset;
74 char globalIsIDAT;
75
76 /******************************************************************************
77 DOCBOOK START
78
79 FUNCTION panda_imagebox
80 PURPOSE insert an image into the PDF document at the specified location
81
82 SYNOPSIS START
83 #include<panda/constants.h>
84 #include<panda/functions.h>
85 void panda_panda_imagebox (panda_pdf * output, panda_page * target, int top, int left, int bottom, int right, char *filename, int type);
86 SYNOPSIS END
87
88 DESCRIPTION This function call inserts an image into the PDF document at the specified location using a reasonable default for rotation (none). This call is included for backward compatability withprevious releases of the API and it is recommened that new code call <command>panda_imageboxrot</command>(). It is unlikely that this call will be retired however. The image types accepted by this call are: panda_image_tiff, panda_image_jpeg and panda_image_png.
89
90 RETURNS Nothing
91
92 EXAMPLE START
93 #include<panda/constants.h>
94 #include<panda/functions.h>
95
96 panda_pdf *demo;
97 panda_page *currPage;
98
99 panda_init ();
100
101 if ((demo = panda_open ("output.pdf", "w")) == NULL)
102 panda_error (panda_true, "demo: could not open output.pdf to write to.");
103
104 currPage = panda_newpage (demo, panda_pagesize_a4);
105
106 panda_imagebox (demo, currPage, 0, 0, currPage->height / 2,
107 currPage->width, "input.tif", panda_image_tiff);
108 EXAMPLE END
109 SEEALSO panda_imageboxrot
110 DOCBOOK END
111 ******************************************************************************/
112
113 // Imagebox now just calls panda_imageboxrot with a default rotational value
114 // Based on patches submitted by Ceasar Miquel (miquel@df.uba.ar)
115 void
panda_imagebox(panda_pdf * output,panda_page * target,int top,int left,int bottom,int right,char * filename,int type)116 panda_imagebox (panda_pdf * output, panda_page * target, int top, int left,
117 int bottom, int right, char *filename, int type)
118 {
119 panda_imageboxrot (output, target, top, left, bottom, right, 0.0,
120 filename, type);
121 }
122
123 /******************************************************************************
124 DOCBOOK START
125
126 FUNCTION panda_imageboxrot
127 PURPOSE insert an image into the PDF document at the specified location
128
129 SYNOPSIS START
130 #include<panda/constants.h>
131 #include<panda/functions.h>
132 void panda_panda_imageboxrot (panda_pdf * output, panda_page * target, int top, int left, int bottom, int right, double angle, char *filename, int type);
133 SYNOPSIS END
134
135 DESCRIPTION This function call inserts an image into the PDF document at the specified location, including the ability to rotate the image on the page. It should be noted that xpdf will sometimes make the rotated image look quite sickly. This is in fact a bug in xpdf (which has beenr eported), and not a bug in <command>Panda</command>. The image types accepted by this call are: panda_image_tiff, panda_image_jpeg and panda_image_png.
136 </para>
137 <para>
138 <emphasis>Note that this function now holds your hand and will save you from inerting an image with the same name over and over. Instead of regrabbing the image, it will just put a pointer to it inside the PDF itself. If you really want to use the same filename over and over with different images inside it, then use the</emphasis> <command>panda_imageboxactual</command>() call.
139
140 RETURNS Nothing
141
142 EXAMPLE START
143 #include<panda/constants.h>
144 #include<panda/functions.h>
145
146 panda_pdf *demo;
147 panda_page *currPage;
148
149 panda_init ();
150
151 if ((demo = panda_open ("output.pdf", "w")) == NULL)
152 panda_error (panda_true, "demo: could not open output.pdf to write to.");
153
154 currPage = panda_newpage (demo, panda_pagesize_a4);
155
156 panda_imagebox (demo, currPage, 0, 0, currPage->height / 2,
157 currPage->width, 45.0, "input.tif", panda_image_tiff);
158 EXAMPLE END
159 SEEALSO panda_imagebox
160 DOCBOOK END
161 ******************************************************************************/
162
163 // Check to see if we already have the image
164 void
panda_imageboxrot(panda_pdf * output,panda_page * target,int top,int left,int bottom,int right,double angle,char * filename,int type)165 panda_imageboxrot (panda_pdf * output, panda_page * target, int top, int left,
166 int bottom, int right, double angle, char *filename,
167 int type)
168 {
169 char *dbkey, *dbdata, *imageref;
170 int count;
171
172 #if defined DEBUG
173 printf ("Check to see if we have used this image before (%s)\n", filename);
174 #endif
175
176 count = 0;
177 dbkey = panda_xsnprintf ("image-%d-name", count);
178 while ((dbdata = panda_dbread (output, dbkey)) != NULL)
179 {
180 panda_xfree (dbkey);
181
182 if (strcmp (dbdata, filename) == 0)
183 {
184 #if defined DEBUG
185 printf
186 ("Found that this is a repeat ref to an image, and recycled\n");
187 #endif
188
189 dbkey = panda_xsnprintf ("image-%d-objectreference", count);
190 imageref = panda_dbread (output, dbkey);
191 panda_imageboxinternal (output, target, top, left, bottom, right,
192 angle, filename, type, panda_false,
193 imageref, -1);
194 panda_xfree (imageref);
195 panda_xfree (dbkey);
196 panda_xfree (dbdata);
197 return;
198 }
199
200 panda_xfree (dbdata);
201 dbkey = panda_xsnprintf ("image-%d-name", ++count);
202 }
203
204 panda_imageboxinternal (output, target, top, left, bottom, right, angle,
205 filename, type, panda_true, NULL, count);
206
207 panda_dbwrite (output, dbkey, filename);
208 panda_xfree (dbkey);
209 }
210
211 // todo_mikal: doco
212 // People might want to force me to add an image
213 void
panda_imageboxactual(panda_pdf * output,panda_page * target,int top,int left,int bottom,int right,double angle,char * filename,int type)214 panda_imageboxactual (panda_pdf * output, panda_page * target, int top,
215 int left, int bottom, int right, double angle,
216 char *filename, int type)
217 {
218 panda_imageboxinternal (output, target, top, left, bottom, right, angle,
219 filename, type, panda_true, NULL, -1);
220 }
221
222 // todo_mikal doco
223 // Redistribute the image types
224 void
panda_imageboxinternal(panda_pdf * output,panda_page * target,int top,int left,int bottom,int right,double angle,char * filename,int type,int addImage,char * objref,int databasecount)225 panda_imageboxinternal (panda_pdf * output, panda_page * target, int top,
226 int left, int bottom, int right, double angle,
227 char *filename, int type, int addImage,
228 char *objref, int databasecount)
229 {
230 panda_object *imageObj;
231 char *pdfFilename, *dictkey, *dbkey, *dbdata;
232 int i;
233
234 #if defined DEBUG
235 printf ("Started inserting an image (%d, %s, %d)\n", addImage, objref,
236 databasecount);
237 #endif
238
239 if (addImage == panda_true)
240 {
241 // Now we need an object to contain the image
242 imageObj = (panda_object *) panda_newobject (output, panda_normal);
243 panda_addchild (target->obj, imageObj);
244
245 if (databasecount != -1)
246 {
247 dbkey = panda_xsnprintf ("image-%d-objectreference", databasecount);
248 dbdata = panda_xsnprintf ("%d %d R",
249 imageObj->number, imageObj->generation);
250 panda_dbwrite (output, dbkey, dbdata);
251 panda_xfree (dbkey);
252 panda_xfree (dbdata);
253 }
254 }
255 else if (objref == NULL)
256 panda_error (panda_true, "Invalid image processing state\n");
257 #if defined DEBUG
258 else
259 printf ("Code is now recycling image... Good for the environment\n");
260 #endif
261
262 // We cannot have some characters in the filename that we embed into the PDF,
263 // so we fix them here
264 pdfFilename =
265 (char *) panda_xmalloc ((strlen (filename) + 1) * sizeof (char));
266 strcpy (pdfFilename, filename);
267
268 for (i = 0; i < strlen (pdfFilename) + 1; i++)
269 if (pdfFilename[i] == '/')
270 pdfFilename[i] = '-';
271
272 #if defined DEBUG
273 printf ("Filename for PDF was \"%s\" and is now \"%s\"\n",
274 filename, pdfFilename);
275 #endif
276
277 dictkey = panda_xsnprintf ("Resources/XObject/%s", pdfFilename);
278 if (objref == NULL)
279 panda_adddictitem (output, target->obj, dictkey, panda_objectvalue,
280 imageObj);
281 else
282 panda_adddictitem (output, target->obj, dictkey, panda_literaltextvalue,
283 objref);
284 panda_xfree (dictkey);
285
286 // We put some information based on a stat of the image file into the object
287 // This will allow us to determine if this file's image is included in the
288 // document again later, which will allow us avoid repetition of the same
289 // image data for no apparent reason -- note that this is not complete yet
290 // and we still need to add the existance check before the object is created
291 // and some form of object searching by a rational and efficient manner (a
292 // binary search tree?)
293
294 if (addImage == panda_true)
295 {
296 // We now add some dictionary elements to the image object to say that
297 // it is a TIFF image
298 panda_adddictitem (output, imageObj, "Type", panda_textvalue,
299 "XObject");
300 panda_adddictitem (output, imageObj, "Subtype", panda_textvalue,
301 "Image");
302
303 // This line will need to be changed to gaurantee that the internal
304 // name is unique unless the actual image is the same
305 panda_adddictitem (output, imageObj, "Name", panda_textvalue,
306 pdfFilename);
307 }
308
309 // Now we do the things that are image format specific... This is also
310 // where we check if support has been compiled in for the libraries we need.
311 switch (type)
312 {
313 case panda_image_tiff:
314 #if defined HAVE_LIBTIFF
315 if (addImage == panda_true)
316 panda_insertTIFF (output, target, imageObj, filename);
317 #else
318 fprintf (stderr, "%s %s\n",
319 "TIFF support not compiled into Panda because libtiff was",
320 "not found at compile time.");
321 panda_adddictitem (output, imageObj, "TIFF_Support_Missing",
322 panda_integervalue, 1);
323 #endif
324 break;
325
326 case panda_image_jpeg:
327 #if defined HAVE_LIBJPEG
328 if (addImage == panda_true)
329 panda_insertJPEG (output, target, imageObj, filename);
330 #else
331 fprintf (stderr, "%s %s\n",
332 "JPEG support not compiled into Panda because libjpeg was",
333 "not found at compile time.");
334 panda_adddictitem (output, imageObj, "JPEG_Support_Missing",
335 panda_integervalue, 1);
336 #endif
337 break;
338
339 case panda_image_png:
340 #if defined HAVE_LIBPNG
341 if (addImage == panda_true)
342 panda_insertPNG (output, target, imageObj, filename);
343 #else
344 fprintf (stderr, "%s %s\n",
345 "PNG support not compiled into Panda because libpng was not",
346 "found at compile time.");
347 panda_adddictitem (output, imageObj, "PNG_Support_Missing",
348 panda_integervalue, 1);
349 #endif
350 break;
351 }
352 // --------------------------------------------------------------------------
353
354 // We also need to add some information to the layout stream for the contents
355 // object for the page that the image is being displayed on. This information
356 // consists of the following [moved to internal.c]
357 panda_entergraphicsmode (target);
358
359 target->contents->layoutstream =
360 panda_streamprintf (target->contents->layoutstream,
361 "\n%.2f %.2f %.2f %.2f %.2f %.2f cm\n",
362 // The first matrix -- this has been modified
363 // because of patches submitted by Ceasar Miquel
364 // (miquel@df.uba.ar)
365 cos (angle * panda_pi / 180.0), // x scale
366 sin (angle * panda_pi / 180.0), // rotate and scale
367 -sin (angle * panda_pi / 180.0), // ???
368 cos (angle * panda_pi / 180.0), // y scale
369 (double) left, // x start
370 (double) target->height - bottom); // y start
371
372 target->contents->layoutstream =
373 panda_streamprintf (target->contents->layoutstream,
374 "%.2f %.2f %.2f %.2f %.2f %.2f cm\n",
375 // The second matrix
376 (double) (right - left), // x size
377 0.0, // ???
378 0.0, // ???
379 (double) (bottom - top), // y size
380 0.0, // ???
381 0.0); // ???
382
383 target->contents->layoutstream =
384 panda_streamprintf (target->contents->layoutstream, "/%s Do\n",
385 pdfFilename);
386
387 free (pdfFilename);
388 panda_exitgraphicsmode (target);
389
390 #if defined DEBUG
391 printf ("Finished inserting an image.\n");
392 #endif
393 }
394
395 /******************************************************************************
396 DOCBOOK START
397
398 FUNCTION panda_insertTIFF
399 PURPOSE insert a TIFF image into the PDF
400
401 SYNOPSIS START
402 #include<panda/constants.h>
403 #include<panda/functions.h>
404 void panda_insertTIFF (panda_pdf * output, panda_page * target, panda_object * imageObj, char *filename);
405 SYNOPSIS END
406
407 DESCRIPTION <command>PANDA INTERNAL</command>. Do the actual insertion of the TIFF image into the PDF document. This routine handles the conversion of the TIFF image into the form supported by the PDF specification, and similar operations. It is an internal <command>Panda</command> call and should not be needed by users of the API.
408
409 RETURNS Nothing
410
411 EXAMPLE START
412 See panda_imageboxrot for an example usage
413 EXAMPLE END
414 SEEALSO panda_imagebox, panda_imageboxrot, panda_insertJPEG, panda_insertPNG
415 DOCBOOK END
416 ******************************************************************************/
417
418 // This function will insert a TIFF image into a PDF
419 void
panda_insertTIFF(panda_pdf * output,panda_page * target,panda_object * imageObj,char * filename)420 panda_insertTIFF (panda_pdf * output, panda_page * target,
421 panda_object * imageObj, char *filename)
422 {
423 /**************************************************************************
424 Some notes about TIFF support inside PDF files.
425
426 - MSB2LSB is the only byte fillorder that is supported.
427 - The images must be converted to single strip
428 - G3 and G4 are supported
429 **************************************************************************/
430
431 TIFF *image, *conv;
432 int stripCount, stripMax;
433 tsize_t stripSize;
434 unsigned long imageOffset;
435 char *tempstream, *stripBuffer, *errMessage;
436 uint16 tiffResponse16, compression, fillorder;
437 int height, width;
438 uint32 theight, twidth;
439
440 // Open the file and make sure that it exists and is a TIFF file
441 if ((image = TIFFOpen (filename, "r")) == NULL)
442 {
443 errMessage =
444 panda_xsnprintf ("Could not open the specified TIFF image \"%s\".",
445 filename);
446 panda_error (panda_true, errMessage);
447 }
448
449 #if defined DEBUG
450 printf ("Inserting a TIFF image on page with object number %d.\n",
451 target->obj->number);
452 #endif
453
454 // Bits per component is per colour component, not per sample. Does this
455 // matter?
456 if (TIFFGetField (image, TIFFTAG_BITSPERSAMPLE, &tiffResponse16) != 0)
457 panda_adddictitem (output, imageObj, "BitsPerComponent",
458 panda_integervalue, tiffResponse16);
459 else
460 panda_error (panda_true,
461 "Could not get the colour depth for the tiff image.");
462
463 // The colour device will change based on the number of samples per pixel
464 if (TIFFGetField (image, TIFFTAG_SAMPLESPERPIXEL, &tiffResponse16) == 0)
465 panda_error
466 (panda_true,
467 "Could not get number of samples per pixel for a tiff image.");
468
469 switch (tiffResponse16)
470 {
471 case 1:
472 panda_adddictitem (output, imageObj, "ColorSpace", panda_textvalue,
473 "DeviceGray");
474 break;
475
476 default:
477 panda_adddictitem (output, imageObj, "ColorSpace", panda_textvalue,
478 "DeviceRGB");
479 break;
480 }
481
482 /****************************************************************************
483 We need to add a sub-dictionary with the parameters for the compression
484 filter in it.
485 ****************************************************************************/
486
487 // K will be minus one for g4 fax, and zero for g3 fax
488 TIFFGetField (image, TIFFTAG_COMPRESSION, &compression);
489 switch (compression)
490 {
491 case COMPRESSION_CCITTFAX3:
492 panda_adddictitem (output, imageObj, "Filter", panda_textvalue,
493 "CCITTFaxDecode");
494 panda_adddictitem (output, imageObj, "DecodeParms/K",
495 panda_integervalue, 0);
496 break;
497
498 case COMPRESSION_CCITTFAX4:
499 panda_adddictitem (output, imageObj, "Filter", panda_textvalue,
500 "CCITTFaxDecode");
501 panda_adddictitem (output, imageObj, "DecodeParms/K",
502 panda_integervalue, -1);
503 break;
504
505 case COMPRESSION_NONE:
506 // We put nothing here because it is not compressed
507 break;
508
509 case COMPRESSION_LZW:
510 panda_error (panda_true,
511 "LZW is encumbered with patents and therefore not supported.");
512 break;
513
514 default:
515 panda_error (panda_true, "Unsupported TIFF compression algorithm.");
516 break;
517 }
518
519 // Get the width and height of the image
520 panda_imagesizeTIFF (&width, &height, filename);
521
522 // Width of the image
523 panda_adddictitem (output, imageObj, "DecodeParms/Columns",
524 panda_integervalue, width);
525 panda_adddictitem (output, imageObj, "Width", panda_integervalue, width);
526
527 // Height of the image
528 panda_adddictitem (output, imageObj, "DecodeParms/Rows",
529 panda_integervalue, height);
530 panda_adddictitem (output, imageObj, "Height", panda_integervalue, height);
531
532 // Fillorder determines whether we convert on the fly or not, although
533 // multistrip images also need to be converted
534 TIFFGetField (image, TIFFTAG_FILLORDER, &fillorder);
535
536 if ((fillorder == FILLORDER_LSB2MSB) || (TIFFNumberOfStrips (image) > 1))
537 {
538 /*************************************************************************
539 Convert the image
540 *************************************************************************/
541
542 #if defined DEBUG
543 printf ("Conversion of the image in-memory will occur.\n");
544 #endif
545
546 // Because of the way this is implemented to integrate with the tiff lib
547 // we need to ensure that we are the only thread that is performing this
548 // operation at the moment. This is not a well coded piece of the library,
549 // but I am at a loss as to how to do it better... We don't check if we
550 // have already used global tiff buffer, because we are still using it's
551 // old contents...
552 #if defined _WINDOWS
553 winmutex = CreateMutex (NULL, TRUE, "Panda");
554 WaitForSingleObject (winmutex, INFINITE);
555 #else
556 pthread_mutex_lock (&convMutex);
557 #endif
558
559 globalImageBuffer = NULL;
560 globalImageBufferOffset = 0;
561
562 // Open the dummy document (which actually only exists in memory)
563 conv =
564 TIFFClientOpen ("dummy", "w", (thandle_t) - 1, libtiffDummyReadProc,
565 libtiffDummyWriteProc, libtiffDummySeekProc,
566 libtiffDummyCloseProc, NULL, NULL, NULL);
567
568 // Copy the image information ready for conversion
569 stripSize = TIFFStripSize (image);
570 stripMax = TIFFNumberOfStrips (image);
571 imageOffset = 0;
572
573 stripBuffer = panda_xmalloc (TIFFNumberOfStrips (image) * stripSize);
574
575 for (stripCount = 0; stripCount < stripMax; stripCount++)
576 {
577 #if defined DEBUG
578 printf ("Read a strip of the input image with offset %ld\n",
579 imageOffset);
580 #endif
581
582 imageOffset += TIFFReadEncodedStrip (image, stripCount,
583 stripBuffer + imageOffset,
584 stripSize);
585 }
586
587 // We also need to copy some of the attributes of the tiff image
588 // Bits per sample has to be 1 because this is going to be a G4/G3 image
589 // (and all other image formats were stripped out above).
590 twidth = width;
591 theight = height;
592 TIFFSetField (conv, TIFFTAG_IMAGEWIDTH, twidth);
593 TIFFSetField (conv, TIFFTAG_IMAGELENGTH, theight);
594 TIFFSetField (conv, TIFFTAG_BITSPERSAMPLE, 1);
595 TIFFSetField (conv, TIFFTAG_COMPRESSION, compression);
596 TIFFSetField (conv, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
597 TIFFSetField (conv, TIFFTAG_ROWSPERSTRIP, height + 1);
598 TIFFSetField (conv, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
599 TIFFSetField (conv, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
600 TIFFSetField (conv, TIFFTAG_SAMPLESPERPIXEL, 1);
601 TIFFSetField (conv, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
602 TIFFSetField (conv, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
603 TIFFSetField (conv, TIFFTAG_XRESOLUTION, 300);
604 TIFFSetField (conv, TIFFTAG_YRESOLUTION, 300);
605
606 if (compression == COMPRESSION_CCITTFAX4)
607 TIFFSetField (conv, TIFFTAG_GROUP4OPTIONS, 0);
608
609 #if defined DEBUG
610 printf ("The image buffer is %ld bytes long\n", imageOffset);
611 #endif
612
613 // Actually do the conversion
614 TIFFWriteEncodedStrip (conv, 0, stripBuffer, imageOffset);
615
616 // Finish up
617 free (stripBuffer);
618
619 #if defined DEBUG
620 printf ("The global tiff buffer became %ld bytes long\n",
621 globalImageBufferOffset);
622 #endif
623
624 imageObj->binarystream = globalImageBuffer;
625 imageObj->binarystreamLength = globalImageBufferOffset;
626
627 #if defined _WINDOWS
628 ReleaseMutex (winmutex);
629 #else
630 pthread_mutex_unlock (&convMutex);
631 #endif
632 }
633
634 else
635 {
636 /**************************************************************************
637 Insert the image
638 **************************************************************************/
639
640 #if defined DEBUG
641 printf ("Image is not being converted internally.\n");
642 #endif
643
644 // We also need to add a binary stream to the object and put the image
645 // data into this stream
646 stripSize = TIFFStripSize (image);
647 imageOffset = 0;
648
649 imageObj->binarystream =
650 panda_xmalloc (TIFFNumberOfStrips (image) * stripSize);
651
652 for (stripCount = 0; stripCount < TIFFNumberOfStrips (image);
653 stripCount++)
654 {
655 imageOffset += TIFFReadRawStrip (image, stripCount,
656 imageObj->binarystream +
657 imageOffset, stripSize);
658 }
659
660 // We might have too much memory, truncate to the size we have actually
661 // read
662 if ((tempstream = realloc (imageObj->binarystream, imageOffset)) !=
663 NULL)
664 imageObj->binarystream = tempstream;
665
666 // The image offset is the total size of the binary stream as well
667 imageObj->binarystreamLength = imageOffset;
668 }
669
670 TIFFClose (image);
671 }
672
673 /******************************************************************************
674 DOCBOOK START
675
676 FUNCTION panda_insertJPEG
677 PURPOSE insert a JPEG image into the PDF
678
679 SYNOPSIS START
680 #include<panda/constants.h>
681 #include<panda/functions.h>
682 void panda_insertJPEG (panda_pdf * output, panda_page * target, panda_object * imageObj, char *filename);
683 SYNOPSIS END
684
685 DESCRIPTION <command>PANDA INTERNAL</command>. Do the actual insertion of the JPEG image into the PDF document. This routine handles the conversion of the JPEG image into the form supported by the PDF specification, and similar operations. It is an internal <command>Panda</command> call and should not be needed by users of the API.
686
687 RETURNS Nothing
688
689 EXAMPLE START
690 See panda_imageboxrot for an example usage
691 EXAMPLE END
692 SEEALSO panda_imagebox, panda_imageboxrot, panda_insertTIFF, panda_insertPNG
693 DOCBOOK END
694 ******************************************************************************/
695
696 // This function will insert a JPEG image into a PDF
697 void
panda_insertJPEG(panda_pdf * output,panda_page * target,panda_object * imageObj,char * filename)698 panda_insertJPEG (panda_pdf * output, panda_page * target,
699 panda_object * imageObj, char *filename)
700 {
701 struct jpeg_decompress_struct cinfo;
702 struct jpeg_error_mgr jerr;
703 FILE *image;
704 int c;
705 unsigned long imageBufSize;
706
707 #if defined DEBUG
708 printf ("Inserting a JPEG image on page with object number %d.\n",
709 target->obj->number);
710 #endif
711
712 // Open the file -- why is this a memory leak?
713 if ((image = fopen (filename, "rb")) == NULL)
714 panda_error (panda_true, "Could not open the specified JPEG file.");
715
716 // Setup the decompression options
717 cinfo.err = jpeg_std_error (&jerr);
718
719 // Start decompressing
720 jpeg_create_decompress (&cinfo);
721 jpeg_stdio_src (&cinfo, image);
722 jpeg_read_header (&cinfo, TRUE);
723
724 // This dictionary item is JPEG specific
725 panda_adddictitem (output, imageObj, "Filter", panda_textvalue,
726 "DCTDecode");
727
728 // Bits per component -- I'm not sure exactly how this works with libjpeg.
729 // Is it possible to have a black and white jpeg? Ceasar Miquel
730 // (miquel@df.uba.ar) has submitted patches suggesting that this should
731 // always be 8, but this seems to work so I will leave it like this for now
732 panda_adddictitem (output, imageObj, "BitsPerComponent", panda_integervalue,
733 cinfo.data_precision);
734
735 // The colour device will change based on this number as well
736 switch (cinfo.jpeg_color_space)
737 {
738 case JCS_GRAYSCALE:
739 panda_adddictitem (output, imageObj, "ColorSpace", panda_textvalue,
740 "DeviceGray");
741 break;
742
743 default:
744 panda_adddictitem (output, imageObj, "ColorSpace", panda_textvalue,
745 "DeviceRGB");
746 break;
747 }
748
749 /****************************************************************************
750 Some details of the image
751 ****************************************************************************/
752
753 panda_adddictitem (output, imageObj, "Width", panda_integervalue,
754 cinfo.image_width);
755 panda_adddictitem (output, imageObj, "Height", panda_integervalue,
756 cinfo.image_height);
757
758 // This cleans things up for us in the JPEG library
759 jpeg_destroy_decompress (&cinfo);
760 fclose (image);
761
762 /****************************************************************************
763 Read the image into it's memory buffer
764 ****************************************************************************/
765
766 imageBufSize = 0;
767 imageObj->binarystreamLength = 0;
768
769 if ((image = fopen (filename, "rb")) == NULL)
770 panda_error (panda_true, "Could not open the JPEG file.");
771
772 while ((c = fgetc (image)) != EOF)
773 {
774 // We need to grow the buffer
775 if (imageBufSize == imageObj->binarystreamLength)
776 {
777 imageBufSize += 1024;
778
779 if ((imageObj->binarystream = realloc (imageObj->binarystream,
780 imageBufSize)) == NULL)
781 panda_error (panda_true,
782 "Could not make enough space for the JPEG image.");
783 }
784
785 // Store the info
786 imageObj->binarystream[imageObj->binarystreamLength++] = c;
787 }
788
789 imageObj->binarystream[imageObj->binarystreamLength++] = 0;
790 fclose (image);
791
792 #if defined DEBUG
793 printf ("Finished inserting the JPEG\n");
794 #endif
795 }
796
797 /******************************************************************************
798 DOCBOOK START
799
800 FUNCTION panda_insertPNG
801 PURPOSE insert a PNG image into the PDF
802
803 SYNOPSIS START
804 #include<panda/constants.h>
805 #include<panda/functions.h>
806 void panda_insertPNG (panda_pdf * output, panda_page * target, panda_object * imageObj, char *filename);
807 SYNOPSIS END
808
809 DESCRIPTION START
810 <command>PANDA INTERNAL</command>. Do the actual insertion of the PNG image into the PDF document. This routine handles the conversion of the PNG image into the form supported by the PDF specification, and similar operations. It is an internal <command>Panda</command> call and should not be needed by users of the API.
811
812 While developing this function call, some reference was made to the source code for iText (http://www.lowagie.com/iText), which is a GPL'ed PDF generator written in Java. The code in Panda is original though...
813 DESCRIPTION END
814
815 RETURNS Nothing
816
817 EXAMPLE START
818 See panda_imageboxrot for an example usage
819 EXAMPLE END
820 SEEALSO panda_imagebox, panda_imageboxrot, panda_insertJPEG, panda_insertTIFF
821 DOCBOOK END
822
823 -----------------------------------------------------------------------------
824 This code is loosely based on examples from the libpng package, as well as
825 some GPL'ed work from Paulo Soares for PNG insertion into PDFs using iText,
826 a Java PDF generator (http://www.lowagie.com/iText). The code below was,
827 however, written by mikal@stillhq.com... iText was merely used for hints on
828 how to do it.
829
830 The PNG specification is also a good read...
831 ******************************************************************************/
832
833 void
panda_insertPNG(panda_pdf * output,panda_page * target,panda_object * imageObj,char * filename)834 panda_insertPNG (panda_pdf * output, panda_page * target,
835 panda_object * imageObj, char *filename)
836 {
837 FILE *image;
838 png_uint_32 width, height;
839 int bitdepth, colourtype, outColourType;
840 png_uint_32 i, rowbytes;
841 png_structp png;
842 png_infop info;
843 unsigned char sig[8];
844 png_bytepp row_pointers = NULL;
845
846 #if defined DEBUG
847 printf ("Inserting a PNG image on page with object number %d.\n",
848 target->obj->number);
849 #endif
850
851 // Open the file
852 if ((image = fopen (filename, "rb")) == NULL)
853 panda_error (panda_true, "Could not open the specified PNG file.");
854
855 // Check that it really is a PNG file
856 fread (sig, 1, 8, image);
857 if (png_sig_cmp (sig, 0, 8))
858 panda_error (panda_true, "PNG file was invalid");
859
860 // Start decompressing
861 if ((png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
862 NULL, NULL)) == NULL)
863 panda_error (panda_true,
864 "Could not create a PNG read structure (out of memory?)");
865
866 if ((info = png_create_info_struct (png)) == NULL)
867 panda_error (panda_true,
868 "Could not create PNG info structure (out of memory?)");
869
870 // If panda_error did not exit, we would have to call png_destroy_read_struct
871
872 if (setjmp (png_jmpbuf (png)))
873 panda_error (panda_true, "Could not set PNG jump value");
874
875 // Get ready for IO and tell the API we have already read the image signature
876 // The IHDR chunk inside the PNG defines some info we need about the picture
877 // (see PNG specification 1.2, page 15).
878 png_init_io (png, image);
879 png_set_sig_bytes (png, 8);
880 png_read_info (png, info);
881 png_get_IHDR (png, info, &width, &height, &bitdepth, &colourtype, NULL,
882 NULL, NULL);
883
884 // This dictionary item is PNG specific, but until we put uncompressed
885 // data into the PDF
886 //panda_adddictitem (imageObj->dict, "Filter", panda_textvalue, "DCTDecode");
887
888 // Get the pixel depth for the image from the PNG
889 panda_adddictitem (output, imageObj, "BitsPerComponent", panda_integervalue,
890 bitdepth);
891
892 // I can't find any documentation for why the predictor should always be
893 // 15. If I ever do, then I will update this...
894 panda_adddictitem (output, imageObj, "DecodeParms/Predictor",
895 panda_integervalue, 15);
896 panda_adddictitem (output, imageObj, "DecodeParms/Columns",
897 panda_integervalue, width);
898 panda_adddictitem (output, imageObj, "DecodeParms/BitsPerComponent",
899 panda_integervalue, bitdepth);
900
901 // The colour device will change based on this number as well
902 switch (colourtype)
903 {
904 case PNG_COLOR_TYPE_GRAY:
905 case PNG_COLOR_TYPE_GRAY_ALPHA:
906 panda_adddictitem (output, imageObj, "ColorSpace", panda_textvalue,
907 "DeviceGray");
908 panda_adddictitem (output, imageObj, "DecodeParms/Colors",
909 panda_integervalue, 1);
910 outColourType = PNG_COLOR_TYPE_GRAY;
911 break;
912
913 default:
914 panda_adddictitem (output, imageObj, "ColorSpace", panda_textvalue,
915 "DeviceRGB");
916 panda_adddictitem (output, imageObj, "DecodeParms/Colors",
917 panda_integervalue, 3);
918 outColourType = PNG_COLOR_TYPE_RGB;
919 break;
920 }
921
922 /****************************************************************************
923 Some details of the image
924 ****************************************************************************/
925
926 panda_adddictitem (output, imageObj, "Width", panda_integervalue, width);
927 panda_adddictitem (output, imageObj, "Height", panda_integervalue, height);
928 panda_adddictitem (output, imageObj, "Filter", panda_textvalue,
929 "FlateDecode");
930
931 /****************************************************************************
932 Now actually insert the image. libpng lets us do some cool stuff with
933 the data before it is handed to us like expanding it to our expectations.
934 I don't use this at the moment, but reserve the right to one day...
935
936 We read the image into a memory buffer...
937 ****************************************************************************/
938
939 /****************************************************************************
940 Read the image into it's memory buffer
941 ****************************************************************************/
942
943 if (colourtype == PNG_COLOR_TYPE_PALETTE)
944 png_set_expand (png);
945 // if(colourtype & PNG_COLOR_MASK_ALPHA)
946 png_set_strip_alpha (png);
947 png_read_update_info (png, info);
948
949 rowbytes = png_get_rowbytes (png, info);
950 imageObj->binarystream =
951 (unsigned char *) panda_xmalloc ((rowbytes * height) + 1);
952 imageObj->binarystreamLength = rowbytes * height;
953 row_pointers = panda_xmalloc (height * sizeof (png_bytep));
954
955 // Get the image bitmap
956 for (i = 0; i < height; ++i)
957 row_pointers[i] = imageObj->binarystream + (i * rowbytes);
958 png_read_image (png, row_pointers);
959 // free(row_pointers);
960 png_read_end (png, NULL);
961
962 imageObj->binarystream[imageObj->binarystreamLength++] = 0;
963 fclose (image);
964
965 // This cleans things up for us in the PNG library
966 png_destroy_read_struct (&png, &info, NULL);
967
968 /****************************************************************************
969 ... And now we write that image out into another memory buffer (this one
970 compressed) via some funky callbacks to libpng...
971 ****************************************************************************/
972
973 if ((png =
974 png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL,
975 NULL)) == NULL)
976 panda_error (panda_true,
977 "Could not create write structure for PNG (out of memory?)");
978
979 if ((info = png_create_info_struct (png)) == NULL)
980 panda_error
981 (panda_true,
982 "Could not create PNG info structure for writing (out of memory?)");
983
984 if (setjmp (png_jmpbuf (png)))
985 panda_error (panda_true, "Could not set the PNG jump value for writing");
986
987 // If this call is done before png_create_write_struct, then everything seg faults...
988 #if defined _WINDOWS
989 winmutex = CreateMutex (NULL, TRUE, "Panda");
990 WaitForSingleObject (winmutex, INFINITE);
991 #else
992 pthread_mutex_lock (&convMutex);
993 #endif
994
995 png_set_write_fn (png, NULL, (png_rw_ptr) libpngDummyWriteProc,
996 (png_flush_ptr) libpngDummyFlushProc);
997 globalIsIDAT = panda_false;
998 globalImageBuffer = NULL;
999 globalImageBufferOffset = 0;
1000
1001 png_set_IHDR (png, info, width, height, bitdepth, outColourType,
1002 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
1003 PNG_FILTER_TYPE_DEFAULT);
1004 png_write_info (png, info);
1005
1006 png_write_image (png, row_pointers);
1007 png_write_end (png, info);
1008 png_destroy_write_struct (&png, &info);
1009
1010 /****************************************************************************
1011 ... Finally, we have something that we can insert into the PDF stream
1012 ****************************************************************************/
1013
1014 // Sometimes this might clobber and existing binary stream
1015 if (imageObj->binarystream != NULL)
1016 free (imageObj->binarystream);
1017
1018 // We don't need row_pointers any more
1019 if (row_pointers != NULL)
1020 free (row_pointers);
1021
1022 imageObj->binarystream = globalImageBuffer;
1023 imageObj->binarystreamLength = globalImageBufferOffset;
1024
1025 #if defined _WINDOWS
1026 ReleaseMutex (winmutex);
1027 #else
1028 pthread_mutex_unlock (&convMutex);
1029 #endif
1030 }
1031
1032 /*****************************************************************************
1033 The following are dummy functions for libtiff that will allow us to do on-
1034 the-fly conversion of tiff images to the small subset of tiff that the
1035 PDF specification allows for...
1036 *****************************************************************************/
1037
1038 /******************************************************************************
1039 DOCBOOK START
1040
1041 FUNCTION libtiffDummyReadProc
1042 PURPOSE mangle libtiff to do image conversion in memory without temportary files
1043
1044 SYNOPSIS START
1045 static tsize_t libtiffDummyReadProc (thandle_t fd, tdata_t buf, tsize_t size);
1046 SYNOPSIS END
1047
1048 DESCRIPTION <command>PANDA INTERNAL</command>. This call implements a dummy read procedure for libtiff to allow for the conversion of TIFF images on the fly in memory without the use of temporary files. It is an internal call and should NEVER be called by users of the API.
1049
1050 RETURNS The amount of data read
1051
1052 EXAMPLE START
1053 See panda_insertTIFF for an example usage
1054 EXAMPLE END
1055 SEEALSO panda_insertTIFF, libtiffDummWriteProc
1056 DOCBOOK END
1057 ******************************************************************************/
1058
1059 static tsize_t
libtiffDummyReadProc(thandle_t fd,tdata_t buf,tsize_t size)1060 libtiffDummyReadProc (thandle_t fd, tdata_t buf, tsize_t size)
1061 {
1062 // Return the amount of data read, which we will always set as 0 because
1063 // we only need to be able to write to these in-memory tiffs
1064 return 0;
1065 }
1066
1067 /******************************************************************************
1068 DOCBOOK START
1069
1070 FUNCTION libtiffDummyWriteProc
1071 PURPOSE mangle libtiff to do image conversion in memory without temportary files
1072
1073 SYNOPSIS START
1074 static tsize_t libtiffDummyWriteProc (thandle_t fd, tdata_t buf, tsize_t size);
1075 SYNOPSIS END
1076
1077 DESCRIPTION <command>PANDA INTERNAL</command>. This call implements a dummy write procedure for libtiff to allow for the conversion of TIFF images on the fly in memory without the use of temporary files. It is an internal call and should NEVER be called by users of the API.
1078
1079 RETURNS The amount of daat written
1080
1081 EXAMPLE START
1082 See panda_insertTIFF for an example usage
1083 EXAMPLE END
1084 SEEALSO panda_insertTIFF, libtiffDummWriteProc
1085 DOCBOOK END
1086 ******************************************************************************/
1087
1088 /* Yes, I know global variables are bad, and this will be changed in the near
1089 future. If you are reading this code and are disgusted, then feel free to
1090 send me a patch at mikal@stillhq.com */
1091
1092 static tsize_t
libtiffDummyWriteProc(thandle_t fd,tdata_t buf,tsize_t size)1093 libtiffDummyWriteProc (thandle_t fd, tdata_t buf, tsize_t size)
1094 {
1095
1096 #if defined DEBUG
1097 printf ("TIFF dummy write procedure called\n");
1098 #endif
1099
1100 // libtiff will try to write an 8 byte header into the tiff file. We need
1101 // to ignore this because PDF does not use it...
1102 if ((size == 8) && (((char *) buf)[0] == 'I') && (((char *) buf)[1] == 'I')
1103 && (((char *) buf)[2] == 42))
1104 {
1105 // Skip the header -- little endian
1106 }
1107 else if ((size == 8) && (((char *) buf)[0] == 'M') &&
1108 (((char *) buf)[1] == 'M') && (((char *) buf)[2] == 42))
1109 {
1110 // Skip the header -- big endian
1111 }
1112 else
1113 {
1114 // Have we done anything yet?
1115 if (globalImageBuffer == NULL)
1116 globalImageBuffer = (char *) panda_xmalloc (size * sizeof (char));
1117
1118 // Otherwise, we need to grow the memory buffer
1119 else
1120 {
1121 if ((globalImageBuffer = (char *) realloc (globalImageBuffer,
1122 (size * sizeof (char)) +
1123 globalImageBufferOffset))
1124 == NULL)
1125 panda_error (panda_true,
1126 "Could not grow the tiff conversion memory buffer.");
1127 }
1128
1129 // Now move the image data into the buffer
1130 memcpy (globalImageBuffer + globalImageBufferOffset, buf, size);
1131 globalImageBufferOffset += size;
1132 }
1133
1134 return (size);
1135 }
1136
1137 /******************************************************************************
1138 DOCBOOK START
1139
1140 FUNCTION libtiffDummySeekProc
1141 PURPOSE mangle libtiff to doc image conversion in memory without temportary files
1142
1143 SYNOPSIS START
1144 static toff_t libtiffDummySeekProc (thandle_t, toff_t off, int i);
1145 SYNOPSIS END
1146
1147 DESCRIPTION <command>PANDA INTERNAL</command>. This call implements a dummy seek procedure for libtiff to allow for the conversion of TIFF images on the fly in memory without the use of temporary files. It is an internal call and should NEVER be called by users of the API.
1148
1149 RETURNS Where the seek took us to
1150
1151 EXAMPLE START
1152 See panda_insertTIFF for an example usage
1153 EXAMPLE END
1154 SEEALSO panda_insertTIFF, libtiffDummWriteProc
1155 DOCBOOK END
1156 ******************************************************************************/
1157
1158 static toff_t
libtiffDummySeekProc(thandle_t fd,toff_t off,int i)1159 libtiffDummySeekProc (thandle_t fd, toff_t off, int i)
1160 {
1161 // This appears to return the location that it went to
1162 return off;
1163 }
1164
1165 /******************************************************************************
1166 DOCBOOK START
1167
1168 FUNCTION libtiffDummyCloseProc
1169 PURPOSE mangle libtiff to do image conversion in memory without temportary files
1170
1171 SYNOPSIS START
1172 static int libtiffDummyCloseProc (thandle_t);
1173 SYNOPSIS END
1174
1175 DESCRIPTION <command>PANDA INTERNAL</command>. This call implements a dummy close procedure for libtiff to allow for the conversion of TIFF images on the fly in memory without the use of temporary files. It is an internal call and should NEVER be called by users of the API.
1176
1177 RETURNS Zero
1178
1179 EXAMPLE START
1180 See panda_insertTIFF for an example usage
1181 EXAMPLE END
1182 SEEALSO panda_insertTIFF, libtiffDummWriteProc
1183 DOCBOOK END
1184 ******************************************************************************/
1185
1186 static int
libtiffDummyCloseProc(thandle_t fd)1187 libtiffDummyCloseProc (thandle_t fd)
1188 {
1189 // Return a zero meaning all is well
1190 return 0;
1191 }
1192
1193 /******************************************************************************
1194 DOCBOOK START
1195
1196 FUNCTION libpngDummyWriteProc
1197 PURPOSE mangle libpng to do image conversion in memory without temportary files
1198
1199 SYNOPSIS START
1200 void libpngDummyWriteProc(png_structp png, png_bytep data, png_uint_32 len);
1201 SYNOPSIS END
1202
1203 DESCRIPTION <command>PANDA INTERNAL</command>. This call implements a dummy write proceedure for libpng. This is needed so that Panda can get at the compressed PNG data, whilst converting it on the fly from unsupported PNG variants, and while not having to deal with temporary files. PDF documents only need the content of the IDAT chunks within the PNG file, and this method eases gaining access to those chunks.
1204
1205 RETURNS Zero
1206
1207 EXAMPLE START
1208 See panda_insertPNG for an example usage
1209 EXAMPLE END
1210 SEEALSO panda_insertPNG, libpngDummyReadProc, libpngDummyFlushProc
1211 DOCBOOK END
1212 ******************************************************************************/
1213
1214 void
libpngDummyWriteProc(png_structp png,png_bytep data,png_uint_32 len)1215 libpngDummyWriteProc (png_structp png, png_bytep data, png_uint_32 len)
1216 {
1217 char tempString[5];
1218
1219 // Copy the first 4 bytes into a string
1220 tempString[0] = data[0];
1221 tempString[1] = data[1];
1222 tempString[2] = data[2];
1223 tempString[3] = data[3];
1224 tempString[4] = '\0';
1225
1226 // If we know this is an IDAT, then copy the compressed image information
1227 if (globalIsIDAT == panda_true)
1228 {
1229 #if defined DEBUG
1230 printf ("Inserted %d bytes into the PNG\n", len);
1231 #endif
1232
1233 // Have we done anything yet?
1234 if (globalImageBuffer == NULL)
1235 globalImageBuffer = (char *) panda_xmalloc (len * sizeof (char));
1236
1237 // Otherwise, we need to grow the memory buffer
1238 else
1239 {
1240 if ((globalImageBuffer = (char *) realloc (globalImageBuffer,
1241 (len * sizeof (char)) +
1242 globalImageBufferOffset))
1243 == NULL)
1244 panda_error (panda_true,
1245 "Could not grow the png conversion memory buffer.");
1246 }
1247
1248 // Now move the image data into the buffer
1249 memcpy (globalImageBuffer + globalImageBufferOffset, data, len);
1250 globalImageBufferOffset += len;
1251
1252 globalIsIDAT = panda_false;
1253 }
1254 else if ((len == 4) && (strcmp (tempString, "IDAT") == 0))
1255 globalIsIDAT = panda_true;
1256 else
1257 globalIsIDAT = panda_false;
1258 }
1259
1260 /******************************************************************************
1261 DOCBOOK START
1262
1263 FUNCTION libpngDummyFlushProc
1264 PURPOSE mangle libpng to do image conversion in memory without temportary files
1265
1266 SYNOPSIS START
1267 void libpngDummyFlushProc(png_structp png);
1268 SYNOPSIS END
1269
1270 DESCRIPTION <command>PANDA INTERNAL</command>. This call implements a dummy flush proceedure for libpng. This is needed so that Panda can get at the compressed PNG data, whilst converting it on the fly from unsupported PNG variants, and while not having to deal with temporary files. PDF documents only need the content of the IDAT chunks within the PNG file, and this method eases gaining access to those chunks.
1271
1272 RETURNS Zero
1273
1274 EXAMPLE START
1275 See panda_insertPNG for an example usage
1276 EXAMPLE END
1277 SEEALSO panda_insertPNG, libpngDummyReadProc, libpngDummyWriteProc
1278 DOCBOOK END
1279 ******************************************************************************/
1280
1281 void
libpngDummyFlushProc(png_structp png)1282 libpngDummyFlushProc (png_structp png)
1283 {
1284 }
1285
1286
1287 /******************************************************************************
1288 DOCBOOK START
1289
1290 FUNCTION panda_imagesize
1291 PURPOSE determine the size of an image
1292
1293 SYNOPSIS START
1294 #include<panda/constants.h>
1295 #include<panda/functions.h>
1296 void panda_panda_imagesize (int *width, int *height, char *filename, int type);
1297 SYNOPSIS END
1298
1299 DESCRIPTION This function can be used to determine the size of an image before a <command>panda_imagebox</command>() function call.
1300 RETURNS Nothing
1301
1302 EXAMPLE START
1303 #include<panda/constants.h>
1304 #include<panda/functions.h>
1305
1306 int height, width;
1307
1308 panda_init ();
1309
1310 panda_imagesize (&width, &height, "input.tif", panda_image_tiff);
1311 EXAMPLE END
1312 SEEALSO panda_imagebox, panda_imageboxrot
1313 DOCBOOK END
1314 ******************************************************************************/
1315 void
panda_imagesize(int * width,int * height,char * filename,int type)1316 panda_imagesize (int *width, int *height, char *filename, int type)
1317 {
1318 *width = 0;
1319 *height = 0;
1320 switch (type)
1321
1322 {
1323 case panda_image_tiff:
1324
1325 #if defined HAVE_LIBTIFF
1326 panda_imagesizeTIFF (width, height, filename);
1327
1328 #else /* */
1329 fprintf (stderr, "%s %s\n",
1330 "TIFF support not compiled into Panda because libtiff was",
1331 "not found at compile time.");
1332
1333 #endif /* */
1334 break;
1335 case panda_image_jpeg:
1336
1337 #if defined HAVE_LIBJPEG
1338 panda_imagesizeJPEG (width, height, filename);
1339
1340 #else /* */
1341 fprintf (stderr, "%s %s\n",
1342 "JPEG support not compiled into Panda because libjpeg was",
1343 "not found at compile time.");
1344
1345 #endif /* */
1346 break;
1347 case panda_image_png:
1348
1349 #if defined HAVE_LIBPNG
1350 panda_imagesizePNG (width, height, filename);
1351
1352 #else /* */
1353 fprintf (stderr, "%s %s\n",
1354 "PNG support not compiled into Panda because libpng was not",
1355 "found at compile time.");
1356
1357 #endif /* */
1358 break;
1359 }
1360 }
1361 void
panda_imagesizeTIFF(int * width,int * height,char * filename)1362 panda_imagesizeTIFF (int *width, int *height, char *filename)
1363 {
1364 uint32 twidth, theight;
1365 TIFF * image;
1366 if ((image = TIFFOpen (filename, "r")) == NULL)
1367 panda_error (panda_true, "Could not open TIFF image to determine size");
1368 TIFFGetField (image, TIFFTAG_IMAGEWIDTH, &twidth);
1369 TIFFGetField (image, TIFFTAG_IMAGELENGTH, &theight);
1370 *width = twidth;
1371 *height = theight;
1372 }
1373 void
panda_imagesizeJPEG(int * width,int * height,char * filename)1374 panda_imagesizeJPEG (int *width, int *height, char *filename)
1375 {
1376 struct jpeg_decompress_struct cinfo;
1377 struct jpeg_error_mgr jerr;
1378 FILE * image;
1379
1380 // Open the file -- why is this a memory leak?
1381 if ((image = fopen (filename, "rb")) == NULL)
1382 panda_error (panda_true, "Could not open the specified JPEG file.");
1383
1384 // Setup the decompression options
1385 cinfo.err = jpeg_std_error (&jerr);
1386
1387 // Start decompressing
1388 jpeg_create_decompress (&cinfo);
1389 jpeg_stdio_src (&cinfo, image);
1390 jpeg_read_header (&cinfo, TRUE);
1391 *width = cinfo.image_width;
1392 *height = cinfo.image_height;
1393
1394 // This cleans things up for us in the JPEG library
1395 jpeg_destroy_decompress (&cinfo);
1396 fclose (image);
1397 }
1398 void
panda_imagesizePNG(int * width,int * height,char * filename)1399 panda_imagesizePNG (int *width, int *height, char *filename)
1400 {
1401 FILE * image;
1402 png_uint_32 pwidth, pheight;
1403 int bitdepth, colourtype;
1404 png_structp png;
1405 png_infop info;
1406 unsigned char sig[8];
1407
1408 // Open the file
1409 if ((image = fopen (filename, "rb")) == NULL)
1410 panda_error (panda_true, "Could not open the specified PNG file.");
1411
1412 // Check that it really is a PNG file
1413 fread (sig, 1, 8, image);
1414 if (png_sig_cmp (sig, 0, 8))
1415 panda_error (panda_true, "PNG file was invalid");
1416
1417 // Start decompressing
1418 if ((png =
1419 png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL,
1420 NULL)) == NULL)
1421 panda_error (panda_true,
1422 "Could not create a PNG read structure (out of memory?)");
1423 if ((info = png_create_info_struct (png)) == NULL)
1424 panda_error (panda_true,
1425 "Could not create PNG info structure (out of memory?)");
1426
1427 // If panda_error did not exit, we would have to call png_destroy_read_struct
1428 if (setjmp (png_jmpbuf (png)))
1429 panda_error (panda_true, "Could not set PNG jump value");
1430
1431 // Get ready for IO and tell the API we have already read the image signature
1432 // The IHDR chunk inside the PNG defines some info we need about the picture
1433 // (see PNG specification 1.2, page 15).
1434 png_init_io (png, image);
1435 png_set_sig_bytes (png, 8);
1436 png_read_info (png, info);
1437 png_get_IHDR (png, info, &pwidth, &pheight, &bitdepth, &colourtype, NULL,
1438 NULL, NULL);
1439 *width = pwidth;
1440 *height = pheight;
1441 }
1442