Fix CVE-2010-1519
[glpng.git] / src / glpng.c
blob688bbbaae321b4a77f00d5b5ec6340f5959b61b4
1 /*
2 * PNG loader library for OpenGL v1.45 (10/07/00)
3 * by Ben Wyatt ben@wyatt100.freeserve.co.uk
4 * Using LibPNG 1.0.2 and ZLib 1.1.3
6 * This software is provided 'as-is', without any express or implied warranty.
7 * In no event will the author be held liable for any damages arising from the
8 * use of this software.
10 * Permission is hereby granted to use, copy, modify, and distribute this
11 * source code, or portions hereof, for any purpose, without fee, subject to
12 * the following restrictions:
14 * 1. The origin of this source code must not be misrepresented. You must not
15 * claim that you wrote the original software. If you use this software in
16 * a product, an acknowledgment in the product documentation would be
17 * appreciated but is not required.
18 * 2. Altered versions must be plainly marked as such and must not be
19 * misrepresented as being the original source.
20 * 3. This notice must not be removed or altered from any source distribution.
23 #ifdef _WIN32 /* Stupid Windows needs to include windows.h before gl.h */
24 #undef FAR
25 #include <windows.h>
26 #endif
28 #define GL_GLEXT_PROTOTYPES
30 #include <GL/glpng.h>
31 #include <GL/gl.h>
32 #include <GL/glext.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <math.h>
36 #include <png.h>
38 /* Used to decide if GL/gl.h supports the paletted extension */
39 #ifdef GL_COLOR_INDEX1_EXT
40 #define SUPPORTS_PALETTE_EXT
41 #endif
43 static unsigned char DefaultAlphaCallback(unsigned char red, unsigned char green, unsigned char blue) {
44 return 255;
47 static unsigned char StencilRed = 0, StencilGreen = 0, StencilBlue = 0;
48 static unsigned char (*AlphaCallback)(unsigned char red, unsigned char green, unsigned char blue) = DefaultAlphaCallback;
49 static int StandardOrientation = 0;
51 #ifdef SUPPORTS_PALETTE_EXT
52 #ifdef _WIN32
53 static PFNGLCOLORTABLEEXTPROC glColorTableEXT = NULL;
54 #endif
55 #endif
57 static int PalettedTextures = -1;
58 static GLint MaxTextureSize = 0;
60 /* screenGamma = displayGamma/viewingGamma
61 * displayGamma = CRT has gamma of ~2.2
62 * viewingGamma depends on platform. PC is 1.0, Mac is 1.45, SGI defaults
63 * to 1.7, but this can be checked and changed w/ /usr/sbin/gamma command.
64 * If the environment variable VIEWING_GAMMA is set, adjust gamma per this value.
66 #ifdef _MAC
67 static double screenGamma = 2.2 / 1.45;
68 #elif SGI
69 static double screenGamma = 2.2 / 1.7;
70 #else /* PC/default */
71 static double screenGamma = 2.2 / 1.0;
72 #endif
74 static char gammaExplicit = 0; /*if */
76 static void checkForGammaEnv()
78 double viewingGamma;
79 char *gammaEnv = getenv("VIEWING_GAMMA");
81 if(gammaEnv && !gammaExplicit)
83 sscanf(gammaEnv, "%lf", &viewingGamma);
84 screenGamma = 2.2/viewingGamma;
88 /* Returns a safe texture size to use (ie a power of 2), based on the current texture size "i" */
89 static int SafeSize(int i) {
90 int p;
92 if (i > MaxTextureSize) return MaxTextureSize;
94 for (p = 0; p < 24; p++)
95 if (i <= (1<<p))
96 return 1<<p;
98 return MaxTextureSize;
101 /* Resize the texture since gluScaleImage doesn't work on everything */
102 static void Resize(int components, const png_bytep d1, int w1, int h1, png_bytep d2, int w2, int h2) {
103 const float sx = (float) w1/w2, sy = (float) h1/h2;
104 int x, y, xx, yy, c;
105 png_bytep d;
107 for (y = 0; y < h2; y++) {
108 yy = (int) (y*sy)*w1;
110 for (x = 0; x < w2; x++) {
111 xx = (int) (x*sx);
112 d = d1 + (yy+xx)*components;
114 for (c = 0; c < components; c++)
115 *d2++ = *d++;
120 #ifdef _WIN32
121 static int ExtSupported(const char *x) {
122 static const GLubyte *ext = NULL;
123 const char *c;
124 int xlen = strlen(x);
126 if (ext == NULL) ext = glGetString(GL_EXTENSIONS);
128 c = (const char*)ext;
130 while (*c != '\0') {
131 if (strcmp(c, x) == 0 && (c[xlen] == '\0' || c[xlen] == ' ')) return 1;
132 c++;
135 return 0;
137 #endif
139 #define GET(o) ((int)*(data + (o)))
141 static int HalfSize(GLint components, GLint width, GLint height, const unsigned char *data, unsigned char *d, int filter) {
142 int x, y, c;
143 int line = width*components;
145 if (width > 1 && height > 1) {
146 if (filter)
147 for (y = 0; y < height; y += 2) {
148 for (x = 0; x < width; x += 2) {
149 for (c = 0; c < components; c++) {
150 *d++ = (GET(0)+GET(components)+GET(line)+GET(line+components)) / 4;
151 data++;
153 data += components;
155 data += line;
157 else
158 for (y = 0; y < height; y += 2) {
159 for (x = 0; x < width; x += 2) {
160 for (c = 0; c < components; c++) {
161 *d++ = GET(0);
162 data++;
164 data += components;
166 data += line;
169 else if (width > 1 && height == 1) {
170 if (filter)
171 for (y = 0; y < height; y += 1) {
172 for (x = 0; x < width; x += 2) {
173 for (c = 0; c < components; c++) {
174 *d++ = (GET(0)+GET(components)) / 2;
175 data++;
177 data += components;
180 else
181 for (y = 0; y < height; y += 1) {
182 for (x = 0; x < width; x += 2) {
183 for (c = 0; c < components; c++) {
184 *d++ = GET(0);
185 data++;
187 data += components;
191 else if (width == 1 && height > 1) {
192 if (filter)
193 for (y = 0; y < height; y += 2) {
194 for (x = 0; x < width; x += 1) {
195 for (c = 0; c < components; c++) {
196 *d++ = (GET(0)+GET(line)) / 2;
197 data++;
200 data += line;
202 else
203 for (y = 0; y < height; y += 2) {
204 for (x = 0; x < width; x += 1) {
205 for (c = 0; c < components; c++) {
206 *d++ = GET(0);
207 data++;
210 data += line;
213 else {
214 return 0;
217 return 1;
220 #undef GET
222 /* Replacement for gluBuild2DMipmaps so GLU isn't needed */
223 static void Build2DMipmaps(GLint components, GLint width, GLint height, GLenum format, const unsigned char *data, int filter) {
224 int level = 0;
225 unsigned char *d = (unsigned char *) malloc((width/2)*(height/2)*components+4);
226 const unsigned char *last = data;
228 glTexImage2D(GL_TEXTURE_2D, level, components, width, height, 0, format, GL_UNSIGNED_BYTE, data);
229 level++;
231 while (HalfSize(components, width, height, last, d, filter)) {
232 if (width > 1) width /= 2;
233 if (height > 1) height /= 2;
235 glTexImage2D(GL_TEXTURE_2D, level, components, width, height, 0, format, GL_UNSIGNED_BYTE, d);
236 level++;
237 last = d;
240 free(d);
243 int APIENTRY pngLoadRaw(const char *filename, pngRawInfo *pinfo) {
244 int result;
245 FILE *fp = fopen(filename, "rb");
246 if (fp == NULL) return 0;
248 result = pngLoadRawF(fp, pinfo);
250 if (fclose(fp) != 0) {
251 if (result) {
252 free(pinfo->Data);
253 free(pinfo->Palette);
255 return 0;
258 return result;
261 int APIENTRY pngLoadRawF(FILE *fp, pngRawInfo *pinfo) {
262 unsigned char header[8];
263 png_structp png;
264 png_infop info;
265 png_infop endinfo;
266 png_bytep data = NULL;
267 png_bytep *row_p = NULL;
268 double fileGamma;
270 png_uint_32 width, height;
271 int depth, color;
273 png_uint_32 i;
275 if (pinfo == NULL) return 0;
277 fread(header, 1, 8, fp);
278 if (!png_check_sig(header, 8)) return 0;
280 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
281 if (!png) return 0;
282 info = png_create_info_struct(png);
283 if (!info) return 0;
284 endinfo = png_create_info_struct(png);
285 if (!endinfo) return 0;
287 // DH: added following lines
288 if (setjmp(png_jmpbuf(png)))
290 error:
291 png_destroy_read_struct(&png, &info, &endinfo);
292 free(data);
293 free(row_p);
294 return 0;
296 // ~DH
298 png_init_io(png, fp);
299 png_set_sig_bytes(png, 8);
300 png_read_info(png, info);
301 png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
303 pinfo->Width = width;
304 pinfo->Height = height;
305 pinfo->Depth = depth;
307 /*--GAMMA--*/
308 checkForGammaEnv();
309 if (png_get_gAMA(png, info, &fileGamma))
310 png_set_gamma(png, screenGamma, fileGamma);
311 else
312 png_set_gamma(png, screenGamma, 1.0/2.2);
314 png_read_update_info(png, info);
316 /* HDG: We allocate all the png data in one linear array, thus
317 height * png_get_rowbytes() may not be > PNG_UINT_32_MAX !
318 This check fixes CVE-2010-1519. */
319 if ((uint64_t)height * png_get_rowbytes(png, info) > PNG_UINT_32_MAX)
320 goto error;
322 data = (png_bytep) malloc(png_get_rowbytes(png, info)*height);
323 row_p = (png_bytep *) malloc(sizeof(png_bytep)*height);
324 if (!data || !row_p)
325 goto error;
327 for (i = 0; i < height; i++) {
328 if (StandardOrientation)
329 row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i];
330 else
331 row_p[i] = &data[png_get_rowbytes(png, info)*i];
334 png_read_image(png, row_p);
335 free(row_p);
336 row_p = NULL;
338 if (color == PNG_COLOR_TYPE_PALETTE) {
339 int cols;
340 png_get_PLTE(png, info, (png_colorp *) &pinfo->Palette, &cols);
342 else {
343 pinfo->Palette = NULL;
346 if (color&PNG_COLOR_MASK_ALPHA) {
347 if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY_ALPHA)
348 pinfo->Components = 2;
349 else
350 pinfo->Components = 4;
351 pinfo->Alpha = 8;
353 else {
354 if (color&PNG_COLOR_MASK_PALETTE || color == PNG_COLOR_TYPE_GRAY)
355 pinfo->Components = 1;
356 else
357 pinfo->Components = 3;
358 pinfo->Alpha = 0;
361 pinfo->Data = data;
363 png_read_end(png, endinfo);
364 png_destroy_read_struct(&png, &info, &endinfo);
366 return 1;
369 int APIENTRY pngLoad(const char *filename, int mipmap, int trans, pngInfo *pinfo) {
370 int result;
371 FILE *fp = fopen(filename, "rb");
372 if (fp == NULL) return 0;
374 result = pngLoadF(fp, mipmap, trans, pinfo);
376 if (fclose(fp) != 0) return 0;
378 return result;
381 int APIENTRY pngLoadF(FILE *fp, int mipmap, int trans, pngInfo *pinfo) {
382 GLint pack, unpack;
383 unsigned char header[8];
384 png_structp png;
385 png_infop info;
386 png_infop endinfo;
387 png_bytep data = NULL;
388 png_bytep data2 = NULL;
389 png_bytep *row_p = NULL;
390 double fileGamma;
392 png_uint_32 width, height, rw, rh;
393 int depth, color;
395 png_uint_32 i;
397 fread(header, 1, 8, fp);
398 if (!png_check_sig(header, 8)) return 0;
400 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
401 if (!png) return 0;
402 info = png_create_info_struct(png);
403 if (!info) return 0;
404 endinfo = png_create_info_struct(png);
405 if (!endinfo) return 0;
407 // DH: added following lines
408 if (setjmp(png_jmpbuf(png)))
410 error:
411 png_destroy_read_struct(&png, &info, &endinfo);
412 free(data);
413 free(data2);
414 free(row_p);
415 return 0;
417 // ~DH
419 png_init_io(png, fp);
420 png_set_sig_bytes(png, 8);
421 png_read_info(png, info);
422 png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
424 if (pinfo != NULL) {
425 pinfo->Width = width;
426 pinfo->Height = height;
427 pinfo->Depth = depth;
430 if (MaxTextureSize == 0)
431 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTextureSize);
433 #ifdef SUPPORTS_PALETTE_EXT
434 #ifdef _WIN32
435 if (PalettedTextures == -1)
436 PalettedTextures = ExtSupported("GL_EXT_paletted_texture") && (strstr((const char *) glGetString(GL_VERSION), "1.1.0 3Dfx Beta") == NULL);
438 if (PalettedTextures) {
439 if (glColorTableEXT == NULL) {
440 glColorTableEXT = (PFNGLCOLORTABLEEXTPROC) wglGetProcAddress("glColorTableEXT");
441 if (glColorTableEXT == NULL)
442 PalettedTextures = 0;
445 #endif
446 #endif
448 if (PalettedTextures == -1)
449 PalettedTextures = 0;
451 if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA)
452 png_set_gray_to_rgb(png);
454 if (color&PNG_COLOR_MASK_ALPHA && trans != PNG_ALPHA) {
455 png_set_strip_alpha(png);
456 color &= ~PNG_COLOR_MASK_ALPHA;
459 if (!(PalettedTextures && mipmap >= 0 && trans == PNG_SOLID))
460 if (color == PNG_COLOR_TYPE_PALETTE)
461 png_set_expand(png);
463 /*--GAMMA--*/
464 checkForGammaEnv();
465 if (png_get_gAMA(png, info, &fileGamma))
466 png_set_gamma(png, screenGamma, fileGamma);
467 else
468 png_set_gamma(png, screenGamma, 1.0/2.2);
470 png_read_update_info(png, info);
472 /* HDG: We allocate all the png data in one linear array, thus
473 height * png_get_rowbytes() may not be > PNG_UINT_32_MAX !
474 This check fixes CVE-2010-1519. */
475 if ((uint64_t)height * png_get_rowbytes(png, info) > PNG_UINT_32_MAX)
476 goto error;
478 data = (png_bytep) malloc(png_get_rowbytes(png, info)*height);
479 row_p = (png_bytep *) malloc(sizeof(png_bytep)*height);
480 if (!data || !row_p)
481 goto error;
483 for (i = 0; i < height; i++) {
484 if (StandardOrientation)
485 row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i];
486 else
487 row_p[i] = &data[png_get_rowbytes(png, info)*i];
490 png_read_image(png, row_p);
491 free(row_p);
492 row_p = NULL;
494 rw = SafeSize(width), rh = SafeSize(height);
496 if (rw != width || rh != height) {
497 const int channels = png_get_rowbytes(png, info)/width;
499 data2 = (png_bytep) malloc(rw*rh*channels);
500 if (!data2)
501 goto error;
503 /* Doesn't work on certain sizes */
504 /* if (gluScaleImage(glformat, width, height, GL_UNSIGNED_BYTE, data, rw, rh, GL_UNSIGNED_BYTE, data2) != 0)
505 return 0;
507 Resize(channels, data, width, height, data2, rw, rh);
509 width = rw, height = rh;
510 free(data);
511 data = data2;
512 data2 = NULL;
515 { /* OpenGL stuff */
516 glGetIntegerv(GL_PACK_ALIGNMENT, &pack);
517 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack);
518 glPixelStorei(GL_PACK_ALIGNMENT, 1);
519 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
521 #ifdef SUPPORTS_PALETTE_EXT
522 if (PalettedTextures && mipmap >= 0 && trans == PNG_SOLID && color == PNG_COLOR_TYPE_PALETTE) {
523 png_colorp pal;
524 int cols;
525 GLint intf;
527 if (pinfo != NULL) pinfo->Alpha = 0;
528 png_get_PLTE(png, info, &pal, &cols);
530 switch (cols) {
531 case 1<<1: intf = GL_COLOR_INDEX1_EXT; break;
532 case 1<<2: intf = GL_COLOR_INDEX2_EXT; break;
533 case 1<<4: intf = GL_COLOR_INDEX4_EXT; break;
534 case 1<<8: intf = GL_COLOR_INDEX8_EXT; break;
535 case 1<<12: intf = GL_COLOR_INDEX12_EXT; break;
536 case 1<<16: intf = GL_COLOR_INDEX16_EXT; break;
537 default:
538 /*printf("Warning: Colour depth %i not recognised\n", cols);*/
539 return 0;
541 glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, cols, GL_RGB, GL_UNSIGNED_BYTE, pal);
542 glTexImage2D(GL_TEXTURE_2D, mipmap, intf, width, height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, data);
544 else
545 #endif
546 if (trans == PNG_SOLID || trans == PNG_ALPHA || color == PNG_COLOR_TYPE_RGB_ALPHA || color == PNG_COLOR_TYPE_GRAY_ALPHA) {
547 GLenum glformat;
548 GLint glcomponent;
550 switch (color) {
551 case PNG_COLOR_TYPE_GRAY:
552 case PNG_COLOR_TYPE_RGB:
553 case PNG_COLOR_TYPE_PALETTE:
554 glformat = GL_RGB;
555 glcomponent = 3;
556 if (pinfo != NULL) pinfo->Alpha = 0;
557 break;
559 case PNG_COLOR_TYPE_GRAY_ALPHA:
560 case PNG_COLOR_TYPE_RGB_ALPHA:
561 glformat = GL_RGBA;
562 glcomponent = 4;
563 if (pinfo != NULL) pinfo->Alpha = 8;
564 break;
566 default:
567 /*puts("glformat not set");*/
568 return 0;
571 if (mipmap == PNG_BUILDMIPMAPS)
572 Build2DMipmaps(glcomponent, width, height, glformat, data, 1);
573 else if (mipmap == PNG_SIMPLEMIPMAPS)
574 Build2DMipmaps(glcomponent, width, height, glformat, data, 0);
575 else
576 glTexImage2D(GL_TEXTURE_2D, mipmap, glcomponent, width, height, 0, glformat, GL_UNSIGNED_BYTE, data);
578 else {
579 png_bytep p, endp, q;
580 int r, g, b, a;
582 /* HDG another potential 32 bit address overflow, the
583 original png had 3 channels and we are going to
584 4 channels now! */
585 if ((uint64_t)width * height > (PNG_UINT_32_MAX >> 2))
586 goto error;
588 p = data, endp = p+width*height*3;
589 q = data2 = (png_bytep) malloc(sizeof(png_byte)*width*height*4);
591 if (pinfo != NULL) pinfo->Alpha = 8;
593 #define FORSTART \
594 do { \
595 r = *p++; /*red */ \
596 g = *p++; /*green*/ \
597 b = *p++; /*blue */ \
598 *q++ = r; \
599 *q++ = g; \
600 *q++ = b;
602 #define FOREND \
603 q++; \
604 } while (p != endp);
606 #define ALPHA *q
608 switch (trans) {
609 case PNG_CALLBACKT:
610 FORSTART
611 ALPHA = AlphaCallback((unsigned char) r, (unsigned char) g, (unsigned char) b);
612 FOREND
613 break;
615 case PNG_STENCIL:
616 FORSTART
617 if (r == StencilRed && g == StencilGreen && b == StencilBlue)
618 ALPHA = 0;
619 else
620 ALPHA = 255;
621 FOREND
622 break;
624 case PNG_BLEND1:
625 FORSTART
626 a = r+g+b;
627 if (a > 255) ALPHA = 255; else ALPHA = a;
628 FOREND
629 break;
631 case PNG_BLEND2:
632 FORSTART
633 a = r+g+b;
634 if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
635 FOREND
636 break;
638 case PNG_BLEND3:
639 FORSTART
640 ALPHA = (r+g+b)/3;
641 FOREND
642 break;
644 case PNG_BLEND4:
645 FORSTART
646 a = r*r+g*g+b*b;
647 if (a > 255) ALPHA = 255; else ALPHA = a;
648 FOREND
649 break;
651 case PNG_BLEND5:
652 FORSTART
653 a = r*r+g*g+b*b;
654 if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
655 FOREND
656 break;
658 case PNG_BLEND6:
659 FORSTART
660 a = r*r+g*g+b*b;
661 if (a > 255*3) ALPHA = 255; else ALPHA = a/3;
662 FOREND
663 break;
665 case PNG_BLEND7:
666 FORSTART
667 a = r*r+g*g+b*b;
668 if (a > 255*255) ALPHA = 255; else ALPHA = (int) sqrt(a);
669 FOREND
670 break;
673 #undef FORSTART
674 #undef FOREND
675 #undef ALPHA
677 if (mipmap == PNG_BUILDMIPMAPS)
678 Build2DMipmaps(4, width, height, GL_RGBA, data2, 1);
679 else if (mipmap == PNG_SIMPLEMIPMAPS)
680 Build2DMipmaps(4, width, height, GL_RGBA, data2, 0);
681 else
682 glTexImage2D(GL_TEXTURE_2D, mipmap, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
684 free(data2);
687 glPixelStorei(GL_PACK_ALIGNMENT, pack);
688 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
689 } /* OpenGL end */
691 png_read_end(png, endinfo);
692 png_destroy_read_struct(&png, &info, &endinfo);
694 free(data);
696 return 1;
699 static unsigned int SetParams(int wrapst, int magfilter, int minfilter) {
700 unsigned int id;
702 glGenTextures(1, &id);
703 glBindTexture(GL_TEXTURE_2D, id);
705 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapst);
706 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapst);
708 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter);
709 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
711 return id;
714 unsigned int APIENTRY pngBind(const char *filename, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter) {
715 unsigned int id = SetParams(wrapst, magfilter, minfilter);
717 if (id != 0 && pngLoad(filename, mipmap, trans, info))
718 return id;
719 return 0;
722 unsigned int APIENTRY pngBindF(FILE *file, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter) {
723 unsigned int id = SetParams(wrapst, magfilter, minfilter);
725 if (id != 0 && pngLoadF(file, mipmap, trans, info))
726 return id;
727 return 0;
730 void APIENTRY pngSetStencil(unsigned char red, unsigned char green, unsigned char blue) {
731 StencilRed = red, StencilGreen = green, StencilBlue = blue;
734 void APIENTRY pngSetAlphaCallback(unsigned char (*callback)(unsigned char red, unsigned char green, unsigned char blue)) {
735 if (callback == NULL)
736 AlphaCallback = DefaultAlphaCallback;
737 else
738 AlphaCallback = callback;
741 void APIENTRY pngSetViewingGamma(double viewingGamma) {
742 if(viewingGamma > 0) {
743 gammaExplicit = 1;
744 screenGamma = 2.2/viewingGamma;
746 else {
747 gammaExplicit = 0;
748 screenGamma = 2.2;
752 void APIENTRY pngSetStandardOrientation(int standardorientation) {
753 StandardOrientation = standardorientation;