/[public]/psiconv/trunk/lib/psiconv/generate_image.c
ViewVC logotype

Annotation of /psiconv/trunk/lib/psiconv/generate_image.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 170 - (hide annotations)
Tue Nov 25 22:08:48 2003 UTC (16 years, 6 months ago) by frodo
File MIME type: text/plain
File size: 10704 byte(s)
(Frodo) Generating of Sketch files, both stand-alone and as objects, works!

No RLE encoding yet, we have to test higher colordepths.

1 frodo 86 /*
2     generate_image.c - Part of psiconv, a PSION 5 file formats converter
3     Copyright (c) 1999, 2000 Frodo Looijaard <frodol@dds.nl>
4    
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18     */
19    
20     #include "config.h"
21     #include "compat.h"
22    
23     #include "generate_routines.h"
24     #include "error.h"
25    
26 frodo 142 #ifdef DMALLOC
27     #include <dmalloc.h>
28     #endif
29    
30 frodo 168 typedef psiconv_list psiconv_pixel_bytes; /* psiconv_u8 */
31 frodo 142
32 frodo 168 typedef psiconv_list psiconv_pixel_ints; /* of psiconv_u32 */
33    
34     typedef struct psiconv_pixel_float_s
35     {
36 frodo 170 psiconv_u32 length;
37 frodo 168 float *red;
38     float *green;
39     float *blue;
40     } psiconv_pixel_floats_t;
41    
42 frodo 170 static int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels,
43     int xsize,int ysize,
44 frodo 168 const psiconv_pixel_floats_t data,
45 frodo 170 int colordepth,
46 frodo 168 const psiconv_pixel_floats_t palet);
47 frodo 170 static int psiconv_pixel_data_to_bytes(const psiconv_config config,
48     psiconv_pixel_bytes *bytes, int xsize,
49 frodo 168 int ysize, const psiconv_pixel_ints pixels,
50     int colordepth);
51    
52 frodo 170 #define PALET_GREY_2_LEN 4
53     float palet_grey_2_rgb[PALET_GREY_2_LEN] = {0.0/3, 1.0/3, 2.0/3, 3.0/3};
54     #define PALET_GREY_4_LEN 16
55     float palet_grey_4_rgb[PALET_GREY_4_LEN] =
56     { 0.0/15, 1.0/15, 2.0/15, 3.0/15,
57 frodo 168 4.0/15, 5.0/15, 6.0/15, 7.0/15,
58     8.0/15, 9.0/15, 10.0/15, 11.0/15,
59     12.0/15, 13.0/15, 14.0/15, 15.0/15};
60 frodo 170 #define PALET_NONE_LEN 0
61 frodo 168
62     psiconv_pixel_floats_t palet_grey_2 =
63     {
64 frodo 170 PALET_GREY_2_LEN,
65 frodo 168 (float *) palet_grey_2_rgb,
66     (float *) palet_grey_2_rgb,
67     (float *) palet_grey_2_rgb
68     };
69    
70     psiconv_pixel_floats_t palet_grey_4 =
71     {
72 frodo 170 PALET_GREY_4_LEN,
73 frodo 168 (float *) palet_grey_4_rgb,
74     (float *) palet_grey_4_rgb,
75     (float *) palet_grey_4_rgb
76     };
77    
78 frodo 170 psiconv_pixel_floats_t palet_none =
79     {
80     PALET_NONE_LEN,
81     NULL,
82     NULL,
83     NULL
84     };
85 frodo 168
86 frodo 170
87 frodo 168 int psiconv_write_paint_data_section(const psiconv_config config,
88 frodo 170 psiconv_buffer buf,
89 frodo 168 const psiconv_paint_data_section value)
90     {
91 frodo 170 int res,colordepth,i;
92     psiconv_pixel_ints ints;
93     psiconv_pixel_floats_t floats,palet;
94     psiconv_list bytes;
95     psiconv_u8 *byteptr;
96 frodo 168
97     if (!value) {
98     psiconv_warn(config,0,psiconv_buffer_length(buf),"Null paint data section");
99     res = -PSICONV_E_GENERATE;
100     goto ERROR1;
101     }
102    
103 frodo 170 floats.red = value->red;
104     floats.green = value->green;
105     floats.blue = value->blue;
106     floats.length = value->xsize * value->ysize;
107    
108     switch (config->colordepth) {
109     default:
110     case 2: palet = (config->color?palet_none:palet_grey_2);
111     break;
112     case 4: palet = (config->color?palet_none:palet_grey_4);
113     break;
114     }
115    
116     if ((res = psiconv_collect_pixel_data(&ints,value->xsize,
117     value->ysize,floats,
118     config->colordepth,palet)))
119 frodo 168 goto ERROR1;
120 frodo 170
121     if ((res = psiconv_pixel_data_to_bytes(config,&bytes,value->xsize,value->ysize,
122     ints,config->colordepth)))
123     goto ERROR2;
124    
125     if ((res = psiconv_write_u32(config,buf,0x28+psiconv_list_length(bytes))))
126     goto ERROR3;
127     if ((res = psiconv_write_u32(config,buf,0x28)))
128     goto ERROR3;
129     if ((res = psiconv_write_u32(config,buf,value->xsize)))
130     goto ERROR3;
131     if ((res = psiconv_write_u32(config,buf,value->ysize)))
132     goto ERROR3;
133     if ((res = psiconv_write_length(config,buf,value->pic_xsize)))
134     goto ERROR3;
135     if ((res = psiconv_write_length(config,buf,value->pic_ysize)))
136     goto ERROR3;
137     colordepth = config->colordepth;
138     if ((colordepth != 2) && colordepth != 4)
139     colordepth = 2;
140     if ((res = psiconv_write_u32(config,buf,colordepth)))
141     goto ERROR3;
142     if ((res = psiconv_write_u32(config,buf,(config->color?1:0))))
143     goto ERROR3;
144     if ((res = psiconv_write_u32(config,buf,0)))
145     goto ERROR3;
146     /* Encoding: no RLE for now */
147     if ((res = psiconv_write_u32(config,buf,0)))
148     goto ERROR3;
149     for (i = 0; i < psiconv_list_length(bytes); i++) {
150     if (!(byteptr = psiconv_list_get(bytes,i)))
151     goto ERROR3;
152     if ((res = psiconv_write_u8(config,buf,*byteptr)))
153     goto ERROR3;
154 frodo 168 }
155    
156 frodo 170 ERROR3:
157     psiconv_list_free(bytes);
158 frodo 168 ERROR2:
159 frodo 170 psiconv_list_free(ints);
160 frodo 168 ERROR1:
161     return res;
162     }
163    
164     /* Translate the floating point RGB information into pixel values.
165     The palet is optional; without it, we just use the
166     colordepth. With a large palet this is not very fast, but it will do for
167     now. For greyscale pictures, just use the palet. */
168 frodo 170 int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels,int xsize,int ysize,
169 frodo 168 const psiconv_pixel_floats_t data,
170 frodo 170 int colordepth,
171 frodo 168 const psiconv_pixel_floats_t palet)
172     {
173     int res,x,y,i;
174 frodo 170 psiconv_u32 index,pixel;
175 frodo 168 float p_red,p_green,p_blue,mult,dist,new_dist;
176    
177     if (!(*pixels = psiconv_list_new(sizeof(psiconv_u32)))) {
178     res = -PSICONV_E_NOMEM;
179     goto ERROR1;
180     }
181    
182     mult = 1 << colordepth;
183     for (y = 0; y < ysize; y++) {
184     for (x = 0; x < xsize; x++) {
185 frodo 170 index = y*xsize+x;
186 frodo 168 p_red = data.red[index];
187     p_green = data.green[index];
188     p_blue = data.blue[index];
189 frodo 170 if (!palet.length) {
190     pixel = (((psiconv_u32) (p_red*mult+0.5)) << (2*colordepth)) +
191     (((psiconv_u32) (p_green*mult+0.5)) << colordepth) +
192     ((psiconv_u32) (p_blue*mult+0.5));
193 frodo 168 } else {
194     dist = 4; /* Max distance is 3, so this is safe */
195     pixel = -1;
196 frodo 170 for (i = 0; i < palet.length; i++) {
197 frodo 168 new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) +
198     (p_green - palet.green[i]) * (p_green - palet.green[i]) +
199     (p_blue - palet.blue[i]) * (p_blue - palet.blue[i]);
200     if (new_dist < dist) {
201     pixel = i;
202     dist = new_dist;
203     }
204     }
205     }
206     if ((res = psiconv_list_add(*pixels,&pixel)))
207     goto ERROR2;
208     }
209     }
210     return 0;
211    
212     ERROR2:
213     psiconv_list_free(*pixels);
214     ERROR1:
215     return res;
216     }
217    
218 frodo 170 int psiconv_pixel_data_to_bytes(const psiconv_config config,
219     psiconv_pixel_bytes *bytes, int xsize,
220 frodo 168 int ysize, const psiconv_pixel_ints pixels,
221     int colordepth)
222     {
223     int res;
224     int x,y;
225    
226     psiconv_u32 inputdata;
227     psiconv_u8 outputbyte;
228     psiconv_u32 *pixelptr;
229 frodo 170 int inputbitsleft,outputbitnr,bitsfit,outputbytenr;
230 frodo 168
231    
232     if (!bytes) {
233     psiconv_warn(config,0,0,"NULL pixel data");
234     res = -PSICONV_E_GENERATE;
235     goto ERROR1;
236     }
237     if (!pixels) {
238     psiconv_warn(config,0,0,"NULL pixel data");
239     res = -PSICONV_E_GENERATE;
240     goto ERROR1;
241     }
242     if (psiconv_list_length(pixels) != xsize * ysize) {
243     psiconv_warn(config,0,0,"Pixel number is not correct");
244     res = -PSICONV_E_GENERATE;
245     goto ERROR1;
246     }
247    
248     if (!(*bytes = psiconv_list_new(sizeof(psiconv_u8)))) {
249     res = -PSICONV_E_NOMEM;
250     goto ERROR1;
251     }
252    
253    
254     outputbitnr = 0;
255     outputbyte = 0;
256     for (y = 0; y < ysize; y++) {
257 frodo 170 outputbytenr = 0;
258 frodo 168 for (x = 0; x < xsize; x++) {
259     if (!(pixelptr = psiconv_list_get(pixels,y*xsize+x))) {
260     psiconv_warn(config,0,0,"Massive internal corruption");
261     res = -PSICONV_E_NOMEM;
262     goto ERROR2;
263     }
264     inputbitsleft = colordepth;
265     inputdata = *pixelptr;
266     while (inputbitsleft) {
267     bitsfit = (inputbitsleft+outputbitnr<=8?inputbitsleft:8-outputbitnr);
268     outputbyte |= (inputdata & ((1 << bitsfit) - 1)) << outputbitnr;
269     inputdata = inputdata >> bitsfit;
270     inputbitsleft -= bitsfit;
271     outputbitnr += bitsfit;
272     if (outputbitnr == 8) {
273     if ((res = psiconv_list_add(*bytes,&outputbyte)))
274     goto ERROR2;
275     outputbitnr = 0;
276     outputbyte = 0;
277 frodo 170 outputbytenr ++;
278 frodo 168 }
279     }
280     }
281 frodo 170 /* Always end lines on a long border */
282 frodo 168 if (outputbitnr != 0) {
283     if ((res = psiconv_list_add(*bytes,&outputbyte)))
284     goto ERROR2;
285     outputbitnr = 0;
286     outputbyte = 0;
287 frodo 170 outputbytenr ++;
288 frodo 168 }
289 frodo 170
290     while (outputbytenr % 0x04) {
291     if ((res = psiconv_list_add(*bytes,&outputbyte)))
292     goto ERROR2;
293     outputbytenr ++;
294     }
295 frodo 168 }
296    
297     return 0;
298    
299     ERROR2:
300     psiconv_list_free(*bytes);
301     ERROR1:
302     return res;
303     }
304 frodo 170
305     int psiconv_write_sketch_section(const psiconv_config config,
306     psiconv_buffer buf,
307     psiconv_sketch_section value)
308     {
309     int res;
310    
311     if (!value) {
312     psiconv_warn(config,0,0,"NULL sketch section");
313     res = -PSICONV_E_GENERATE;
314     goto ERROR1;
315     }
316    
317     if ((res = psiconv_write_u16(config,buf,value->displayed_xsize)))
318     goto ERROR1;
319     if ((res = psiconv_write_u16(config,buf,value->displayed_ysize)))
320     goto ERROR1;
321     if ((res = psiconv_write_u16(config,buf,value->picture_data_x_offset)))
322     goto ERROR1;
323     if ((res = psiconv_write_u16(config,buf,value->picture_data_y_offset)))
324     goto ERROR1;
325     if ((res = psiconv_write_u16(config,buf,value->displayed_size_x_offset)))
326     goto ERROR1;
327     if ((res = psiconv_write_u16(config,buf,value->displayed_size_y_offset)))
328     goto ERROR1;
329     if ((res = psiconv_write_u16(config,buf,value->form_xsize)))
330     goto ERROR1;
331     if ((res = psiconv_write_u16(config,buf,value->form_ysize)))
332     goto ERROR1;
333     if ((res = psiconv_write_u16(config,buf,0x0000)))
334     goto ERROR1;
335     if ((res = psiconv_write_paint_data_section(config,buf,value->picture)))
336     goto ERROR1;
337     if ((res = psiconv_write_u16(config,buf,value->magnification_x * 0x03e8)))
338     goto ERROR1;
339     if ((res = psiconv_write_u16(config,buf,value->magnification_y * 0x03e8)))
340     goto ERROR1;
341     if ((res = psiconv_write_u32(config,buf,value->cut_left * 0x0c *
342     value->displayed_xsize)))
343     goto ERROR1;
344     if ((res = psiconv_write_u32(config,buf,value->cut_right * 0x0c *
345     value->displayed_xsize)))
346     goto ERROR1;
347     if ((res = psiconv_write_u32(config,buf,value->cut_top * 0x0c *
348     value->displayed_ysize)))
349     goto ERROR1;
350     if ((res = psiconv_write_u32(config,buf,value->cut_bottom * 0x0c *
351     value->displayed_ysize)))
352     goto ERROR1;
353    
354     ERROR1:
355     return res;
356     }

frodo@frodo.looijaard.name
ViewVC Help
Powered by ViewVC 1.1.26