IMG_pnm.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. SDL_image: An example image loading library for use with SDL
  3. Copyright (C) 1999, 2000, 2001 Sam Lantinga
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this library; if not, write to the Free
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. Sam Lantinga
  16. slouken@libsdl.org
  17. */
  18. /* $Id: IMG_pnm.c,v 1.1 2004/07/21 16:24:11 paigoddess Exp $ */
  19. /*
  20. * PNM (portable anymap) image loader:
  21. *
  22. * Supports: PBM, PGM and PPM, ASCII and binary formats
  23. * (PBM and PGM are loaded as 8bpp surfaces)
  24. * Does not support: maximum component value > 255
  25. */
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <ctype.h>
  29. #include <string.h>
  30. #include "SDL_image.h"
  31. /* See if an image is contained in a data source */
  32. int IMG_isPNM(SDL_RWops *src)
  33. {
  34. char magic[2];
  35. /*
  36. * PNM magic signatures:
  37. * P1 PBM, ascii format
  38. * P2 PGM, ascii format
  39. * P3 PPM, ascii format
  40. * P4 PBM, binary format
  41. * P5 PGM, binary format
  42. * P6 PPM, binary format
  43. */
  44. return (SDL_RWread(src, magic, 2, 1)
  45. && magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6');
  46. }
  47. /* read a non-negative integer from the source. return -1 upon error */
  48. static int ReadNumber(SDL_RWops *src)
  49. {
  50. int number;
  51. unsigned char ch;
  52. /* Initialize return value */
  53. number = 0;
  54. /* Skip leading whitespace */
  55. do {
  56. if ( ! SDL_RWread(src, &ch, 1, 1) ) {
  57. return(0);
  58. }
  59. /* Eat comments as whitespace */
  60. if ( ch == '#' ) { /* Comment is '#' to end of line */
  61. do {
  62. if ( ! SDL_RWread(src, &ch, 1, 1) ) {
  63. return -1;
  64. }
  65. } while ( (ch != '\r') && (ch != '\n') );
  66. }
  67. } while ( isspace(ch) );
  68. /* Add up the number */
  69. do {
  70. number *= 10;
  71. number += ch-'0';
  72. if ( !SDL_RWread(src, &ch, 1, 1) ) {
  73. return -1;
  74. }
  75. } while ( isdigit(ch) );
  76. return(number);
  77. }
  78. SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
  79. {
  80. SDL_Surface *surface = NULL;
  81. int width, height;
  82. int maxval, y, bpl;
  83. Uint8 *row;
  84. Uint8 *buf = NULL;
  85. char *error = NULL;
  86. Uint8 magic[2];
  87. int ascii;
  88. enum PNM_kind { PBM, PGM, PPM } kind;
  89. #define ERROR(s) do { error = (s); goto done; } while(0)
  90. if(!src)
  91. return NULL;
  92. SDL_RWread(src, magic, 2, 1);
  93. kind = (PNM_kind)(magic[1] - '1');
  94. ascii = 1;
  95. if(kind >= 3) {
  96. ascii = 0;
  97. kind = (PNM_kind)(kind - 3);
  98. }
  99. width = ReadNumber(src);
  100. height = ReadNumber(src);
  101. if(width <= 0 || height <= 0)
  102. ERROR("Unable to read image width and height");
  103. if(kind != PBM) {
  104. maxval = ReadNumber(src);
  105. if(maxval <= 0 || maxval > 255)
  106. ERROR("unsupported PNM format");
  107. } else
  108. maxval = 255; /* never scale PBMs */
  109. /* binary PNM allows just a single character of whitespace after
  110. the last parameter, and we've already consumed it */
  111. if(kind == PPM) {
  112. /* 24-bit surface in R,G,B byte order */
  113. surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
  114. #if SDL_BYTEORDER == SDL_LIL_ENDIAN
  115. 0x000000ff, 0x0000ff00, 0x00ff0000,
  116. #else
  117. 0x00ff0000, 0x0000ff00, 0x000000ff,
  118. #endif
  119. 0);
  120. } else {
  121. /* load PBM/PGM as 8-bit indexed images */
  122. surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
  123. 0, 0, 0, 0);
  124. }
  125. if ( surface == NULL )
  126. ERROR("Out of memory");
  127. bpl = width * surface->format->BytesPerPixel;
  128. if(kind == PGM) {
  129. SDL_Color *c = surface->format->palette->colors;
  130. int i;
  131. for(i = 0; i < 256; i++)
  132. c[i].r = c[i].g = c[i].b = i;
  133. surface->format->palette->ncolors = 256;
  134. } else if(kind == PBM) {
  135. /* for some reason PBM has 1=black, 0=white */
  136. SDL_Color *c = surface->format->palette->colors;
  137. c[0].r = c[0].g = c[0].b = 255;
  138. c[1].r = c[1].g = c[1].b = 0;
  139. surface->format->palette->ncolors = 2;
  140. bpl = (width + 7) >> 3;
  141. buf = (Uint8*)malloc(bpl);
  142. if(buf == NULL)
  143. ERROR("Out of memory");
  144. }
  145. /* Read the image into the surface */
  146. row = (Uint8*)surface->pixels;
  147. for(y = 0; y < height; y++) {
  148. if(ascii) {
  149. int i;
  150. if(kind == PBM) {
  151. for(i = 0; i < width; i++) {
  152. Uint8 ch;
  153. do {
  154. if(!SDL_RWread(src, &ch,
  155. 1, 1))
  156. ERROR("file truncated");
  157. ch -= '0';
  158. } while(ch > 1);
  159. row[i] = ch;
  160. }
  161. } else {
  162. for(i = 0; i < bpl; i++) {
  163. int c;
  164. c = ReadNumber(src);
  165. if(c < 0)
  166. ERROR("file truncated");
  167. row[i] = c;
  168. }
  169. }
  170. } else {
  171. Uint8 *dst = (kind == PBM) ? buf : row;
  172. if(!SDL_RWread(src, dst, bpl, 1))
  173. ERROR("file truncated");
  174. if(kind == PBM) {
  175. /* expand bitmap to 8bpp */
  176. int i;
  177. for(i = 0; i < width; i++) {
  178. int bit = 7 - (i & 7);
  179. row[i] = (buf[i >> 3] >> bit) & 1;
  180. }
  181. }
  182. }
  183. if(maxval < 255) {
  184. /* scale up to full dynamic range (slow) */
  185. int i;
  186. for(i = 0; i < bpl; i++)
  187. row[i] = row[i] * 255 / maxval;
  188. }
  189. row += surface->pitch;
  190. }
  191. done:
  192. free(buf);
  193. if(error) {
  194. SDL_FreeSurface(surface);
  195. IMG_SetError(error);
  196. surface = NULL;
  197. }
  198. return(surface);
  199. }