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