1 /****************************************************************************
4 * This module contains the code to read and write the PPM file format.
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.
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.
22 * Original patch copyright 1994 Tim Rowley
23 * Updated for POV 3.0 by Chris Cason, Jan '95.
25 * Modifications by Hans-Detlev Fink, January 1999, used with permission.
27 *****************************************************************************/
29 /****************************************************************************
30 * The format is as follows:
34 * P6 - raw binary data
35 * # hello - optional comment(s)
36 * wwww hhhh - Width, Height (ASCII text)
37 * # world - optional comment(s)
38 * nnn - maximum color (nnn = bright, 0 = black)
40 * (each pixel: one of the following)
41 * rr gg bb - Red, green, blue of intensity 0-nnn (binary byte)
42 * RRR GGG BBB - Red, green, blue of intensity 0-nnn (ASCII number)
44 *****************************************************************************/
53 /*****************************************************************************
54 * Local preprocessor defines
55 ******************************************************************************/
57 /*****************************************************************************
59 ******************************************************************************/
61 /*****************************************************************************
63 ******************************************************************************/
65 static int PPM_Line_Number
;
67 /*****************************************************************************
69 ******************************************************************************/
71 static int Open_PPM_File (FILE_HANDLE
*handle
, char *name
, int *width
, int *height
, int buffer_size
, int mode
);
72 static void Write_PPM_Line (FILE_HANDLE
*handle
, COLOUR
*line_data
, int line_number
);
73 static int Read_PPM_Line (FILE_HANDLE
*handle
, COLOUR
*line_data
, int *line_number
);
74 static void Close_PPM_File (FILE_HANDLE
*handle
);
76 /*****************************************************************************
92 ******************************************************************************/
94 FILE_HANDLE
*Get_PPM_File_Handle()
98 handle
= (FILE_HANDLE
*) POV_MALLOC(sizeof(FILE_HANDLE
), "PPM file handle") ;
100 handle
->Open_File_p
= Open_PPM_File
;
101 handle
->Write_Line_p
= Write_PPM_Line
;
102 handle
->Read_Line_p
= Read_PPM_Line
;
103 handle
->Read_Image_p
= Read_PPM_Image
;
104 handle
->Close_File_p
= Close_PPM_File
;
107 handle
->buffer
= NULL
;
108 handle
->buffer_size
= 0;
113 /*****************************************************************************
129 ******************************************************************************/
131 static int Open_PPM_File(FILE_HANDLE
*handle
, char *name
, int *width
, int *height
, int buffer_size
, int mode
)
138 handle
->filename
= name
;
145 /* We can't resume from stdout. */
146 if (opts
.Options
& TO_STDOUT
||
147 (handle
->file
= fopen(name
, READ_BINFILE_STRING
)) == NULL
)
153 if (buffer_size
!= 0)
155 handle
->buffer
= (char *)POV_MALLOC((size_t)buffer_size
, "PPM file buffer") ;
156 setvbuf(handle
->file
, handle
->buffer
, _IOFBF
, buffer_size
);
159 if (fscanf(handle
->file
, "P%c\n", &type
) != 1 || type
!= '6')
164 /* Ignore any comments (if they are written) */
166 while ((input
= fgetc(handle
->file
)) == '#')
168 fgets(junk
, 512, handle
->file
);
171 ungetc(input
, handle
->file
);
173 if (fscanf(handle
->file
, "%d %d\n255\n", width
, height
) != 2)
178 Status_Info("\nResuming interrupted trace from %s",handle
->filename
);
180 handle
->width
= *width
;
181 handle
->height
= *height
;
182 handle
->buffer_size
= buffer_size
;
188 if (opts
.Options
& TO_STDOUT
)
191 handle
->file
= stdout
;
195 if ((handle
->file
= fopen(name
, WRITE_BINFILE_STRING
)) == NULL
)
201 if (buffer_size
!= 0)
203 handle
->buffer
= (char *)POV_MALLOC((size_t)buffer_size
, "PPM file buffer") ;
204 setvbuf(handle
->file
, handle
->buffer
, _IOFBF
, buffer_size
);
207 fprintf(handle
->file
, "P6\n");
211 fprintf(handle
->file
, "# Author: %s\n", TRACER
);
214 fprintf(handle
->file
, "# Source: Persistence of Vision(tm) Ray Tracer v%s%s\n",
215 POV_RAY_VERSION
, COMPILER_VER
);
217 if (!(opts
.Options
& TO_STDOUT
))
219 fprintf(handle
->file
, "# Input File: %s\n", opts
.Input_File_Name
);
222 if (opts
.FrameSeq
.Clock_Value
!= 0)
224 fprintf(handle
->file
, "# POV Clock: %g\n", opts
.FrameSeq
.Clock_Value
);
227 if (opts
.Quality
!= 9)
229 fprintf(handle
->file
, "# Rendering Quality: %d\n", opts
.Quality
);
231 #endif /* POV_COMMENTS */
233 fprintf(handle
->file
, "%d %d\n255\n", *width
, *height
);
235 handle
->width
= *width
;
236 handle
->height
= *height
;
238 handle
->buffer_size
= buffer_size
;
244 if (opts
.Options
& TO_STDOUT
)
247 handle
->file
= stdout
;
251 if ((handle
->file
= fopen(name
, APPEND_BINFILE_STRING
)) == NULL
)
257 if (buffer_size
!= 0)
259 handle
->buffer
= (char *)POV_MALLOC((size_t)buffer_size
, "PPM file buffer") ;
260 setvbuf(handle
->file
, handle
->buffer
, _IOFBF
, buffer_size
);
263 handle
->buffer_size
= buffer_size
;
271 /*****************************************************************************
287 ******************************************************************************/
289 static void Write_PPM_Line(FILE_HANDLE
*handle
, COLOUR
*line_data
, int line_number
)
294 for (x
= 0 ; x
< handle
->width
; x
++)
296 if (opts
.Options
& HF_GRAY_16
) /* 16 bit grayscale output */
298 gray
= ((0.30 * line_data
[x
][RED
]) +
299 (0.59 * line_data
[x
][GREEN
]) +
300 (0.11 * line_data
[x
][BLUE
])) * 65535;
302 if ((putc((gray
>> 8) & 0xFF, handle
->file
) == EOF
) ||
303 (putc(gray
& 0xFF, handle
->file
) == EOF
) ||
304 (putc(0, handle
->file
) == EOF
))
306 Error("Error writing PPM output data to %s.\n",handle
->filename
);
309 else /* Normal 24 bit pixel coloring */
311 if ((putc((int)floor(line_data
[x
][RED
] * 255.0), handle
->file
) == EOF
) ||
312 (putc((int)floor(line_data
[x
][GREEN
]*255.0), handle
->file
) == EOF
) ||
313 (putc((int)floor(line_data
[x
][BLUE
]*255.0), handle
->file
) == EOF
))
315 Error("Error writing PPM output data to %s.\n",handle
->filename
);
322 if (handle
->buffer_size
== 0)
324 /* close and reopen file for integrity in case we crash */
326 fflush(handle
->file
);
328 if (!(opts
.Options
& TO_STDOUT
))
330 handle
->file
= freopen(handle
->filename
,APPEND_BINFILE_STRING
,handle
->file
);
335 /*****************************************************************************
351 ******************************************************************************/
353 static int Read_PPM_Line(FILE_HANDLE
*handle
, COLOUR
*line_data
, int *line_number
)
357 if ((data
= getc(handle
->file
)) == EOF
)
362 ungetc(data
, handle
->file
);
364 *line_number
= PPM_Line_Number
++;
366 for (i
= 0 ; i
< handle
->width
; i
++)
368 if ((data
= getc(handle
->file
)) == EOF
)
373 line_data
[i
][RED
] = (DBL
) data
/ 255.0;
375 if ((data
= getc(handle
->file
)) == EOF
)
380 line_data
[i
][GREEN
] = (DBL
) data
/ 255.0;
382 if ((data
= getc(handle
->file
)) == EOF
)
387 line_data
[i
][BLUE
] = (DBL
) data
/ 255.0;
393 /*****************************************************************************
409 ******************************************************************************/
411 static void Close_PPM_File(FILE_HANDLE
*handle
)
415 fflush(handle
->file
);
417 /* Close and reopen file (if not stdout) for integrity in case we crash */
419 if (!(opts
.Options
& TO_STDOUT
))
420 fclose(handle
->file
);
423 if (handle
->buffer
!= NULL
)
425 POV_FREE(handle
->buffer
);
429 handle
->buffer
= NULL
;
432 /*****************************************************************************
448 ******************************************************************************/
450 void Read_PPM_Image(IMAGE
*Image
, char *name
)
459 IMAGE_LINE
*line_data
;
462 if ((infile
= Locate_File(name
, READ_BINFILE_STRING
, ".ppm", ".PPM",NULL
,TRUE
)) == NULL
)
464 Error("Error opening PPM image %s.\n", name
);
465 return; /* -hdf99- */
468 if (fscanf(infile
, "P%c\n", &type
) != 1 || (type
!= '3' && type
!= '6'))
470 Error ("File is not in PPM format.\n", name
);
471 return; /* -hdf99- */
474 /* Ignore any comments */
476 while ((input
= fgetc(infile
)) == '#')
478 fgets(junk
, 512, infile
);
481 ungetc(input
, infile
);
483 if (fscanf(infile
, "%d %d\n", &width
, &height
) != 2)
485 Error ("Error reading width or height from PPM image.\n", name
);
488 /* Ignore any comments */
489 while ((input
= fgetc(infile
)) == '#')
491 fgets(junk
, 512, infile
);
494 ungetc(input
, infile
);
496 if (fscanf(infile
, "%d\n", &depth
) != 1 || depth
> 255 || depth
< 1)
498 Error ("Unsupported number of colors (%d) in PPM image.\n", depth
);
501 Image
->width
= (DBL
)(Image
->iwidth
= width
);
502 Image
->height
= (DBL
)(Image
->iheight
= height
);
504 Image
->Colour_Map_Size
= 0;
506 Image
->Colour_Map
= NULL
;
508 Image
->data
.rgb_lines
= (IMAGE_LINE
*) POV_MALLOC(Image
->iheight
* sizeof (IMAGE_LINE
), "PPM image");
510 for (y
= 0; y
< height
; y
++)
512 line_data
= &Image
->data
.rgb_lines
[y
];
514 line_data
->red
= (unsigned char *)POV_MALLOC(width
,"PPM image line");
515 line_data
->green
= (unsigned char *)POV_MALLOC(width
,"PPM image line");
516 line_data
->blue
= (unsigned char *)POV_MALLOC(width
,"PPM image line");
517 line_data
->transm
= (unsigned char *)NULL
;
519 if (type
== '3') /* ASCII data to be input */
521 for (x
= 0; x
< width
; x
++)
523 if (fscanf(infile
,"%d",&data
) != 1)
525 Error("Error reading data from PPM image.\n");
528 line_data
->red
[x
] = data
*255/depth
;
530 if (fscanf(infile
,"%d",&data
) != 1)
532 Error("Error reading data from PPM image.\n");
535 line_data
->green
[x
] = data
*255/depth
;
537 if (fscanf(infile
,"%d",&data
) != 1)
539 Error("Error reading data from PPM image.\n");
542 line_data
->blue
[x
] = data
*255/depth
;
545 else /* (type == '6') Raw binary data to be input */
547 for (x
= 0; x
< width
; x
++)
549 if ((data
= getc(infile
)) == EOF
)
551 Error("Error reading data from PPM image.\n");
554 line_data
->red
[x
] = data
*255/depth
;
556 if ((data
= getc(infile
)) == EOF
)
558 Error("Error reading data from PPM image.\n");
561 line_data
->green
[x
] = data
*255/depth
;
563 if ((data
= getc(infile
)) == EOF
)
565 Error("Error reading data from PPM image.\n");
568 line_data
->blue
[x
] = data
*255/depth
;