1 /* png_img.c
2 
3    MolScript v2.1.2
4 
5    PNG image.
6 
7    This implementation is based on the PNG Reference Library 1.0
8    version 0.96 and zlib v1.0.4. It relies on the 'image.c' code,
9    and therefore implicitly on OpenGL and GLX.
10 
11    Copyright (C) 1997-1998 Per Kraulis
12     12-Sep-1997  started
13     21-Dec-1997  identified minor memory leak in PNG library; not fixed
14 */
15 
16 #include <assert.h>
17 #include <stdlib.h>
18 
19 #include <GL/gl.h>
20 
21 #include <png.h>
22 #include <zlib.h>
23 
24 #include "clib/str_utils.h"
25 #include "clib/dynstring.h"
26 
27 #include "png_img.h"
28 #include "global.h"
29 #include "graphics.h"
30 #include "image.h"
31 #include "opengl.h"
32 
33 
34 /*============================================================*/
35 static int compression_level = Z_DEFAULT_COMPRESSION;
36 static png_structp png_ptr;
37 static png_infop info_ptr;
38 static png_text text_ptr[4];
39 
40 
41 /*------------------------------------------------------------*/
42 void
pngi_set(void)43 pngi_set (void)
44 {
45   ogl_set();
46 
47   output_first_plot = pngi_first_plot;
48   output_finish_output = pngi_finish_output;
49   output_start_plot = ogl_start_plot_general;
50 
51   output_pickable = NULL;
52 
53   output_mode = PNG_MODE;
54 }
55 
56 
57 /*------------------------------------------------------------*/
58 void
pngi_first_plot(void)59 pngi_first_plot (void)
60 {
61   int count = 0;
62   dynstring *software_info;
63 
64   image_first_plot();
65   set_outfile ("wb");
66 
67   png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
68   if (png_ptr == NULL)
69     yyerror ("png_img: could not create PNG image structure");
70   info_ptr = png_create_info_struct (png_ptr);
71   if (info_ptr == NULL)
72     yyerror ("png_img: could not create PNG info structure");
73   if (setjmp (png_jmpbuf(png_ptr))) yyerror ("png_img: could not setjmp");
74 
75   png_init_io (png_ptr, outfile);
76   png_set_compression_level (png_ptr, compression_level);
77   png_set_IHDR (png_ptr, info_ptr, output_width, output_height, 8,
78 		PNG_COLOR_TYPE_RGB, NULL, NULL, NULL);
79 
80   if (title) {
81     text_ptr[count].key = "Title";
82     text_ptr[count].text = title;
83     text_ptr[count++].compression = PNG_TEXT_COMPRESSION_NONE;
84   }
85   text_ptr[count].key = "Software";
86   software_info = ds_create (program_str);
87   ds_cat (software_info, ", ");
88   ds_cat (software_info, copyright_str);
89   text_ptr[count].text = software_info->string;
90   text_ptr[count++].compression = PNG_TEXT_COMPRESSION_NONE;
91   if (user_str[0] != '\0') {
92     text_ptr[count].key = "Author";
93     text_ptr[count].text = user_str;
94     text_ptr[count++].compression = PNG_TEXT_COMPRESSION_NONE;
95   }
96   png_set_text (png_ptr, info_ptr, text_ptr, count);
97 
98   png_write_info (png_ptr, info_ptr);
99 
100   ds_delete (software_info);
101 }
102 
103 
104 /*------------------------------------------------------------*/
105 void
pngi_finish_output(void)106 pngi_finish_output (void)
107 {
108   int row;
109   unsigned char *buffer;	/* this ought to be png_bytep? */
110 
111   image_render();
112 
113   buffer = malloc (output_width * 3 * sizeof (unsigned char));
114 
115   for (row = output_height - 1; row >= 0; row--) {
116     glReadPixels (0, row, output_width, 1, GL_RGB, GL_UNSIGNED_BYTE, buffer);
117     png_write_row (png_ptr, (png_bytep) buffer);
118   }
119 
120   free (buffer);
121 
122   png_write_end (png_ptr, NULL);
123   png_destroy_write_struct (&png_ptr, &info_ptr);
124 
125   image_close();
126 }
127 
128 
129 /*------------------------------------------------------------*/
130 int
pngi_set_compression(char * level)131 pngi_set_compression (char *level)
132 {
133   assert (level);
134   assert (*level);
135 
136   if (str_eq (level, "default")) {
137     compression_level = Z_DEFAULT_COMPRESSION;
138   } else if (str_eq (level, "speed")) {
139     compression_level = Z_BEST_SPEED;
140   } else if (str_eq (level, "size")) {
141     compression_level = Z_BEST_COMPRESSION;
142   } else if (str_eq (level, "none")) {
143     compression_level = Z_NO_COMPRESSION;
144   } else {
145     return FALSE;
146   }
147   return TRUE;
148 }
149