PPM.C 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /****************************************************************************
  2. * ppm.c
  3. *
  4. * This module contains the code to read and write the PPM file format.
  5. *
  6. * from Persistence of Vision(tm) Ray Tracer
  7. * Copyright 1996,1999 Persistence of Vision Team
  8. *---------------------------------------------------------------------------
  9. * NOTICE: This source code file is provided so that users may experiment
  10. * with enhancements to POV-Ray and to port the software to platforms other
  11. * than those supported by the POV-Ray Team. There are strict rules under
  12. * which you are permitted to use this file. The rules are in the file
  13. * named POVLEGAL.DOC which should be distributed with this file.
  14. * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  15. * Team Coordinator by email to team-coord@povray.org or visit us on the web at
  16. * http://www.povray.org. The latest version of POV-Ray may be found at this site.
  17. *
  18. * This program is based on the popular DKB raytracer version 2.12.
  19. * DKBTrace was originally written by David K. Buck.
  20. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  21. *
  22. * Original patch copyright 1994 Tim Rowley
  23. * Updated for POV 3.0 by Chris Cason, Jan '95.
  24. *
  25. * Modifications by Hans-Detlev Fink, January 1999, used with permission.
  26. *
  27. *****************************************************************************/
  28. /****************************************************************************
  29. * The format is as follows:
  30. *
  31. * (header:)
  32. * P3 - ASCII data OR
  33. * P6 - raw binary data
  34. * # hello - optional comment(s)
  35. * wwww hhhh - Width, Height (ASCII text)
  36. * # world - optional comment(s)
  37. * nnn - maximum color (nnn = bright, 0 = black)
  38. *
  39. * (each pixel: one of the following)
  40. * rr gg bb - Red, green, blue of intensity 0-nnn (binary byte)
  41. * RRR GGG BBB - Red, green, blue of intensity 0-nnn (ASCII number)
  42. *
  43. *****************************************************************************/
  44. #include "frame.h"
  45. #include "povproto.h"
  46. #include "povray.h"
  47. #include "optout.h"
  48. #include "pgm.h"
  49. #include "ppm.h"
  50. /*****************************************************************************
  51. * Local preprocessor defines
  52. ******************************************************************************/
  53. /*****************************************************************************
  54. * Local typedefs
  55. ******************************************************************************/
  56. /*****************************************************************************
  57. * Local variables
  58. ******************************************************************************/
  59. static int PPM_Line_Number;
  60. /*****************************************************************************
  61. * Static functions
  62. ******************************************************************************/
  63. static int Open_PPM_File (FILE_HANDLE *handle, char *name, int *width, int *height, int buffer_size, int mode);
  64. static void Write_PPM_Line (FILE_HANDLE *handle, COLOUR *line_data, int line_number);
  65. static int Read_PPM_Line (FILE_HANDLE *handle, COLOUR *line_data, int *line_number);
  66. static void Close_PPM_File (FILE_HANDLE *handle);
  67. /*****************************************************************************
  68. *
  69. * FUNCTION
  70. *
  71. * INPUT
  72. *
  73. * OUTPUT
  74. *
  75. * RETURNS
  76. *
  77. * AUTHOR
  78. *
  79. * DESCRIPTION
  80. *
  81. * CHANGES
  82. *
  83. ******************************************************************************/
  84. FILE_HANDLE *Get_PPM_File_Handle()
  85. {
  86. FILE_HANDLE *handle;
  87. handle = (FILE_HANDLE *) POV_MALLOC(sizeof(FILE_HANDLE), "PPM file handle") ;
  88. handle->Open_File_p = Open_PPM_File;
  89. handle->Write_Line_p = Write_PPM_Line;
  90. handle->Read_Line_p = Read_PPM_Line;
  91. handle->Read_Image_p = Read_PPM_Image;
  92. handle->Close_File_p = Close_PPM_File;
  93. handle->file = NULL;
  94. handle->buffer = NULL;
  95. handle->buffer_size = 0;
  96. return (handle);
  97. }
  98. /*****************************************************************************
  99. *
  100. * FUNCTION
  101. *
  102. * INPUT
  103. *
  104. * OUTPUT
  105. *
  106. * RETURNS
  107. *
  108. * AUTHOR
  109. *
  110. * DESCRIPTION
  111. *
  112. * CHANGES
  113. *
  114. ******************************************************************************/
  115. static int Open_PPM_File(FILE_HANDLE *handle, char *name, int *width, int *height, int buffer_size, int mode)
  116. {
  117. char type;
  118. int input;
  119. char junk[512];
  120. handle->mode = mode;
  121. handle->filename = name;
  122. PPM_Line_Number = 0;
  123. switch (mode)
  124. {
  125. case READ_MODE:
  126. /* We can't resume from stdout. */
  127. if (opts.Options & TO_STDOUT ||
  128. (handle->file = fopen(name, READ_BINFILE_STRING)) == NULL)
  129. {
  130. Status_Info("\n");
  131. return(0);
  132. }
  133. if (buffer_size != 0)
  134. {
  135. handle->buffer = (char *)POV_MALLOC((size_t)buffer_size, "PPM file buffer") ;
  136. setvbuf(handle->file, handle->buffer, _IOFBF, buffer_size);
  137. }
  138. if (fscanf(handle->file, "P%c\n", &type) != 1 || type != '6')
  139. {
  140. return(0);
  141. }
  142. /* Ignore any comments (if they are written) */
  143. while ((input = fgetc(handle->file)) == '#')
  144. {
  145. fgets(junk, 512, handle->file);
  146. }
  147. ungetc(input, handle->file);
  148. if (fscanf(handle->file, "%d %d\n255\n", width, height) != 2)
  149. {
  150. return(0);
  151. }
  152. Status_Info("\nResuming interrupted trace from %s",handle->filename);
  153. handle->width = *width;
  154. handle->height = *height;
  155. handle->buffer_size = buffer_size;
  156. break;
  157. case WRITE_MODE:
  158. if (opts.Options & TO_STDOUT)
  159. {
  160. buffer_size = 0;
  161. handle->file = stdout;
  162. }
  163. else
  164. {
  165. if ((handle->file = fopen(name, WRITE_BINFILE_STRING)) == NULL)
  166. {
  167. return(0);
  168. }
  169. }
  170. if (buffer_size != 0)
  171. {
  172. handle->buffer = (char *)POV_MALLOC((size_t)buffer_size, "PPM file buffer") ;
  173. setvbuf(handle->file, handle->buffer, _IOFBF, buffer_size);
  174. }
  175. fprintf(handle->file, "P6\n");
  176. #ifdef POV_COMMENTS
  177. #ifdef TRACER
  178. fprintf(handle->file, "# Author: %s\n", TRACER);
  179. #endif
  180. fprintf(handle->file, "# Source: Persistence of Vision(tm) Ray Tracer v%s%s\n",
  181. POV_RAY_VERSION, COMPILER_VER);
  182. if (!(opts.Options & TO_STDOUT))
  183. {
  184. fprintf(handle->file, "# Input File: %s\n", opts.Input_File_Name);
  185. }
  186. if (opts.FrameSeq.Clock_Value != 0)
  187. {
  188. fprintf(handle->file, "# POV Clock: %g\n", opts.FrameSeq.Clock_Value);
  189. }
  190. if (opts.Quality != 9)
  191. {
  192. fprintf(handle->file, "# Rendering Quality: %d\n", opts.Quality);
  193. }
  194. #endif /* POV_COMMENTS */
  195. fprintf(handle->file, "%d %d\n255\n", *width, *height);
  196. handle->width = *width;
  197. handle->height = *height;
  198. handle->buffer_size = buffer_size;
  199. break;
  200. case APPEND_MODE:
  201. if (opts.Options & TO_STDOUT)
  202. {
  203. buffer_size = 0;
  204. handle->file = stdout;
  205. }
  206. else
  207. {
  208. if ((handle->file = fopen(name, APPEND_BINFILE_STRING)) == NULL)
  209. {
  210. return(0);
  211. }
  212. }
  213. if (buffer_size != 0)
  214. {
  215. handle->buffer = (char *)POV_MALLOC((size_t)buffer_size, "PPM file buffer") ;
  216. setvbuf(handle->file, handle->buffer, _IOFBF, buffer_size);
  217. }
  218. handle->buffer_size = buffer_size;
  219. break;
  220. }
  221. return(1);
  222. }
  223. /*****************************************************************************
  224. *
  225. * FUNCTION
  226. *
  227. * INPUT
  228. *
  229. * OUTPUT
  230. *
  231. * RETURNS
  232. *
  233. * AUTHOR
  234. *
  235. * DESCRIPTION
  236. *
  237. * CHANGES
  238. *
  239. ******************************************************************************/
  240. static void Write_PPM_Line(FILE_HANDLE *handle, COLOUR *line_data, int line_number)
  241. {
  242. unsigned int gray;
  243. register int x;
  244. for (x = 0 ; x < handle->width ; x++)
  245. {
  246. if (opts.Options & HF_GRAY_16) /* 16 bit grayscale output */
  247. {
  248. gray = ((0.30 * line_data[x][RED]) +
  249. (0.59 * line_data[x][GREEN]) +
  250. (0.11 * line_data[x][BLUE])) * 65535;
  251. if ((putc((gray >> 8) & 0xFF, handle->file) == EOF) ||
  252. (putc(gray & 0xFF, handle->file) == EOF) ||
  253. (putc(0, handle->file) == EOF))
  254. {
  255. Error("Error writing PPM output data to %s.\n",handle->filename);
  256. }
  257. }
  258. else /* Normal 24 bit pixel coloring */
  259. {
  260. if ((putc((int)floor(line_data[x][RED] * 255.0), handle->file) == EOF) ||
  261. (putc((int)floor(line_data[x][GREEN]*255.0), handle->file) == EOF) ||
  262. (putc((int)floor(line_data[x][BLUE]*255.0), handle->file) == EOF))
  263. {
  264. Error("Error writing PPM output data to %s.\n",handle->filename);
  265. }
  266. }
  267. }
  268. PPM_Line_Number++;
  269. if (handle->buffer_size == 0)
  270. {
  271. /* close and reopen file for integrity in case we crash */
  272. fflush(handle->file);
  273. if (!(opts.Options & TO_STDOUT))
  274. {
  275. handle->file = freopen(handle->filename,APPEND_BINFILE_STRING,handle->file);
  276. }
  277. }
  278. }
  279. /*****************************************************************************
  280. *
  281. * FUNCTION
  282. *
  283. * INPUT
  284. *
  285. * OUTPUT
  286. *
  287. * RETURNS
  288. *
  289. * AUTHOR
  290. *
  291. * DESCRIPTION
  292. *
  293. * CHANGES
  294. *
  295. ******************************************************************************/
  296. static int Read_PPM_Line(FILE_HANDLE *handle, COLOUR *line_data, int *line_number)
  297. {
  298. int data, i;
  299. if ((data = getc(handle->file)) == EOF)
  300. {
  301. return (0);
  302. }
  303. ungetc(data, handle->file);
  304. *line_number = PPM_Line_Number++;
  305. for (i = 0 ; i < handle->width ; i++)
  306. {
  307. if ((data = getc(handle->file)) == EOF)
  308. {
  309. return(-1);
  310. }
  311. line_data[i][RED] = (DBL) data / 255.0;
  312. if ((data = getc(handle->file)) == EOF)
  313. {
  314. return(-1);
  315. }
  316. line_data[i][GREEN] = (DBL) data / 255.0;
  317. if ((data = getc(handle->file)) == EOF)
  318. {
  319. return(-1);
  320. }
  321. line_data[i][BLUE] = (DBL) data / 255.0;
  322. }
  323. return (1);
  324. }
  325. /*****************************************************************************
  326. *
  327. * FUNCTION
  328. *
  329. * INPUT
  330. *
  331. * OUTPUT
  332. *
  333. * RETURNS
  334. *
  335. * AUTHOR
  336. *
  337. * DESCRIPTION
  338. *
  339. * CHANGES
  340. *
  341. ******************************************************************************/
  342. static void Close_PPM_File(FILE_HANDLE *handle)
  343. {
  344. if (handle->file)
  345. {
  346. fflush(handle->file);
  347. /* Close and reopen file (if not stdout) for integrity in case we crash */
  348. if (!(opts.Options & TO_STDOUT))
  349. fclose(handle->file);
  350. }
  351. if (handle->buffer != NULL)
  352. {
  353. POV_FREE(handle->buffer);
  354. }
  355. handle->file = NULL;
  356. handle->buffer = NULL;
  357. }
  358. /*****************************************************************************
  359. *
  360. * FUNCTION
  361. *
  362. * INPUT
  363. *
  364. * OUTPUT
  365. *
  366. * RETURNS
  367. *
  368. * AUTHOR
  369. *
  370. * DESCRIPTION
  371. *
  372. * CHANGES
  373. *
  374. ******************************************************************************/
  375. void Read_PPM_Image(IMAGE *Image, char *name)
  376. {
  377. char type;
  378. int width, height;
  379. int depth;
  380. char input;
  381. char junk[512];
  382. int x, y;
  383. int data;
  384. IMAGE_LINE *line_data;
  385. FILE *infile;
  386. if ((infile = Locate_File(name, READ_BINFILE_STRING, ".ppm", ".PPM",NULL,TRUE)) == NULL)
  387. {
  388. Error("Error opening PPM image %s.\n", name);
  389. return; /* -hdf99- */
  390. }
  391. if (fscanf(infile, "P%c\n", &type) != 1 || (type != '3' && type != '6'))
  392. {
  393. Error ("File is not in PPM format.\n", name);
  394. return; /* -hdf99- */
  395. }
  396. /* Ignore any comments */
  397. while ((input = fgetc(infile)) == '#')
  398. {
  399. fgets(junk, 512, infile);
  400. }
  401. ungetc(input, infile);
  402. if (fscanf(infile, "%d %d\n", &width, &height) != 2)
  403. {
  404. Error ("Error reading width or height from PPM image.\n", name);
  405. }
  406. /* Ignore any comments */
  407. while ((input = fgetc(infile)) == '#')
  408. {
  409. fgets(junk, 512, infile);
  410. }
  411. ungetc(input, infile);
  412. if (fscanf(infile, "%d\n", &depth) != 1 || depth > 255 || depth < 1)
  413. {
  414. Error ("Unsupported number of colors (%d) in PPM image.\n", depth);
  415. }
  416. Image->width = (DBL)(Image->iwidth = width);
  417. Image->height = (DBL)(Image->iheight = height);
  418. Image->Colour_Map_Size = 0;
  419. Image->Colour_Map = NULL;
  420. Image->data.rgb_lines = (IMAGE_LINE *) POV_MALLOC(Image->iheight * sizeof (IMAGE_LINE), "PPM image");
  421. for (y = 0; y < height; y++)
  422. {
  423. line_data = &Image->data.rgb_lines[y];
  424. line_data->red = (unsigned char *)POV_MALLOC(width,"PPM image line");
  425. line_data->green = (unsigned char *)POV_MALLOC(width,"PPM image line");
  426. line_data->blue = (unsigned char *)POV_MALLOC(width,"PPM image line");
  427. line_data->transm = (unsigned char *)NULL;
  428. if (type == '3') /* ASCII data to be input */
  429. {
  430. for (x = 0; x < width; x++)
  431. {
  432. if (fscanf(infile,"%d",&data) != 1)
  433. {
  434. Error("Error reading data from PPM image.\n");
  435. }
  436. line_data->red[x] = data*255/depth;
  437. if (fscanf(infile,"%d",&data) != 1)
  438. {
  439. Error("Error reading data from PPM image.\n");
  440. }
  441. line_data->green[x] = data*255/depth;
  442. if (fscanf(infile,"%d",&data) != 1)
  443. {
  444. Error("Error reading data from PPM image.\n");
  445. }
  446. line_data->blue[x] = data*255/depth;
  447. }
  448. }
  449. else /* (type == '6') Raw binary data to be input */
  450. {
  451. for (x = 0; x < width; x++)
  452. {
  453. if ((data = getc(infile)) == EOF)
  454. {
  455. Error("Error reading data from PPM image.\n");
  456. }
  457. line_data->red[x] = data*255/depth;
  458. if ((data = getc(infile)) == EOF)
  459. {
  460. Error("Error reading data from PPM image.\n");
  461. }
  462. line_data->green[x] = data*255/depth;
  463. if ((data = getc(infile)) == EOF)
  464. {
  465. Error("Error reading data from PPM image.\n");
  466. }
  467. line_data->blue[x] = data*255/depth;
  468. }
  469. }
  470. }
  471. fclose(infile);
  472. }