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&lt;panda/constants.h&gt;
84 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
94 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
131 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
144 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
403 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
681 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
805 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
1295 #include&lt;panda/functions.h&gt;
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&lt;panda/constants.h&gt;
1304 #include&lt;panda/functions.h&gt;
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