~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to lib/image/imageUtilPng.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-15 21:21:40 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080815212140-05fhxj8wroosysmj
Tags: 2008.08.08-109361-1ubuntu1
* Merge from Debian unstable (LP: #258393), remaining Ubuntu change:
  - add ubuntu_toolchain_FTBFS.dpatch patch, fix FTBFS
* Update ubuntu_toolchain_FTBFS.dpatch patch for the new version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2002 VMware, Inc. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License as published
 
6
 * by the Free Software Foundation version 2.1 and no later version.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
10
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
 
11
 * License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/*
 
20
 * imageUtilPng.c -- 
 
21
 *
 
22
 *      This file contains platform independent code to read and write PNG files
 
23
 *      using libpng. 
 
24
 */
 
25
 
 
26
#include "vmware.h"
 
27
#include "imageUtil.h"
 
28
#include "rasterConv.h"
 
29
#include "util.h"
 
30
 
 
31
#include <png.h>
 
32
#include <stdlib.h>
 
33
 
 
34
#define PNG_HEADER_CHECK_BUF_SIZE  8
 
35
 
 
36
typedef struct ImageUtilReadPng {
 
37
   unsigned char *data;
 
38
   unsigned int offset;
 
39
} ImageUtilReadPng;
 
40
 
 
41
/*
 
42
 *-----------------------------------------------------------------------------
 
43
 *
 
44
 * ImageUtilReadPngCallback --
 
45
 *
 
46
 *      Callback function for reading from a PNG file.
 
47
 *
 
48
 * Results:
 
49
 *      None.
 
50
 *
 
51
 * Side effects:
 
52
 *      Fills buffer `data' by reading from the file.  Note that png_error()
 
53
 *      calls longjmp() so that an error will unwind the stack.
 
54
 *
 
55
 *-----------------------------------------------------------------------------
 
56
 */
 
57
 
 
58
void
 
59
ImageUtilReadPngCallback(png_structp png_ptr,   // IN: PNG file info structure
 
60
                         png_bytep data,        // OUT: input buffer
 
61
                         png_size_t length)     // IN: byte count
 
62
{
 
63
   ImageUtilReadPng *pngData = png_get_io_ptr(png_ptr);
 
64
   memcpy(data, pngData->data + pngData->offset, length);
 
65
   pngData->offset += (unsigned int)length;
 
66
}
 
67
 
 
68
 
 
69
/*
 
70
 *----------------------------------------------------------------------------
 
71
 *
 
72
 * ImageUtil_ReadPNGBuffer --
 
73
 *
 
74
 *      Loads and reads the specified PNG file and returns its attributes and
 
75
 *      data in the provided out parameters. 
 
76
 *
 
77
 * Results:
 
78
 *      Lots. 
 
79
 *
 
80
 * Side effects:
 
81
 *      Reads PNG from disk. 
 
82
 *
 
83
 *----------------------------------------------------------------------------
 
84
 */
 
85
 
 
86
Bool 
 
87
ImageUtil_ReadPNGBuffer(ImageInfo *image,          // OUT
 
88
                        const unsigned char *data, // IN
 
89
                        size_t dataLen)            // IN
 
90
{
 
91
   png_structp png_ptr;
 
92
   png_infop info_ptr;
 
93
   int i, channel_depth, color_type, interlace_type, compression_type, filter_type;
 
94
   png_colorp palette;
 
95
   int num_palette = 0; 
 
96
   int bytes_per_line;
 
97
   png_bytep *row_pointers = NULL;
 
98
   Bool ret = FALSE;
 
99
   ImageUtilReadPng *pngData = NULL;
 
100
   png_uint_32 width;
 
101
   png_uint_32 height;
 
102
 
 
103
   if (!image || !data || !dataLen) {
 
104
      return FALSE;
 
105
   }
 
106
 
 
107
   pngData = Util_SafeCalloc(1, sizeof *pngData);
 
108
   pngData->data = (char *) data;
 
109
   pngData->offset = 0;
 
110
 
 
111
   /* 
 
112
    * Do an initial check to make sure this is a PNG file. This check also
 
113
    * eliminate the case of 0-byte file due to the previous write error
 
114
    */
 
115
   if (dataLen < PNG_HEADER_CHECK_BUF_SIZE) {
 
116
      goto exit;
 
117
   }
 
118
 
 
119
   if (png_sig_cmp(pngData->data, 0, PNG_HEADER_CHECK_BUF_SIZE)) {
 
120
      goto exit;
 
121
   }
 
122
 
 
123
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
124
 
 
125
   if (png_ptr == NULL) {
 
126
      goto exit;
 
127
   }
 
128
 
 
129
   /* Allocate/initialize the memory for image information. */
 
130
   info_ptr = png_create_info_struct(png_ptr);
 
131
   if (info_ptr == NULL) {
 
132
      png_destroy_read_struct(&png_ptr, NULL, NULL);
 
133
      goto exit;
 
134
   }
 
135
 
 
136
   if (setjmp(png_ptr->jmpbuf)) {
 
137
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
138
      goto exit;
 
139
   }
 
140
 
 
141
   png_set_read_fn(png_ptr, pngData, ImageUtilReadPngCallback);
 
142
 
 
143
   png_read_info(png_ptr, info_ptr);
 
144
 
 
145
   png_get_IHDR(png_ptr, info_ptr, 
 
146
                &width, &height,
 
147
                &channel_depth, &color_type,
 
148
                &interlace_type, &compression_type, &filter_type);
 
149
 
 
150
   bytes_per_line = png_get_rowbytes(png_ptr, info_ptr);
 
151
 
 
152
   if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
 
153
      /*
 
154
       * Strip out alpha
 
155
       */
 
156
      png_set_strip_alpha(png_ptr);
 
157
 
 
158
      /* Update the bytes_per_line now that we've eliminated the alpha channel */
 
159
      png_read_update_info(png_ptr, info_ptr);
 
160
      bytes_per_line = png_get_rowbytes(png_ptr, info_ptr);
 
161
 
 
162
      png_get_IHDR(png_ptr, info_ptr, 
 
163
                   &width, &height, 
 
164
                   &channel_depth, &color_type, &interlace_type, 
 
165
                   &compression_type, &filter_type);
 
166
      image->bpp = 24;
 
167
   } else if (color_type == PNG_COLOR_TYPE_RGB) {
 
168
      image->bpp = 24;  
 
169
   } else if (color_type == PNG_COLOR_TYPE_PALETTE) {
 
170
      /*
 
171
       * Load palette
 
172
       */
 
173
      if (channel_depth < 8) {
 
174
         png_set_packing(png_ptr);
 
175
         png_read_update_info(png_ptr, info_ptr);
 
176
         bytes_per_line = png_get_rowbytes(png_ptr, info_ptr);
 
177
      }
 
178
 
 
179
      image->bpp = 8; 
 
180
 
 
181
      png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
 
182
      ASSERT(num_palette <= 256); 
 
183
 
 
184
      for (i = 0; i < num_palette; i++) {
 
185
         image->palette[i].red = palette[i].red;
 
186
         image->palette[i].green = palette[i].green;
 
187
         image->palette[i].blue = palette[i].blue;
 
188
         image->palette[i].reserved = 0;
 
189
      }
 
190
 
 
191
      image->numColors = num_palette; 
 
192
   } else {
 
193
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
194
      goto exit;
 
195
   }
 
196
 
 
197
   image->width = width;
 
198
   image->height = height;
 
199
   image->bytesPerLine = DWORD_ALIGN(bytes_per_line);
 
200
   image->depth = image->bpp;
 
201
   image->flags = 0;
 
202
 
 
203
   /* BGR instead of RGB - Intel byte-order is backwards */
 
204
   png_set_bgr(png_ptr);
 
205
 
 
206
   /* Allocate the memory to hold the image using the fields of info_ptr. */
 
207
   image->data = Util_SafeMalloc(image->bytesPerLine * image->height);
 
208
   row_pointers = Util_SafeMalloc(sizeof *row_pointers * image->height);
 
209
 
 
210
   /* The easiest way to read the image: */
 
211
   for (i = 0; i < image->height; i++) {
 
212
      row_pointers[i] = image->data + i * (DWORD_ALIGN(bytes_per_line));
 
213
   }
 
214
 
 
215
   png_read_image(png_ptr, row_pointers);
 
216
   png_read_end(png_ptr, info_ptr);
 
217
 
 
218
#ifdef VMX86_DEVEL
 
219
   /* Read text fields (XXX eventually read rectangle data here) */
 
220
   {
 
221
      png_text *text_ptr = NULL;
 
222
      int num_text = 0;
 
223
 
 
224
      if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) {
 
225
         for(i = 0; i < num_text; i++) {
 
226
            fprintf(stderr, "Png text: (%s) %s\n", text_ptr[i].key,
 
227
                    text_ptr[i].text);
 
228
         }
 
229
      }
 
230
   }
 
231
#endif
 
232
 
 
233
   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
234
   ret = TRUE;
 
235
 
 
236
  exit:
 
237
   free(row_pointers);
 
238
   free(pngData);
 
239
   return ret;
 
240
}
 
241
 
 
242
 
 
243
/*
 
244
 *----------------------------------------------------------------------------
 
245
 *
 
246
 * ImageUtilDataWriteCallback
 
247
 *
 
248
 *      Callback for the png library to write data into the DynBuf.
 
249
 *
 
250
 * Results:
 
251
 *      None.
 
252
 *
 
253
 * Side effects:
 
254
 *      Writes data to DynBuf.
 
255
 *
 
256
 *----------------------------------------------------------------------------
 
257
 */
 
258
 
 
259
void
 
260
ImageUtilDataWriteCallback(png_structp png_ptr,         // IN
 
261
                           png_bytep data,              // IN
 
262
                           png_size_t length)           // IN
 
263
{
 
264
   DynBuf *imageData = png_get_io_ptr(png_ptr);
 
265
   if (!DynBuf_Append(imageData, data, length)) {
 
266
      png_error(png_ptr, "Unable to append data");
 
267
   }
 
268
}
 
269
 
 
270
 
 
271
/*
 
272
 *----------------------------------------------------------------------------
 
273
 *
 
274
 * ImageUtil_ConstructPNGBuffer --
 
275
 *
 
276
 *      Writes a PNG of the image to the DynBuf passed in.
 
277
 *
 
278
 * Results:
 
279
 *      TRUE if successful, FALSE otherwise.
 
280
 *
 
281
 * Side effects:
 
282
 *      If successful, imageData should be destroyed.
 
283
 *
 
284
 *----------------------------------------------------------------------------
 
285
 */
 
286
 
 
287
Bool
 
288
ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN
 
289
                             DynBuf *imageData)      // OUT
 
290
 
 
291
{
 
292
   ImagePngOptions options;
 
293
 
 
294
   options.zlibCompressLevel = -1;
 
295
   options.stripAlphaChannel = TRUE;
 
296
 
 
297
   return ImageUtil_ConstructPNGBufferEx(image, &options, imageData);
 
298
}
 
299
 
 
300
 
 
301
/*
 
302
 *----------------------------------------------------------------------------
 
303
 *
 
304
 * ImageUtil_ConstructPNGBufferEx --
 
305
 *
 
306
 *      Writes a PNG of the image to the DynBuf passed in. Accepts a zlib
 
307
 *      compression level (0-9, 0 means no compression, -1 means "use the
 
308
 *      default").
 
309
 *
 
310
 * Results:
 
311
 *      TRUE if successful, FALSE otherwise.
 
312
 *
 
313
 * Side effects:
 
314
 *      Allocates memory; If successful, imageData needs to be cleaned up later.
 
315
 *
 
316
 *----------------------------------------------------------------------------
 
317
 */
 
318
 
 
319
Bool
 
320
ImageUtil_ConstructPNGBufferEx(const ImageInfo *image,         // IN
 
321
                               const ImagePngOptions *options, // IN
 
322
                               DynBuf *imageData)              // OUT
 
323
{
 
324
   png_structp png_ptr;
 
325
   png_infop info_ptr;
 
326
   int color_type, i;
 
327
   png_bytep data;
 
328
   
 
329
   //png_text text_ptr[1];
 
330
#ifdef RGB_MASK
 
331
   png_color_8 sig_bit;
 
332
#endif
 
333
 
 
334
   png_uint_32 k;
 
335
 
 
336
   int bytes_per_line;
 
337
   png_bytep *row_pointers;
 
338
 
 
339
   ASSERT(image);
 
340
   ASSERT(imageData);
 
341
   ASSERT(options);
 
342
 
 
343
   if (!image || !options || !imageData) {
 
344
      return FALSE;
 
345
   }
 
346
 
 
347
   row_pointers = malloc(sizeof *row_pointers * image->height);
 
348
   if (!row_pointers) {
 
349
      return FALSE;
 
350
   }
 
351
 
 
352
   DynBuf_Init(imageData);
 
353
 
 
354
   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
355
 
 
356
   if (png_ptr == NULL) {
 
357
      goto error;
 
358
   }
 
359
 
 
360
   /* Allocate/initialize the image information data.  REQUIRED */
 
361
   info_ptr = png_create_info_struct(png_ptr);
 
362
   if (info_ptr == NULL) {
 
363
      png_destroy_write_struct(&png_ptr, NULL);
 
364
      goto error;
 
365
   }
 
366
 
 
367
   if (setjmp(png_ptr->jmpbuf)) {
 
368
      png_destroy_write_struct(&png_ptr, &info_ptr);
 
369
      goto error;
 
370
   }
 
371
 
 
372
   png_set_write_fn(png_ptr, imageData, ImageUtilDataWriteCallback, NULL);
 
373
 
 
374
   if (image->bpp <= 8) {
 
375
      /*
 
376
       * Save palette
 
377
       */
 
378
      color_type = PNG_COLOR_TYPE_PALETTE;
 
379
   } else if (image->bpp == 32) {
 
380
      /*
 
381
       * Save with alpha channel
 
382
       */
 
383
      color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 
384
   } else {
 
385
      /*
 
386
       * Everything else is RGB
 
387
       */
 
388
      color_type = PNG_COLOR_TYPE_RGB;
 
389
   }
 
390
 
 
391
   png_set_IHDR(png_ptr, info_ptr, image->width, image->height, 8, color_type,
 
392
                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 
393
 
 
394
   if (options->zlibCompressLevel >= 0 && options->zlibCompressLevel <= 9) {
 
395
      png_set_compression_level(png_ptr, options->zlibCompressLevel);
 
396
   }
 
397
 
 
398
#ifdef RGB_MASK
 
399
   /* Setup the color depths */
 
400
   sig_bit.red = COUNT_BITS(image->redMask);
 
401
   sig_bit.green = COUNT_BITS(image->greenMask);
 
402
   sig_bit.blue = COUNT_BITS(image->blueMask);
 
403
   png_set_sBIT(png_ptr, info_ptr, &sig_bit);
 
404
 
 
405
#if 1 //We probably DO need this
 
406
   /* Shift the pixels up to a legal bit depth and fill in
 
407
    * as appropriate to correctly scale the image.
 
408
    */
 
409
   png_set_shift(png_ptr, &sig_bit);
 
410
#endif
 
411
#endif
 
412
 
 
413
   // BGR instead of RGB - Intel byte-order is backwards
 
414
   png_set_bgr(png_ptr);
 
415
 
 
416
   /* 
 
417
    * Optionally write comments into the image, e.g.
 
418
    *   text_ptr[0].key = "Title";
 
419
    *   text_ptr[0].text = "Mona Lisa";
 
420
    *   text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
 
421
    *   png_set_text(png_ptr, info_ptr, text_ptr, 1);
 
422
    */
 
423
 
 
424
 
 
425
   /* 
 
426
    * Now set up the transformations you want.  Note that these are
 
427
    * all optional.  Only call them if you want them.
 
428
    */
 
429
   bytes_per_line = image->bytesPerLine;
 
430
 
 
431
#if 0
 
432
   /* pack pixels into bytes */
 
433
   png_set_packing(png_ptr);
 
434
#endif
 
435
 
 
436
   data = image->data;
 
437
 
 
438
   if (image->bpp == 24) {
 
439
      /*
 
440
       * The image is already RGB, no need for any conversion/processing
 
441
       */
 
442
   } else if (image->bpp <= 8) {
 
443
      /*
 
444
       * Save palette
 
445
       */
 
446
      png_color palette[256];
 
447
      ASSERT(image->numColors <= 256);
 
448
 
 
449
      for (i = 0; i < image->numColors; i++) {
 
450
         palette[i].red = image->palette[i].red;
 
451
         palette[i].green = image->palette[i].green;
 
452
         palette[i].blue = image->palette[i].blue;
 
453
      }
 
454
 
 
455
      png_set_PLTE(png_ptr, info_ptr, palette, image->numColors);
 
456
   } else if (image->bpp == 32) {
 
457
      if (options->stripAlphaChannel) {
 
458
 
 
459
         /*
 
460
          * Strip the alpha channel
 
461
          */
 
462
 
 
463
         png_set_strip_alpha(png_ptr);
 
464
 
 
465
         /*
 
466
          * XXX: Following call appears to leak two allocations of 1 byte
 
467
          * each deep inside the png library via png_malloc.
 
468
          */
 
469
         png_read_update_info(png_ptr, info_ptr);
 
470
      }
 
471
   } else {
 
472
      /* XXX convert to 24 - we could try and support other modes? */
 
473
      bytes_per_line = DWORD_ALIGN(png_get_rowbytes(png_ptr, info_ptr));
 
474
 
 
475
      data = Util_SafeMalloc(bytes_per_line * image->height);
 
476
 
 
477
      Raster_ConvertPixels(data, bytes_per_line, 24,
 
478
                           image->data, image->bytesPerLine, image->depth,
 
479
                           FALSE, NULL, 0, 0, 0, 0,
 
480
                           image->width, image->height);
 
481
   }
 
482
 
 
483
   /* Write the file header information.  REQUIRED */
 
484
   png_write_info(png_ptr, info_ptr);
 
485
 
 
486
   if ((image->bpp == 32) && options->stripAlphaChannel) {
 
487
      /* treat the alpha channel byte as filler */
 
488
      png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
 
489
   }
 
490
 
 
491
   for (k = 0; k < image->height; k++) {
 
492
      int rowIndex;
 
493
 
 
494
      if (image->flags & IMAGE_FLAG_BOTTOM_UP) {
 
495
         rowIndex = image->height - 1 - k;
 
496
      } else {
 
497
         rowIndex = k;
 
498
      }
 
499
 
 
500
      row_pointers[rowIndex] = data + k * bytes_per_line;
 
501
   }
 
502
 
 
503
   png_write_image(png_ptr, row_pointers);
 
504
 
 
505
   if (data != image->data) {
 
506
      free(data);
 
507
   }
 
508
 
 
509
   /* It is REQUIRED to call this to finish writing the rest of the file */
 
510
   png_write_end(png_ptr, info_ptr);
 
511
 
 
512
   /* if you allocated any text comments, free them here */
 
513
 
 
514
   png_destroy_write_struct(&png_ptr, &info_ptr);
 
515
 
 
516
   free(row_pointers);
 
517
 
 
518
   return TRUE;
 
519
  error:
 
520
   free(row_pointers);
 
521
   DynBuf_Destroy(imageData);
 
522
   return FALSE;
 
523
}
 
524