File: pngLoad.c

package info (click to toggle)
whitedune 0.30.10-2.1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 42,004 kB
  • ctags: 27,321
  • sloc: cpp: 116,017; ansic: 79,688; java: 20,101; sh: 3,248; yacc: 2,902; makefile: 1,718; lex: 848; awk: 363; perl: 270; objc: 143; lisp: 112; python: 22
file content (355 lines) | stat: -rw-r--r-- 9,895 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/*
 * from OpenVRML
 *
 * Copyright (C) 1998  Chris Morley
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 

#include <stdio.h>
#include <stdlib.h>

#include "config.h"

#include "pngLoad.h"

#ifdef HAVE_LIBPNG
#include <png.h>


static double get_gamma_exp( void );
static int pngreadstr( FILE *fp,
                       int *w, int *h, int *nc,
                       png_structp png_ptr,
                       png_infop info_ptr,
                       unsigned char **pixels,
                       unsigned char ***rows );

unsigned char *pngread (FILE *fp, int *w, int *h, int *nc)
{
  png_structp png_ptr;
  png_infop info_ptr;
  unsigned char *pixels = 0, **rows = 0;

  /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  REQUIRED
    */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);

  if (png_ptr == NULL) return NULL;
 
   /* Allocate/initialize the memory for image information.  REQUIRED. */
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL)
    {
      png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
      return 0;
    }

  /* png_ptr and info_ptr are freed in pngreadstr */
  if (! pngreadstr( fp, w, h, nc, png_ptr, info_ptr, &pixels, &rows ))
    {
      /* Free all of the memory associated with the png_ptr and info_ptr */
      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

      if (pixels) free(pixels);
      if (rows) free(rows);
      return 0;
    }

  if (rows) free(rows);
  return pixels;
}

static unsigned char* pngdata;
static int pnglen;

int pngOpen(const char *filename, int *width, int *height, 
                          int *components)
   {
   FILE* f;
   f=fopen(filename,"rb");
   if (f==NULL)
      return 0;
   pngdata=pngread(f,width,height,components);
   pnglen=*width**height**components;
   if (pngdata==NULL)
      return 0;
   else 
      return 1;
   }

void pngRead(unsigned char *data)
   {
   memcpy(data,pngdata,pnglen);
   }

jmp_buf pngenv;

#ifndef HAVE_NO_PNG_HANDLE_UNKNOWN
# ifndef HAVE_OLPC
#  ifndef MACOSX
#   ifndef __alpha
#    ifndef __hppa
void png_handle_unknown PNGARG((png_structp png_ptr, png_infop info_ptr, 
                               png_uint_32 length))
   {
   longjmp(pngenv,1);
   }
#    endif
#   endif
#  endif
# endif
#endif

/* This is broken out into a separate function so the setjmp
 * can't clobber pixels and rows.
 */

static int pngreadstr( FILE *fp,
                       int *w, int *h, int *nc,
                       png_structp png_ptr,
                       png_infop info_ptr,
                       unsigned char **ppixels,
                       unsigned char ***prows )
{
  png_uint_32 width, height;
  int bit_depth, color_type, interlace_type;
  int bytes_per_row, row;
  int gray_palette;
  unsigned char *pixels, **rows;


  /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */
#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4
  if (setjmp(png_jmpbuf((png_ptr))))
#else
  if (setjmp(png_ptr->jmpbuf))
#endif
    {
      /* If we get here, we had a problem reading the file */
      return 0;
    }
  if (setjmp(pngenv)!=0)
    return(0);
 
  /* Set up the input control if you are using standard C streams */
#if !defined(PNG_NO_STDIO)
  png_init_io(png_ptr, fp);
#endif
  /* The call to png_read_info() gives us all of the information from the
   * PNG file before the first IDAT (image data chunk).  REQUIRED
   */
  png_read_info(png_ptr, info_ptr);
 
  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
               &interlace_type, NULL, NULL);
 
  *nc = png_get_channels(png_ptr, info_ptr);
  /*printf("color_type %d, nc = %d ", color_type, *nc);*/

/**** Set up the data transformations you want.  Note that these are all
 **** optional.  Only call them if you want/need them.  Many of the
 **** transformations only work on specific types of images, and many
 **** are mutually exclusive.
 ****/
 
  /* tell libpng to strip 16 bit/color files down to 8 bits/color */
  png_set_strip_16(png_ptr);

  /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
   * byte into separate bytes (useful for paletted and grayscale images).
   */
  png_set_packing(png_ptr);

  /* Expand paletted colors into true RGB triplets */
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
      /* Even gray paletted images will get expanded here */
      png_set_expand(png_ptr);
      *nc = 3;
    }
 
  /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    png_set_expand(png_ptr);
 
  /* Expand paletted or RGB images with transparency to full alpha channels
   * so the data will be available as RGBA quartets.
   */
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
      png_set_expand(png_ptr);
      ++(*nc);
    }

  gray_palette = 0;
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
      int n, num_palette;
      png_colorp palette;
      if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
        {
          gray_palette = 1;
          for (n=0; n<num_palette; ++n)
            if (palette[n].red != palette[n].green ||
                palette[n].blue != palette[n].green)
              {
                gray_palette = 0;
                break;
              }
        }
    }

  /* set gamma */
  {
    double file_gamma, default_exponent = get_gamma_exp();
    if (png_get_gAMA(png_ptr, info_ptr, &file_gamma))
      png_set_gamma(png_ptr, default_exponent, file_gamma);
    else
      png_set_gamma(png_ptr, default_exponent, 0.45455);
  }

  /* Get updated info */
  png_read_update_info(png_ptr, info_ptr);
  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
               &interlace_type, NULL, NULL);
 
  /* Allocate the memory to hold the image using the fields of info_ptr. */
  bytes_per_row = *nc * width;

  *ppixels = (unsigned char*) malloc(bytes_per_row * height);
  *prows = (unsigned char**) malloc(height * sizeof(char *));
  if (*ppixels == 0 || *prows == 0)
    {
      /* Free all of the memory associated with the png_ptr and info_ptr */
      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
      return 0;
    }

  pixels = *ppixels;
  rows = *prows;

  
  /* read in "upside down" because opengl says the
   * texture origin is lower left 
   */
  /*for (row=0; row<(int)height; ++row)*/
  /*rows[row] = &pixels[row * bytes_per_row];*/
  for (row=0; row<(int)height; ++row)
    rows[row] = &pixels[(height-row-1) * bytes_per_row];

  /* Now it's time to read the image.  One of these methods is REQUIRED */
  /* Read the entire image in one go */
  png_read_image(png_ptr, rows);
 
  /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
  png_read_end(png_ptr, info_ptr);
 
  /* clean up after the read, and free any memory allocated - REQUIRED */
  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

  /* Reduce gray palette images down to intensity or intensity/alpha */
  if (gray_palette)
    {
      int n, np = width * height;
      if (*nc == 3)
        {
          for (n=1; n<np; ++n)
            pixels[n] = pixels[3*n];
          *nc = 1;
        }
      else if (*nc == 4)
        {
          for (n=0; n<np; ++n) {
            pixels[2*n] = pixels[4*n];
            pixels[2*n+1] = pixels[4*n+3];
          }
          *nc = 2;
        }
    }

  *w = width;
  *h = height;
  return 1;
}

/* From Greg Roelofs */

static double get_gamma_exp()
{
  static double default_exponent = 2.2;
  static int set = 0;
#if defined(sgi)
  FILE *infile;
#endif

  if (! set)
    {

#if defined(NeXT)
      default_exponent = 1.0;   /* 2.2/next_gamma for 3rd-party utils */

#elif defined(sgi)
      default_exponent = 1.7;   /* default == 2.2 / 1.7 */
      /* 
       * there doesn't seem to be any documented function to get the
       * "gamma" value, so we do it the hard way 
       */
      if (infile = fopen("/etc/config/system.glGammaVal", "rb")) {
        double sgi_gamma;
        char fooline[80];
        fgets(fooline, sizeof(fooline), infile);
        fclose(infile);
        sgi_gamma = atof(fooline);
        if (sgi_gamma > 0.0)
          default_exponent = 2.2 / sgi_gamma;
      }

#elif defined(Macintosh)
      default_exponent = 1.5;   /* default == (1.8/2.61) * 2.2 */
      /*
        if (mac_gamma = some_mac_function_that_returns_gamma())
        default_exponent = (mac_gamma/2.61) * 2.2;
        */

#endif

      set = 1;
    }

  return default_exponent;
}

#else

int 
pngOpen(const char *filename, int *width, int *height,int *nc)
{
    return 0;
}

void pngRead(unsigned char *data)
   {      
   }
   
#endif