1 | /* |
1 | /* |
2 | generate_image.c - Part of psiconv, a PSION 5 file formats converter |
2 | generate_image.c - Part of psiconv, a PSION 5 file formats converter |
3 | Copyright (c) 1999-2004 Frodo Looijaard <frodol@dds.nl> |
3 | Copyright (c) 1999-2014 Frodo Looijaard <frodo@frodo.looijaard.name> |
4 | |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
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 |
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 |
7 | the Free Software Foundation; either version 2 of the License, or |
8 | (at your option) any later version. |
8 | (at your option) any later version. |
… | |
… | |
34 | int xsize,int ysize, |
34 | int xsize,int ysize, |
35 | const psiconv_pixel_floats_t data, |
35 | const psiconv_pixel_floats_t data, |
36 | int colordepth,int color, |
36 | int colordepth,int color, |
37 | int redbits,int greenbits,int bluebits, |
37 | int redbits,int greenbits,int bluebits, |
38 | const psiconv_pixel_floats_t palet); |
38 | const psiconv_pixel_floats_t palet); |
39 | static int psiconv_pixel_data_to_bytes(const psiconv_config config, |
39 | static int psiconv_pixel_data_to_bytes(const psiconv_config config,int lev, |
40 | psiconv_pixel_bytes *bytes, int xsize, |
40 | psiconv_pixel_bytes *bytes, int xsize, |
41 | int ysize, const psiconv_pixel_ints pixels, |
41 | int ysize, const psiconv_pixel_ints pixels, |
42 | int colordepth); |
42 | int colordepth); |
43 | static int psiconv_encode_rle8(const psiconv_config config, |
43 | static int psiconv_encode_rle8(const psiconv_config config, |
44 | const psiconv_pixel_bytes plain_bytes, |
44 | const psiconv_pixel_bytes plain_bytes, |
… | |
… | |
69 | /* First, we check whether we can cope with the current configuration. |
69 | /* First, we check whether we can cope with the current configuration. |
70 | If not, we stop at once */ |
70 | If not, we stop at once */ |
71 | if ((config->colordepth != 2) && (config->colordepth != 4) && |
71 | if ((config->colordepth != 2) && (config->colordepth != 4) && |
72 | (config->colordepth != 8) && (config->colordepth != 12) && |
72 | (config->colordepth != 8) && (config->colordepth != 12) && |
73 | (config->colordepth != 16) && (config->colordepth != 24)) { |
73 | (config->colordepth != 16) && (config->colordepth != 24)) { |
74 | psiconv_error(config,0,psiconv_buffer_length(buf), |
74 | psiconv_error(config,lev,0, |
75 | "Unsupported color depth (%d); try 2, 4, 8, 16 or 24", |
75 | "Unsupported color depth (%d); try 2, 4, 8, 16 or 24", |
76 | config->colordepth); |
76 | config->colordepth); |
77 | res = -PSICONV_E_GENERATE; |
77 | res = -PSICONV_E_GENERATE; |
78 | goto ERROR1; |
78 | goto ERROR1; |
79 | } |
79 | } |
80 | |
80 | |
81 | if ((config->color) && |
81 | if ((config->color) && |
82 | (config->bluebits || config->redbits || config->greenbits) && |
82 | (config->bluebits || config->redbits || config->greenbits) && |
83 | (config->bluebits+config->redbits+config->greenbits!=config->colordepth)) { |
83 | (config->bluebits+config->redbits+config->greenbits!=config->colordepth)) { |
84 | psiconv_error(config,0,psiconv_buffer_length(buf), |
84 | psiconv_error(config,lev,0, |
85 | "Sum of red (%d), green (%d) and blue (%d) bits should be " |
85 | "Sum of red (%d), green (%d) and blue (%d) bits should be " |
86 | "equal to the color depth (%d)", |
86 | "equal to the color depth (%d)", |
87 | config->redbits,config->greenbits,config->bluebits, |
87 | config->redbits,config->greenbits,config->bluebits, |
88 | config->colordepth); |
88 | config->colordepth); |
89 | res = -PSICONV_E_GENERATE; |
89 | res = -PSICONV_E_GENERATE; |
… | |
… | |
91 | } |
91 | } |
92 | |
92 | |
93 | if (config->color && |
93 | if (config->color && |
94 | !(config->redbits || config->greenbits || config->bluebits) && |
94 | !(config->redbits || config->greenbits || config->bluebits) && |
95 | (config->colordepth != 4) && (config->colordepth != 8)) { |
95 | (config->colordepth != 4) && (config->colordepth != 8)) { |
96 | psiconv_error(config,0,psiconv_buffer_length(buf), |
96 | psiconv_error(config,lev,0, |
97 | "Current color depth (%d) has no palet associated with it", |
97 | "Current color depth (%d) has no palet associated with it", |
98 | config->colordepth); |
98 | config->colordepth); |
99 | res = -PSICONV_E_GENERATE; |
99 | res = -PSICONV_E_GENERATE; |
100 | goto ERROR1; |
100 | goto ERROR1; |
101 | } |
101 | } |
102 | |
102 | |
103 | if (config->color || (config->colordepth != 2)) |
103 | if (config->color || (config->colordepth != 2)) |
104 | psiconv_warn(config,0,psiconv_buffer_length(buf), |
104 | psiconv_warn(config,lev,0, |
105 | "All image types except 2-bit greyscale are experimental!"); |
105 | "All image types except 2-bit greyscale are experimental!"); |
106 | |
106 | |
107 | |
107 | |
108 | if (!value) { |
108 | if (!value) { |
109 | psiconv_error(config,0,psiconv_buffer_length(buf),"Null paint data section"); |
109 | psiconv_error(config,lev,0,"Null paint data section"); |
110 | res = -PSICONV_E_GENERATE; |
110 | res = -PSICONV_E_GENERATE; |
111 | goto ERROR1; |
111 | goto ERROR1; |
112 | } |
112 | } |
113 | |
113 | |
114 | floats.red = value->red; |
114 | floats.red = value->red; |
… | |
… | |
132 | config->bluebits,palet))) { |
132 | config->bluebits,palet))) { |
133 | psiconv_error(config,lev,0,"Error collecting pixel data"); |
133 | psiconv_error(config,lev,0,"Error collecting pixel data"); |
134 | goto ERROR1; |
134 | goto ERROR1; |
135 | } |
135 | } |
136 | |
136 | |
137 | if ((res = psiconv_pixel_data_to_bytes(config,&bytes,value->xsize,value->ysize, |
137 | if ((res = psiconv_pixel_data_to_bytes(config,lev+1,&bytes,value->xsize, |
138 | ints,config->colordepth))) { |
138 | value->ysize,ints, |
|
|
139 | config->colordepth))) { |
139 | psiconv_error(config,lev,0,"Error translating pixel data to bytes"); |
140 | psiconv_error(config,lev,0,"Error translating pixel data to bytes"); |
140 | goto ERROR2; |
141 | goto ERROR2; |
141 | } |
142 | } |
142 | |
143 | |
143 | |
144 | |
… | |
… | |
223 | ERROR3: |
224 | ERROR3: |
224 | psiconv_list_free(bytes); |
225 | psiconv_list_free(bytes); |
225 | ERROR2: |
226 | ERROR2: |
226 | psiconv_list_free(ints); |
227 | psiconv_list_free(ints); |
227 | ERROR1: |
228 | ERROR1: |
|
|
229 | if (res) |
|
|
230 | psiconv_error(config,lev,0,"Writing of paint data section failed"); |
|
|
231 | else |
|
|
232 | psiconv_progress(config,lev,0,"End of paint data section"); |
228 | return res; |
233 | return res; |
229 | } |
234 | } |
230 | |
235 | |
231 | /* Translate the floating point RGB information into pixel values. |
236 | /* Translate the floating point RGB information into pixel values. |
232 | The palet is optional; without it, we just use the |
237 | The palet is optional; without it, we just use the |
… | |
… | |
259 | << (greenbits+bluebits)) + |
264 | << (greenbits+bluebits)) + |
260 | (((psiconv_u32) (p_green * (1 << greenbits) + 0.5)) |
265 | (((psiconv_u32) (p_green * (1 << greenbits) + 0.5)) |
261 | << bluebits) + |
266 | << bluebits) + |
262 | ((psiconv_u32) (p_blue * (1 << bluebits) + 0.5)); |
267 | ((psiconv_u32) (p_blue * (1 << bluebits) + 0.5)); |
263 | else |
268 | else |
264 | pixel = (p_red + p_green + p_blue)/3.0 * (1 << colordepth); |
269 | pixel = (0.212671 * p_red + 0.715160 * p_green + 0.072169 * p_blue) * ((1 << colordepth) * 0.999); |
265 | } else { |
270 | } else { |
266 | dist = 4; /* Max distance is 3, so this is safe */ |
271 | dist = 4; /* Max distance is 3, so this is safe */ |
267 | pixel = -1; |
272 | pixel = -1; |
268 | for (i = 0; i < palet.length; i++) { |
273 | for (i = 0; i < palet.length; i++) { |
269 | new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) + |
274 | new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) + |
… | |
… | |
285 | psiconv_list_free(*pixels); |
290 | psiconv_list_free(*pixels); |
286 | ERROR1: |
291 | ERROR1: |
287 | return res; |
292 | return res; |
288 | } |
293 | } |
289 | |
294 | |
290 | int psiconv_pixel_data_to_bytes(const psiconv_config config, |
295 | int psiconv_pixel_data_to_bytes(const psiconv_config config,int lev, |
291 | psiconv_pixel_bytes *bytes, int xsize, |
296 | psiconv_pixel_bytes *bytes, int xsize, |
292 | int ysize, const psiconv_pixel_ints pixels, |
297 | int ysize, const psiconv_pixel_ints pixels, |
293 | int colordepth) |
298 | int colordepth) |
294 | { |
299 | { |
295 | int res; |
300 | int res; |
… | |
… | |
300 | psiconv_u32 *pixelptr; |
305 | psiconv_u32 *pixelptr; |
301 | int inputbitsleft,outputbitnr,bitsfit,outputbytenr; |
306 | int inputbitsleft,outputbitnr,bitsfit,outputbytenr; |
302 | |
307 | |
303 | |
308 | |
304 | if (!bytes) { |
309 | if (!bytes) { |
305 | psiconv_error(config,0,0,"NULL pixel data"); |
310 | psiconv_error(config,lev,0,"NULL pixel data"); |
306 | res = -PSICONV_E_GENERATE; |
311 | res = -PSICONV_E_GENERATE; |
307 | goto ERROR1; |
312 | goto ERROR1; |
308 | } |
313 | } |
309 | if (!pixels) { |
314 | if (!pixels) { |
310 | psiconv_error(config,0,0,"NULL pixel data"); |
315 | psiconv_error(config,lev,0,"NULL pixel data"); |
311 | res = -PSICONV_E_GENERATE; |
316 | res = -PSICONV_E_GENERATE; |
312 | goto ERROR1; |
317 | goto ERROR1; |
313 | } |
318 | } |
314 | if (psiconv_list_length(pixels) != xsize * ysize) { |
319 | if (psiconv_list_length(pixels) != xsize * ysize) { |
315 | psiconv_error(config,0,0,"Pixel number is not correct"); |
320 | psiconv_error(config,lev,0,"Pixel number is not correct"); |
316 | res = -PSICONV_E_GENERATE; |
321 | res = -PSICONV_E_GENERATE; |
317 | goto ERROR1; |
322 | goto ERROR1; |
318 | } |
323 | } |
319 | |
324 | |
320 | if (!(*bytes = psiconv_list_new(sizeof(psiconv_u8)))) { |
325 | if (!(*bytes = psiconv_list_new(sizeof(psiconv_u8)))) { |
… | |
… | |
327 | outputbyte = 0; |
332 | outputbyte = 0; |
328 | for (y = 0; y < ysize; y++) { |
333 | for (y = 0; y < ysize; y++) { |
329 | outputbytenr = 0; |
334 | outputbytenr = 0; |
330 | for (x = 0; x < xsize; x++) { |
335 | for (x = 0; x < xsize; x++) { |
331 | if (!(pixelptr = psiconv_list_get(pixels,y*xsize+x))) { |
336 | if (!(pixelptr = psiconv_list_get(pixels,y*xsize+x))) { |
332 | psiconv_error(config,0,0,"Massive internal corruption"); |
337 | psiconv_error(config,lev,0,"Data structure corruption"); |
333 | res = -PSICONV_E_NOMEM; |
338 | res = -PSICONV_E_NOMEM; |
334 | goto ERROR2; |
339 | goto ERROR2; |
335 | } |
340 | } |
336 | inputbitsleft = colordepth; |
341 | inputbitsleft = colordepth; |
337 | inputdata = *pixelptr; |
342 | inputdata = *pixelptr; |
… | |
… | |
837 | { |
842 | { |
838 | int res; |
843 | int res; |
839 | |
844 | |
840 | psiconv_progress(config,lev,0,"Writing sketch section"); |
845 | psiconv_progress(config,lev,0,"Writing sketch section"); |
841 | if (!value) { |
846 | if (!value) { |
842 | psiconv_error(config,0,0,"NULL sketch section"); |
847 | psiconv_error(config,lev,0,"NULL sketch section"); |
843 | res = -PSICONV_E_GENERATE; |
848 | res = -PSICONV_E_GENERATE; |
844 | goto ERROR1; |
849 | goto ERROR1; |
845 | } |
850 | } |
846 | |
851 | |
847 | if ((res = psiconv_write_u16(config,buf,lev+1,value->displayed_xsize))) |
852 | if ((res = psiconv_write_u16(config,buf,lev+1,value->displayed_xsize))) |
… | |
… | |
880 | if ((res = psiconv_write_u32(config,buf,lev+1,value->cut_bottom * 0x0c * |
885 | if ((res = psiconv_write_u32(config,buf,lev+1,value->cut_bottom * 0x0c * |
881 | value->displayed_ysize))) |
886 | value->displayed_ysize))) |
882 | goto ERROR1; |
887 | goto ERROR1; |
883 | |
888 | |
884 | ERROR1: |
889 | ERROR1: |
|
|
890 | if (res) |
|
|
891 | psiconv_error(config,lev,0,"Writing of sketch section failed"); |
|
|
892 | else |
|
|
893 | psiconv_progress(config,lev,0,"End of sketch section"); |
885 | return res; |
894 | return res; |
886 | } |
895 | } |
887 | |
896 | |
888 | int psiconv_write_clipart_section(const psiconv_config config, |
897 | int psiconv_write_clipart_section(const psiconv_config config, |
889 | psiconv_buffer buf, int lev, |
898 | psiconv_buffer buf, int lev, |
… | |
… | |
891 | { |
900 | { |
892 | int res; |
901 | int res; |
893 | |
902 | |
894 | psiconv_progress(config,lev,0,"Writing clipart section"); |
903 | psiconv_progress(config,lev,0,"Writing clipart section"); |
895 | if (!value) { |
904 | if (!value) { |
896 | psiconv_error(config,0,psiconv_buffer_length(buf), |
905 | psiconv_error(config,lev,0, "NULL Clipart Section"); |
897 | "NULL Clipart Section"); |
|
|
898 | res = -PSICONV_E_GENERATE; |
906 | res = -PSICONV_E_GENERATE; |
899 | goto ERROR; |
907 | goto ERROR; |
900 | } |
908 | } |
901 | if ((res = psiconv_write_u32(config,buf,lev+1,PSICONV_ID_CLIPART_ITEM))) |
909 | if ((res = psiconv_write_u32(config,buf,lev+1,PSICONV_ID_CLIPART_ITEM))) |
902 | goto ERROR; |
910 | goto ERROR; |
… | |
… | |
910 | goto ERROR; |
918 | goto ERROR; |
911 | if ((res = psiconv_write_paint_data_section(config,buf,lev+1,value->picture,1))) |
919 | if ((res = psiconv_write_paint_data_section(config,buf,lev+1,value->picture,1))) |
912 | goto ERROR; |
920 | goto ERROR; |
913 | |
921 | |
914 | ERROR: |
922 | ERROR: |
|
|
923 | if (res) |
|
|
924 | psiconv_error(config,lev,0,"Writing of clipart section failed"); |
|
|
925 | else |
|
|
926 | psiconv_progress(config,lev,0,"End of clipart section"); |
915 | return res; |
927 | return res; |
916 | } |
928 | } |
917 | |
929 | |
918 | int psiconv_write_jumptable_section(const psiconv_config config, |
930 | int psiconv_write_jumptable_section(const psiconv_config config, |
919 | psiconv_buffer buf, int lev, |
931 | psiconv_buffer buf, int lev, |
… | |
… | |
923 | psiconv_u32 *offset_ptr; |
935 | psiconv_u32 *offset_ptr; |
924 | |
936 | |
925 | psiconv_progress(config,lev,0,"Writing jumptable section"); |
937 | psiconv_progress(config,lev,0,"Writing jumptable section"); |
926 | |
938 | |
927 | if (!value) { |
939 | if (!value) { |
928 | psiconv_error(config,0,psiconv_buffer_length(buf), |
940 | psiconv_error(config,lev,0,"NULL Jumptable Section"); |
929 | "NULL Jumptable Section"); |
|
|
930 | res = -PSICONV_E_GENERATE; |
941 | res = -PSICONV_E_GENERATE; |
931 | goto ERROR; |
942 | goto ERROR; |
932 | } |
943 | } |
933 | if ((res = psiconv_write_u32(config,buf,lev+1,psiconv_list_length(value)))) |
944 | if ((res = psiconv_write_u32(config,buf,lev+1,psiconv_list_length(value)))) |
934 | goto ERROR; |
945 | goto ERROR; |
935 | for (i = 0; i < psiconv_list_length(value); i++) { |
946 | for (i = 0; i < psiconv_list_length(value); i++) { |
936 | if (!(offset_ptr = psiconv_list_get(value,i))) { |
947 | if (!(offset_ptr = psiconv_list_get(value,i))) { |
937 | psiconv_error(config,0,psiconv_buffer_length(buf), |
948 | psiconv_error(config,lev,0,"Massive memory corruption"); |
938 | "Massive memory corruption"); |
|
|
939 | res = -PSICONV_E_NOMEM; |
949 | res = -PSICONV_E_NOMEM; |
940 | goto ERROR; |
950 | goto ERROR; |
941 | } |
951 | } |
942 | if ((res = psiconv_write_offset(config,buf,lev+1,*offset_ptr))) |
952 | if ((res = psiconv_write_offset(config,buf,lev+1,*offset_ptr))) |
943 | goto ERROR; |
953 | goto ERROR; |
944 | } |
954 | } |
945 | |
955 | |
946 | ERROR: |
956 | ERROR: |
|
|
957 | if (res) |
|
|
958 | psiconv_error(config,lev,0,"Writing of jumptable section failed"); |
|
|
959 | else |
|
|
960 | psiconv_progress(config,lev,0,"End of jumptable section"); |
947 | return res; |
961 | return res; |
948 | } |
962 | } |
949 | |
|
|