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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 175 Revision 178
22#include "compat.h" 22#include "compat.h"
23 23
24#include "generate_routines.h" 24#include "generate_routines.h"
25#include "error.h" 25#include "error.h"
26#include "list.h" 26#include "list.h"
27#include "image.h"
27 28
28#ifdef DMALLOC 29#ifdef DMALLOC
29#include <dmalloc.h> 30#include <dmalloc.h>
30#endif 31#endif
31 32
32typedef psiconv_list psiconv_pixel_bytes; /* psiconv_u8 */
33
34typedef psiconv_list psiconv_pixel_ints; /* of psiconv_u32 */
35
36typedef struct psiconv_pixel_float_s
37{
38 psiconv_u32 length;
39 float *red;
40 float *green;
41 float *blue;
42} psiconv_pixel_floats_t;
43 33
44static int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels, 34static int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels,
45 int xsize,int ysize, 35 int xsize,int ysize,
46 const psiconv_pixel_floats_t data, 36 const psiconv_pixel_floats_t data,
47 int colordepth, 37 int colordepth,int color,
38 int redbits,int greenbits,int bluebits,
48 const psiconv_pixel_floats_t palet); 39 const psiconv_pixel_floats_t palet);
49static int psiconv_pixel_data_to_bytes(const psiconv_config config, 40static int psiconv_pixel_data_to_bytes(const psiconv_config config,
50 psiconv_pixel_bytes *bytes, int xsize, 41 psiconv_pixel_bytes *bytes, int xsize,
51 int ysize, const psiconv_pixel_ints pixels, 42 int ysize, const psiconv_pixel_ints pixels,
52 int colordepth); 43 int colordepth);
53static int psiconv_encode_rle8(const psiconv_config config, 44static int psiconv_encode_rle8(const psiconv_config config,
54 const psiconv_pixel_bytes plain_bytes, 45 const psiconv_pixel_bytes plain_bytes,
55 psiconv_pixel_bytes *encoded_bytes); 46 psiconv_pixel_bytes *encoded_bytes);
47static int psiconv_encode_rle12(const psiconv_config config,
48 const psiconv_pixel_bytes plain_bytes,
49 psiconv_pixel_bytes *encoded_bytes);
56static int psiconv_encode_rle16(const psiconv_config config, 50static int psiconv_encode_rle16(const psiconv_config config,
57 const psiconv_pixel_bytes plain_bytes, 51 const psiconv_pixel_bytes plain_bytes,
58 psiconv_pixel_bytes *encoded_bytes); 52 psiconv_pixel_bytes *encoded_bytes);
59static int psiconv_encode_rle24(const psiconv_config config, 53static int psiconv_encode_rle24(const psiconv_config config,
60 const psiconv_pixel_bytes plain_bytes, 54 const psiconv_pixel_bytes plain_bytes,
61 psiconv_pixel_bytes *encoded_bytes); 55 psiconv_pixel_bytes *encoded_bytes);
62
63#define PALET_GREY_2_LEN 4
64float palet_grey_2_rgb[PALET_GREY_2_LEN] = {0.0/3, 1.0/3, 2.0/3, 3.0/3};
65#define PALET_GREY_4_LEN 16
66float palet_grey_4_rgb[PALET_GREY_4_LEN] =
67 { 0.0/15, 1.0/15, 2.0/15, 3.0/15,
68 4.0/15, 5.0/15, 6.0/15, 7.0/15,
69 8.0/15, 9.0/15, 10.0/15, 11.0/15,
70 12.0/15, 13.0/15, 14.0/15, 15.0/15};
71#define PALET_NONE_LEN 0
72
73psiconv_pixel_floats_t palet_grey_2 =
74 {
75 PALET_GREY_2_LEN,
76 (float *) palet_grey_2_rgb,
77 (float *) palet_grey_2_rgb,
78 (float *) palet_grey_2_rgb
79 };
80
81psiconv_pixel_floats_t palet_grey_4 =
82 {
83 PALET_GREY_4_LEN,
84 (float *) palet_grey_4_rgb,
85 (float *) palet_grey_4_rgb,
86 (float *) palet_grey_4_rgb
87 };
88
89psiconv_pixel_floats_t palet_none =
90 {
91 PALET_NONE_LEN,
92 NULL,
93 NULL,
94 NULL
95 };
96
97 56
98int psiconv_write_paint_data_section(const psiconv_config config, 57int psiconv_write_paint_data_section(const psiconv_config config,
99 psiconv_buffer buf, 58 psiconv_buffer buf,
100 const psiconv_paint_data_section value, 59 const psiconv_paint_data_section value,
101 int is_clipart) 60 int is_clipart)
104 psiconv_pixel_ints ints; 63 psiconv_pixel_ints ints;
105 psiconv_pixel_floats_t floats,palet; 64 psiconv_pixel_floats_t floats,palet;
106 psiconv_list bytes,bytes_rle; 65 psiconv_list bytes,bytes_rle;
107 psiconv_u8 *byteptr,encoding; 66 psiconv_u8 *byteptr,encoding;
108 67
68 /* First, we check whether we can cope with the current configuration.
69 If not, we stop at once */
70 if ((config->colordepth != 2) && (config->colordepth != 4) &&
71 (config->colordepth != 8) && (config->colordepth != 12) &&
72 (config->colordepth != 16) && (config->colordepth != 24)) {
73 psiconv_warn(config,0,psiconv_buffer_length(buf),
74 "Unsupported color depth (%d); try 2, 4, 8, 16 or 24",
75 config->colordepth);
76 res = -PSICONV_E_GENERATE;
77 goto ERROR1;
78 }
79
80 if ((config->color) &&
81 (config->bluebits || config->redbits || config->greenbits) &&
82 (config->bluebits+config->redbits+config->greenbits!=config->colordepth)) {
83 psiconv_warn(config,0,psiconv_buffer_length(buf),
84 "Sum of red (%d), green (%d) and blue (%d) bits should be "
85 "equal to the color depth (%d)",
86 config->redbits,config->greenbits,config->bluebits,
87 config->colordepth);
88 res = -PSICONV_E_GENERATE;
89 goto ERROR1;
90 }
91
92 if (config->color &&
93 !(config->redbits || config->greenbits || config->bluebits) &&
94 (config->colordepth != 4) && (config->colordepth != 8)) {
95 psiconv_warn(config,0,psiconv_buffer_length(buf),
96 "Current color depth (%d) has no palet associated with it",
97 config->colordepth);
98 res = -PSICONV_E_GENERATE;
99 goto ERROR1;
100 }
101
102 if (config->color || (config->colordepth != 2))
103 psiconv_warn(config,0,psiconv_buffer_length(buf),
104 "All image types except 2-bit greyscale are experimental!");
105
106
109 if (!value) { 107 if (!value) {
110 psiconv_warn(config,0,psiconv_buffer_length(buf),"Null paint data section"); 108 psiconv_warn(config,0,psiconv_buffer_length(buf),"Null paint data section");
111 res = -PSICONV_E_GENERATE; 109 res = -PSICONV_E_GENERATE;
112 goto ERROR1; 110 goto ERROR1;
113 } 111 }
115 floats.red = value->red; 113 floats.red = value->red;
116 floats.green = value->green; 114 floats.green = value->green;
117 floats.blue = value->blue; 115 floats.blue = value->blue;
118 floats.length = value->xsize * value->ysize; 116 floats.length = value->xsize * value->ysize;
119 117
118 palet = psiconv_palet_none;
119 if ((config->color) && (config->redbits == 0) && (config->greenbits == 0) &&\
120 (config->bluebits == 0))
120 switch (config->colordepth) { 121 switch (config->colordepth) {
121 default: 122 case 4: palet = psiconv_palet_color_4; break;
122 case 2: palet = (config->color?palet_none:palet_grey_2); 123 case 8: palet = psiconv_palet_color_8; break;
123 break; 124 default: palet = psiconv_palet_none; break;
124 case 4: palet = (config->color?palet_none:palet_grey_4);
125 break;
126 } 125 }
127 126
128 if ((res = psiconv_collect_pixel_data(&ints,value->xsize, 127 if ((res = psiconv_collect_pixel_data(&ints,value->xsize,
129 value->ysize,floats, 128 value->ysize,floats,
130 config->colordepth,palet))) 129 config->colordepth,config->color,
130 config->redbits,config->greenbits,
131 config->bluebits,palet)))
131 goto ERROR1; 132 goto ERROR1;
132 133
133 if ((res = psiconv_pixel_data_to_bytes(config,&bytes,value->xsize,value->ysize, 134 if ((res = psiconv_pixel_data_to_bytes(config,&bytes,value->xsize,value->ysize,
134 ints,config->colordepth))) 135 ints,config->colordepth)))
135 goto ERROR2; 136 goto ERROR2;
136 137
137 138
139 switch (config->colordepth) {
140 case 2:
141 case 4:
142 case 8:
138 encoding = 0x00; 143 encoding = 0x01;
139 if ((res = psiconv_encode_rle8(config,bytes,&bytes_rle))) 144 if ((res = psiconv_encode_rle8(config,bytes,&bytes_rle)))
140 goto ERROR3; 145 goto ERROR3;
146 break;
147 case 12:
148 encoding = 0x02;
149 if ((res = psiconv_encode_rle12(config,bytes,&bytes_rle)))
150 goto ERROR3;
151 break;
152 case 16:
153 encoding = 0x03;
154 if ((res = psiconv_encode_rle16(config,bytes,&bytes_rle)))
155 goto ERROR3;
156 break;
157 case 24:
158 encoding = 0x04;
159 if ((res = psiconv_encode_rle24(config,bytes,&bytes_rle)))
160 goto ERROR3;
161 break;
162 default:
163 encoding = 0x00;
164 }
165 if (encoding) {
141 if (psiconv_list_length(bytes_rle) < psiconv_list_length(bytes)) { 166 if (psiconv_list_length(bytes_rle) < psiconv_list_length(bytes)) {
142 encoding = 0x01;
143 psiconv_list_free(bytes); 167 psiconv_list_free(bytes);
144 bytes = bytes_rle; 168 bytes = bytes_rle;
145 } else { 169 } else {
146 bytes_rle = NULL; 170 psiconv_list_free(bytes_rle);
171 encoding = 0x00;
172 }
147 } 173 }
148 174
149 if ((res = psiconv_write_u32(config,buf, 175 if ((res = psiconv_write_u32(config,buf,
150 0x28+psiconv_list_length(bytes)))) 176 0x28+psiconv_list_length(bytes))))
151 goto ERROR3; 177 goto ERROR3;
158 if ((res = psiconv_write_length(config,buf,value->pic_xsize))) 184 if ((res = psiconv_write_length(config,buf,value->pic_xsize)))
159 goto ERROR3; 185 goto ERROR3;
160 if ((res = psiconv_write_length(config,buf,value->pic_ysize))) 186 if ((res = psiconv_write_length(config,buf,value->pic_ysize)))
161 goto ERROR3; 187 goto ERROR3;
162 colordepth = config->colordepth; 188 colordepth = config->colordepth;
163 if ((colordepth != 2) && colordepth != 4)
164 colordepth = 2;
165 if ((res = psiconv_write_u32(config,buf,colordepth))) 189 if ((res = psiconv_write_u32(config,buf,colordepth)))
166 goto ERROR3; 190 goto ERROR3;
167 if ((res = psiconv_write_u32(config,buf,(config->color?1:0)))) 191 if ((res = psiconv_write_u32(config,buf,(config->color?1:0))))
168 goto ERROR3; 192 goto ERROR3;
169 if ((res = psiconv_write_u32(config,buf,0))) 193 if ((res = psiconv_write_u32(config,buf,0)))
195 The palet is optional; without it, we just use the 219 The palet is optional; without it, we just use the
196 colordepth. With a large palet this is not very fast, but it will do for 220 colordepth. With a large palet this is not very fast, but it will do for
197 now. For greyscale pictures, just use the palet. */ 221 now. For greyscale pictures, just use the palet. */
198int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels,int xsize,int ysize, 222int psiconv_collect_pixel_data(psiconv_pixel_ints *pixels,int xsize,int ysize,
199 const psiconv_pixel_floats_t data, 223 const psiconv_pixel_floats_t data,
200 int colordepth, 224 int colordepth,int color,
225 int redbits,int bluebits,int greenbits,
201 const psiconv_pixel_floats_t palet) 226 const psiconv_pixel_floats_t palet)
202{ 227{
203 int res,x,y,i; 228 int res,x,y,i;
204 psiconv_u32 index,pixel; 229 psiconv_u32 index,pixel;
205 float p_red,p_green,p_blue,mult,dist,new_dist; 230 float p_red,p_green,p_blue,dist,new_dist;
206 231
207 if (!(*pixels = psiconv_list_new(sizeof(psiconv_u32)))) { 232 if (!(*pixels = psiconv_list_new(sizeof(psiconv_u32)))) {
208 res = -PSICONV_E_NOMEM; 233 res = -PSICONV_E_NOMEM;
209 goto ERROR1; 234 goto ERROR1;
210 } 235 }
211 236
212 mult = 1 << colordepth;
213 for (y = 0; y < ysize; y++) { 237 for (y = 0; y < ysize; y++) {
214 for (x = 0; x < xsize; x++) { 238 for (x = 0; x < xsize; x++) {
215 index = y*xsize+x; 239 index = y*xsize+x;
216 p_red = data.red[index]; 240 p_red = data.red[index];
217 p_green = data.green[index]; 241 p_green = data.green[index];
218 p_blue = data.blue[index]; 242 p_blue = data.blue[index];
219 if (!palet.length) { 243 if (!palet.length) {
220 pixel = (((psiconv_u32) (p_red*mult+0.5)) << (2*colordepth)) + 244 if (color)
221 (((psiconv_u32) (p_green*mult+0.5)) << colordepth) + 245 pixel = (((psiconv_u32) (p_red * (1 << redbits) + 0.5))
246 << (greenbits+bluebits)) +
247 (((psiconv_u32) (p_green * (1 << greenbits) + 0.5))
248 << bluebits) +
222 ((psiconv_u32) (p_blue*mult+0.5)); 249 ((psiconv_u32) (p_blue * (1 << bluebits) + 0.5));
250 else
251 pixel = (p_red + p_green + p_blue)/3.0 * (1 << colordepth);
223 } else { 252 } else {
224 dist = 4; /* Max distance is 3, so this is safe */ 253 dist = 4; /* Max distance is 3, so this is safe */
225 pixel = -1; 254 pixel = -1;
226 for (i = 0; i < palet.length; i++) { 255 for (i = 0; i < palet.length; i++) {
227 new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) + 256 new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) +
330 psiconv_list_free(*bytes); 359 psiconv_list_free(*bytes);
331ERROR1: 360ERROR1:
332 return res; 361 return res;
333} 362}
334 363
364/* RLE8 encoding:
365 Marker bytes followed by one or more data bytes.
366 Marker value 0x00-0x7f: repeat the next data byte (marker+1) times
367 Marker value 0xff-0x80: (0x100-marker) data bytes follow */
335int psiconv_encode_rle8(const psiconv_config config, 368int psiconv_encode_rle8(const psiconv_config config,
336 const psiconv_pixel_bytes plain_bytes, 369 const psiconv_pixel_bytes plain_bytes,
337 psiconv_pixel_bytes *encoded_bytes) 370 psiconv_pixel_bytes *encoded_bytes)
338{ 371{
339 int res,i,j,len; 372 int res,i,j,len;
413 psiconv_list_free(*encoded_bytes); 446 psiconv_list_free(*encoded_bytes);
414ERROR1: 447ERROR1:
415 return res; 448 return res;
416} 449}
417 450
451/* RLE12 encoding:
452 Word based. The 12 least significant bits contain the pixel colors.
453 the 4 most signigicant bits are the number of repetitions minus 1 */
454int psiconv_encode_rle12(const psiconv_config config,
455 const psiconv_pixel_bytes plain_bytes,
456 psiconv_pixel_bytes *encoded_bytes)
457{
458 typedef psiconv_list psiconv_word_data; /* of psiconv_u16 */
459 psiconv_word_data data;
460 int res,i,len,location;
461 psiconv_u16 *word_entry,*word_next;
462 psiconv_u16 word_data;
463 psiconv_u8 byte_temp;
464 psiconv_u8 *byte_entry;
465
466
467 /* First extract the 12-bit values to encode */
468 if (!(data = psiconv_list_new(sizeof(psiconv_u16)))) {
469 res = -PSICONV_E_NOMEM;
470 goto ERROR1;
471 }
472
473 for (i = 0; i < psiconv_list_length(plain_bytes); i++) {
474 if (!(byte_entry = psiconv_list_get(plain_bytes,i))) {
475 res = -PSICONV_E_NOMEM;
476 goto ERROR2;
477 }
478 location = 0;
479 if (location == 0) {
480 word_data = *byte_entry;
481 location ++;
482 } else if (location == 1) {
483 word_data = (word_data << 4) + (*byte_entry & 0x0f);
484 if ((res = psiconv_list_add(data,&word_data)))
485 goto ERROR2;
486 word_data = *byte_entry >> 4;
487 location ++;
488 } else {
489 word_data = (word_data << 8) + *byte_entry;
490 if ((res = psiconv_list_add(data,&word_data)))
491 goto ERROR2;
492 location = 0;
493 }
494 }
495
496 if (!(*encoded_bytes = psiconv_list_new(sizeof(psiconv_u8)))) {
497 res = -PSICONV_E_NOMEM;
498 goto ERROR2;
499 }
500
501 for (i = 0; i < psiconv_list_length(data);) {
502 if (!(word_entry = psiconv_list_get(data,i))) {
503 res = -PSICONV_E_NOMEM;
504 goto ERROR3;
505 }
506
507 if (!(word_next = psiconv_list_get(data,i+1))) {
508 res = -PSICONV_E_NOMEM;
509 goto ERROR3;
510 }
511
512 if (i == psiconv_list_length(data) - 2) {
513 byte_temp = *word_entry && 0xff;
514 if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
515 goto ERROR3;
516 byte_temp = *word_entry >> 8;
517 if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
518 goto ERROR3;
519 byte_temp = *word_next && 0xff;
520 if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
521 goto ERROR3;
522 byte_temp = *word_next >> 8;
523 if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
524 goto ERROR3;
525 i += 2;
526 }
527
528 len = 0;
529 while ((*word_entry == *word_next) && (len < 16) &&
530 (i+len+1 < psiconv_list_length(data))) {
531 len ++;
532 if (!(word_next = psiconv_list_get(data,i+len))) {
533 res = -PSICONV_E_NOMEM;
534 goto ERROR3;
535 }
536 }
537
538 byte_temp = *word_entry && 0xff;
539 if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
540 goto ERROR3;
541 byte_temp = (*word_entry >> 8) + ((len - 1) << 4);
542 if ((res = psiconv_list_add(*encoded_bytes,&byte_temp)))
543 goto ERROR3;
544 i += len;
545 }
546 return 0;
547
548ERROR3:
549 psiconv_list_free(*encoded_bytes);
550ERROR2:
551 psiconv_list_free(data);
552ERROR1:
553 return res;
554}
555
556/* RLE16 encoding:
557 Marker bytes followed by one or more data words.
558 Marker value 0x00-0x7f: repeat the next data word (marker+1) times
559 Marker value 0xff-0x80: (0x100-marker) data words follow */
418int psiconv_encode_rle16(const psiconv_config config, 560int psiconv_encode_rle16(const psiconv_config config,
419 const psiconv_pixel_bytes plain_bytes, 561 const psiconv_pixel_bytes plain_bytes,
420 psiconv_pixel_bytes *encoded_bytes) 562 psiconv_pixel_bytes *encoded_bytes)
421{ 563{
422 int res,i,j,len; 564 int res,i,j,len;
525 psiconv_list_free(*encoded_bytes); 667 psiconv_list_free(*encoded_bytes);
526ERROR1: 668ERROR1:
527 return res; 669 return res;
528} 670}
529 671
672/* RLE24 encoding:
673 Marker bytes followed by one or more data byte-triplets.
674 Marker value 0x00-0x7f: repeat the next data byte-triplets (marker+1) times
675 Marker value 0xff-0x80: (0x100-marker) data byte-triplets follow */
530int psiconv_encode_rle24(const psiconv_config config, 676int psiconv_encode_rle24(const psiconv_config config,
531 const psiconv_pixel_bytes plain_bytes, 677 const psiconv_pixel_bytes plain_bytes,
532 psiconv_pixel_bytes *encoded_bytes) 678 psiconv_pixel_bytes *encoded_bytes)
533{ 679{
534 int res,i,j,len; 680 int res,i,j,len;

Legend:
Removed from v.175  
changed lines
  Added in v.178

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