… | |
… | |
25 | |
25 | |
26 | #ifdef DMALLOC |
26 | #ifdef DMALLOC |
27 | #include <dmalloc.h> |
27 | #include <dmalloc.h> |
28 | #endif |
28 | #endif |
29 | |
29 | |
|
|
30 | typedef psiconv_list psiconv_pixel_bytes; /* psiconv_u8 */ |
30 | |
31 | |
|
|
32 | typedef psiconv_list psiconv_pixel_ints; /* of psiconv_u32 */ |
|
|
33 | |
|
|
34 | typedef struct psiconv_pixel_float_s |
|
|
35 | { |
|
|
36 | float *red; |
|
|
37 | float *green; |
|
|
38 | float *blue; |
|
|
39 | } psiconv_pixel_floats_t; |
|
|
40 | |
|
|
41 | static int psiconv_collect_pixel_data(const psiconv_config config, |
|
|
42 | psiconv_pixel_ints *pixels,int xsize, |
|
|
43 | int ysize, |
|
|
44 | const psiconv_pixel_floats_t data, |
|
|
45 | int colordepth, int palet_len, |
|
|
46 | const psiconv_pixel_floats_t palet); |
|
|
47 | |
|
|
48 | static int psiconv_pixel_data_to_bytes(const psiconv_config config, psiconv_pixel_bytes *bytes, int xsize, |
|
|
49 | int ysize, const psiconv_pixel_ints pixels, |
|
|
50 | int colordepth); |
|
|
51 | |
|
|
52 | float palet_grey_2_rgb[4] = {0.0/3, 1.0/3, 2.0/3, 3.0/3}; |
|
|
53 | float palet_grey_4_rgb[16] = { 0.0/15, 1.0/15, 2.0/15, 3.0/15, |
|
|
54 | 4.0/15, 5.0/15, 6.0/15, 7.0/15, |
|
|
55 | 8.0/15, 9.0/15, 10.0/15, 11.0/15, |
|
|
56 | 12.0/15, 13.0/15, 14.0/15, 15.0/15}; |
|
|
57 | |
|
|
58 | psiconv_pixel_floats_t palet_grey_2 = |
|
|
59 | { |
|
|
60 | (float *) palet_grey_2_rgb, |
|
|
61 | (float *) palet_grey_2_rgb, |
|
|
62 | (float *) palet_grey_2_rgb |
|
|
63 | }; |
|
|
64 | |
|
|
65 | psiconv_pixel_floats_t palet_grey_4 = |
|
|
66 | { |
|
|
67 | (float *) palet_grey_4_rgb, |
|
|
68 | (float *) palet_grey_4_rgb, |
|
|
69 | (float *) palet_grey_4_rgb |
|
|
70 | }; |
|
|
71 | |
|
|
72 | |
|
|
73 | /* For now, we only write 2-bit non-RLE-encoded stuff */ |
|
|
74 | int psiconv_write_paint_data_section(const psiconv_config config, |
|
|
75 | psiconv_buffer buf, |
|
|
76 | const psiconv_paint_data_section value) |
|
|
77 | { |
|
|
78 | int res; |
|
|
79 | psiconv_buffer pix_buf; |
|
|
80 | |
|
|
81 | if (!value) { |
|
|
82 | psiconv_warn(config,0,psiconv_buffer_length(buf),"Null paint data section"); |
|
|
83 | res = -PSICONV_E_GENERATE; |
|
|
84 | goto ERROR1; |
|
|
85 | } |
|
|
86 | |
|
|
87 | if (!(pix_buf = psiconv_buffer_new())) { |
|
|
88 | res = -PSICONV_E_NOMEM; |
|
|
89 | goto ERROR1; |
|
|
90 | } |
|
|
91 | |
|
|
92 | return 0; |
|
|
93 | |
|
|
94 | ERROR2: |
|
|
95 | psiconv_buffer_free(pix_buf); |
|
|
96 | ERROR1: |
|
|
97 | return res; |
|
|
98 | } |
|
|
99 | |
|
|
100 | /* Translate the floating point RGB information into pixel values. |
|
|
101 | The palet is optional; without it, we just use the |
|
|
102 | colordepth. With a large palet this is not very fast, but it will do for |
|
|
103 | now. For greyscale pictures, just use the palet. */ |
|
|
104 | int psiconv_collect_pixel_data(const psiconv_config config, |
|
|
105 | psiconv_pixel_ints *pixels,int xsize,int ysize, |
|
|
106 | const psiconv_pixel_floats_t data, |
|
|
107 | int colordepth, int palet_len, |
|
|
108 | const psiconv_pixel_floats_t palet) |
|
|
109 | { |
|
|
110 | int res,x,y,i; |
|
|
111 | psiconv_u32 index,mask,pixel; |
|
|
112 | float p_red,p_green,p_blue,mult,dist,new_dist; |
|
|
113 | |
|
|
114 | if (!(*pixels = psiconv_list_new(sizeof(psiconv_u32)))) { |
|
|
115 | res = -PSICONV_E_NOMEM; |
|
|
116 | goto ERROR1; |
|
|
117 | } |
|
|
118 | |
|
|
119 | mult = 1 << colordepth; |
|
|
120 | mask = mult -1; |
|
|
121 | for (y = 0; y < ysize; y++) { |
|
|
122 | for (x = 0; x < xsize; x++) { |
|
|
123 | index = y*ysize+x; |
|
|
124 | p_red = data.red[index]; |
|
|
125 | p_green = data.green[index]; |
|
|
126 | p_blue = data.blue[index]; |
|
|
127 | if (! palet_len) { |
|
|
128 | pixel = (((psiconv_u32) (p_red*mult) & mask) << (2*colordepth)) + |
|
|
129 | (((psiconv_u32) (p_green*mult) & mask) << colordepth) + |
|
|
130 | ((psiconv_u32) (p_blue*mult) & mask); |
|
|
131 | } else { |
|
|
132 | dist = 4; /* Max distance is 3, so this is safe */ |
|
|
133 | pixel = -1; |
|
|
134 | for (i = 0; i < palet_len; i++) { |
|
|
135 | new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) + |
|
|
136 | (p_green - palet.green[i]) * (p_green - palet.green[i]) + |
|
|
137 | (p_blue - palet.blue[i]) * (p_blue - palet.blue[i]); |
|
|
138 | if (new_dist < dist) { |
|
|
139 | pixel = i; |
|
|
140 | dist = new_dist; |
|
|
141 | } |
|
|
142 | } |
|
|
143 | } |
|
|
144 | if ((res = psiconv_list_add(*pixels,&pixel))) |
|
|
145 | goto ERROR2; |
|
|
146 | } |
|
|
147 | } |
|
|
148 | return 0; |
|
|
149 | |
|
|
150 | ERROR2: |
|
|
151 | psiconv_list_free(*pixels); |
|
|
152 | ERROR1: |
|
|
153 | return res; |
|
|
154 | } |
|
|
155 | |
|
|
156 | int psiconv_pixel_data_to_bytes(const psiconv_config config, psiconv_pixel_bytes *bytes, int xsize, |
|
|
157 | int ysize, const psiconv_pixel_ints pixels, |
|
|
158 | int colordepth) |
|
|
159 | { |
|
|
160 | int res; |
|
|
161 | int x,y; |
|
|
162 | |
|
|
163 | psiconv_u32 inputdata; |
|
|
164 | psiconv_u8 outputbyte; |
|
|
165 | psiconv_u32 *pixelptr; |
|
|
166 | int inputbitsleft,outputbitnr,bitsfit; |
|
|
167 | |
|
|
168 | |
|
|
169 | if (!bytes) { |
|
|
170 | psiconv_warn(config,0,0,"NULL pixel data"); |
|
|
171 | res = -PSICONV_E_GENERATE; |
|
|
172 | goto ERROR1; |
|
|
173 | } |
|
|
174 | if (!pixels) { |
|
|
175 | psiconv_warn(config,0,0,"NULL pixel data"); |
|
|
176 | res = -PSICONV_E_GENERATE; |
|
|
177 | goto ERROR1; |
|
|
178 | } |
|
|
179 | if (psiconv_list_length(pixels) != xsize * ysize) { |
|
|
180 | psiconv_warn(config,0,0,"Pixel number is not correct"); |
|
|
181 | res = -PSICONV_E_GENERATE; |
|
|
182 | goto ERROR1; |
|
|
183 | } |
|
|
184 | |
|
|
185 | if (!(*bytes = psiconv_list_new(sizeof(psiconv_u8)))) { |
|
|
186 | res = -PSICONV_E_NOMEM; |
|
|
187 | goto ERROR1; |
|
|
188 | } |
|
|
189 | |
|
|
190 | |
|
|
191 | outputbitnr = 0; |
|
|
192 | outputbyte = 0; |
|
|
193 | for (y = 0; y < ysize; y++) { |
|
|
194 | for (x = 0; x < xsize; x++) { |
|
|
195 | if (!(pixelptr = psiconv_list_get(pixels,y*xsize+x))) { |
|
|
196 | psiconv_warn(config,0,0,"Massive internal corruption"); |
|
|
197 | res = -PSICONV_E_NOMEM; |
|
|
198 | goto ERROR2; |
|
|
199 | } |
|
|
200 | inputbitsleft = colordepth; |
|
|
201 | inputdata = *pixelptr; |
|
|
202 | while (inputbitsleft) { |
|
|
203 | bitsfit = (inputbitsleft+outputbitnr<=8?inputbitsleft:8-outputbitnr); |
|
|
204 | outputbyte |= (inputdata & ((1 << bitsfit) - 1)) << outputbitnr; |
|
|
205 | inputdata = inputdata >> bitsfit; |
|
|
206 | inputbitsleft -= bitsfit; |
|
|
207 | outputbitnr += bitsfit; |
|
|
208 | if (outputbitnr == 8) { |
|
|
209 | if ((res = psiconv_list_add(*bytes,&outputbyte))) |
|
|
210 | goto ERROR2; |
|
|
211 | outputbitnr = 0; |
|
|
212 | outputbyte = 0; |
|
|
213 | } |
|
|
214 | } |
|
|
215 | } |
|
|
216 | /* Always end lines on a byte border */ |
|
|
217 | if (outputbitnr != 0) { |
|
|
218 | if ((res = psiconv_list_add(*bytes,&outputbyte))) |
|
|
219 | goto ERROR2; |
|
|
220 | outputbitnr = 0; |
|
|
221 | outputbyte = 0; |
|
|
222 | } |
|
|
223 | } |
|
|
224 | |
|
|
225 | return 0; |
|
|
226 | |
|
|
227 | ERROR2: |
|
|
228 | psiconv_list_free(*bytes); |
|
|
229 | ERROR1: |
|
|
230 | return res; |
|
|
231 | } |