BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / translators / ppm / colorspace.cpp
blobc64dcc194386117d76fee1f9e502ca625371670a
1 /* colorspace.cpp */
2 /*
3 Copyright 1999, Be Incorporated. All Rights Reserved.
4 This file may be used under the terms of the Be Sample Code License.
5 */
8 #include <GraphicsDefs.h>
9 #include <InterfaceDefs.h>
10 #include <Debug.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
16 #include "colorspace.h"
19 #if !defined(_PR3_COMPATIBLE_)
20 #define B_CMY24 ((color_space)0xC001) /* C[7:0] M[7:0] Y[7:0] No gray removal done */
21 #define B_CMY32 ((color_space)0xC002) /* C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done */
22 #define B_CMYA32 ((color_space)0xE002) /* C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done */
23 #define B_CMYK32 ((color_space)0xC003) /* C[7:0] M[7:0] Y[7:0] K[7:0] */
24 #endif
26 int
27 expand_data( /* expands to BGRA in the output buffer from <whatever> in the input buffer */
28 color_space from_space,
29 unsigned char * in_data,
30 int rowbytes,
31 unsigned char * out_buf)
33 ASSERT(in_data != out_buf);
35 /* We don't do YUV and friends yet. */
36 /* It's important to replicate the most significant component bits to LSB when going 15->24 */
37 unsigned char * in_out = out_buf;
38 switch (from_space) {
39 case B_RGB32:
40 while (rowbytes > 3) {
41 out_buf[0] = in_data[0];
42 out_buf[1] = in_data[1];
43 out_buf[2] = in_data[2];
44 out_buf[3] = 255;
45 out_buf += 4;
46 in_data += 4;
47 rowbytes -= 4;
49 break;
50 case B_RGBA32:
51 memcpy(out_buf, in_data, rowbytes);
52 break;
53 case B_RGB24:
54 while (rowbytes > 2) {
55 out_buf[0] = in_data[0];
56 out_buf[1] = in_data[1];
57 out_buf[2] = in_data[2];
58 out_buf[3] = 255;
59 out_buf += 4;
60 in_data += 3;
61 rowbytes -= 3;
63 break;
64 case B_RGB15:
65 while (rowbytes > 1) {
66 uint16 val = in_data[0]+(in_data[1]<<8);
67 out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
68 out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
69 out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
70 out_buf[3] = 255;
71 out_buf += 4;
72 in_data += 2;
73 rowbytes -= 2;
75 break;
76 case B_RGBA15:
77 while (rowbytes > 1) {
78 uint16 val = in_data[0]+(in_data[1]<<8);
79 out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
80 out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
81 out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
82 out_buf[3] = (val&0x8000) ? 255 : 0;
83 out_buf += 4;
84 in_data += 2;
85 rowbytes -= 2;
87 break;
88 case B_RGB16:
89 while (rowbytes > 1) {
90 uint16 val = in_data[0]+(in_data[1]<<8);
91 out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
92 out_buf[1] = ((val&0x7e0)>>3)|((val&0x7e0)>>9);
93 out_buf[2] = ((val&0xf800)>>8)|((val&0xf800)>>13);
94 out_buf[3] = 255;
95 out_buf += 4;
96 in_data += 2;
97 rowbytes -= 2;
99 break;
100 case B_RGB32_BIG:
101 while (rowbytes > 3) {
102 out_buf[0] = in_data[3];
103 out_buf[1] = in_data[2];
104 out_buf[2] = in_data[1];
105 out_buf[3] = 255;
106 out_buf += 4;
107 in_data += 4;
108 rowbytes -= 4;
110 break;
111 case B_RGBA32_BIG:
112 while (rowbytes > 3) {
113 out_buf[0] = in_data[3];
114 out_buf[1] = in_data[2];
115 out_buf[2] = in_data[1];
116 out_buf[3] = in_data[0];
117 out_buf += 4;
118 in_data += 4;
119 rowbytes -= 4;
121 break;
122 case B_RGB24_BIG:
123 while (rowbytes > 2) {
124 out_buf[0] = in_data[2];
125 out_buf[1] = in_data[1];
126 out_buf[2] = in_data[0];
127 out_buf[3] = 255;
128 out_buf += 4;
129 in_data += 3;
130 rowbytes -= 3;
132 break;
133 case B_RGB15_BIG:
134 while (rowbytes > 1) {
135 uint16 val = in_data[1]+(in_data[0]<<8);
136 out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
137 out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
138 out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
139 out_buf[3] = 255;
140 out_buf += 4;
141 in_data += 2;
142 rowbytes -= 2;
144 break;
145 case B_RGBA15_BIG:
146 while (rowbytes > 1) {
147 uint16 val = in_data[1]+(in_data[0]<<8);
148 out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
149 out_buf[1] = ((val&0x3e0)>>2)|((val&0x3e0)>>7);
150 out_buf[2] = ((val&0x7c00)>>7)|((val&0x7c00)>>12);
151 out_buf[3] = (val&0x8000) ? 255 : 0;
152 out_buf += 4;
153 in_data += 2;
154 rowbytes -= 2;
156 break;
157 case B_RGB16_BIG:
158 while (rowbytes > 1) {
159 uint16 val = in_data[1]+(in_data[0]<<8);
160 out_buf[0] = ((val&0x1f)<<3)|((val&0x1f)>>2);
161 out_buf[1] = ((val&0x7e0)>>3)|((val&0x7e0)>>9);
162 out_buf[2] = ((val&0xf800)>>8)|((val&0xf800)>>13);
163 out_buf[3] = 255;
164 out_buf += 4;
165 in_data += 2;
166 rowbytes -= 2;
168 break;
169 case B_CMAP8: {
170 const color_map * map = system_colors();
171 while (rowbytes > 0) {
172 rgb_color c = map->color_list[in_data[0]];
173 out_buf[0] = c.blue;
174 out_buf[1] = c.green;
175 out_buf[2] = c.red;
176 out_buf[3] = c.alpha;
177 out_buf += 4;
178 in_data += 1;
179 rowbytes -= 1;
181 } break;
182 case B_GRAY8:
183 while (rowbytes > 0) {
184 unsigned char ch = *in_data;
185 out_buf[0] = ch;
186 out_buf[1] = ch;
187 out_buf[2] = ch;
188 out_buf[3] = 255;
189 out_buf += 4;
190 in_data += 1;
191 rowbytes -= 1;
193 break;
194 case B_GRAY1:
195 while (rowbytes > 0) { /* expansion 1->32 is pretty good :-) */
196 unsigned char c1 = *in_data;
197 for (int b = 128; b; b = b>>1) {
198 unsigned char ch;
199 if (c1 & b) {
200 ch = 0;
202 else {
203 ch = 255;
205 out_buf[0] = ch;
206 out_buf[1] = ch;
207 out_buf[2] = ch;
208 out_buf[3] = 255;
209 out_buf += 4;
211 in_data += 1;
212 rowbytes -= 1;
214 break;
215 case B_CMY24: /* We do the "clean" inversion which doesn't correct for printing ink deficiencies. */
216 while (rowbytes > 2) {
217 out_buf[0] = 255-in_data[2];
218 out_buf[1] = 255-in_data[1];
219 out_buf[2] = 255-in_data[0];
220 out_buf[3] = 255;
221 out_buf += 4;
222 in_data += 3;
223 rowbytes -= 3;
225 break;
226 case B_CMY32:
227 while (rowbytes > 3) {
228 out_buf[0] = 255-in_data[2];
229 out_buf[1] = 255-in_data[1];
230 out_buf[2] = 255-in_data[0];
231 out_buf[3] = 255;
232 out_buf += 4;
233 in_data += 4;
234 rowbytes -= 4;
236 break;
237 case B_CMYA32:
238 while (rowbytes > 3) {
239 out_buf[0] = 255-in_data[2];
240 out_buf[1] = 255-in_data[1];
241 out_buf[2] = 255-in_data[0];
242 out_buf[3] = in_data[3];
243 out_buf += 4;
244 in_data += 4;
245 rowbytes -= 4;
247 break;
248 case B_CMYK32: /* We assume uniform gray removal, and no under-color-removal. */
249 while (rowbytes > 3) {
250 int comp = 255-in_data[2]-in_data[3];
251 out_buf[0] = comp < 0 ? 0 : comp;
252 comp = 255-in_data[1]-in_data[3];
253 out_buf[1] = comp < 0 ? 0 : comp;
254 comp = 255-in_data[0]-in_data[3];
255 out_buf[2] = comp < 0 ? 0 : comp;
256 out_buf[3] = 255;
257 out_buf += 4;
258 in_data += 4;
259 rowbytes -= 4;
261 break;
262 default:
263 break;
265 return out_buf - in_out;
270 collapse_data(
271 unsigned char * in_buf,
272 int num_bytes,
273 color_space out_space,
274 unsigned char * out_buf)
276 ASSERT(in_buf != out_buf);
278 unsigned char * in_out = out_buf;
279 /* We could increase perceived image quality of down conversions by implementing */
280 /* dithering. However, someone might want to operate on the images after */
281 /* conversion, in which case dithering would be un-good. Besides, good error */
282 /* diffusion requires more than one scan line to propagate errors to. */
283 switch(out_space) {
284 case B_RGB32:
285 memcpy(out_buf, in_buf, num_bytes);
286 break;
287 case B_RGBA32:
288 memcpy(out_buf, in_buf, num_bytes);
289 break;
290 case B_RGB24:
291 while (num_bytes > 3) {
292 out_buf[0] = in_buf[0];
293 out_buf[1] = in_buf[1];
294 out_buf[2] = in_buf[2];
295 out_buf += 3;
296 in_buf += 4;
297 num_bytes -= 4;
299 break;
300 case B_RGB16:
301 while (num_bytes > 3) {
302 uint16 val = (in_buf[0]>>3)|((in_buf[1]<<3)&0x7e0)|((in_buf[2]<<8)&0xf800);
303 out_buf[0] = val;
304 out_buf[1] = val>>8;
305 out_buf += 2;
306 in_buf += 4;
307 num_bytes -= 4;
309 break;
310 case B_RGB15:
311 while (num_bytes > 3) {
312 uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00)|0x8000;
313 out_buf[0] = val;
314 out_buf[1] = val>>8;
315 out_buf += 2;
316 in_buf += 4;
317 num_bytes -= 4;
319 break;
320 case B_RGBA15:
321 while (num_bytes > 3) {
322 uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00);
323 if (in_buf[3] > 127) {
324 val = val | 0x8000;
326 out_buf[0] = val;
327 out_buf[1] = val>>8;
328 out_buf += 2;
329 in_buf += 4;
330 num_bytes -= 4;
332 break;
333 case B_CMAP8: {
334 const color_map * map = system_colors();
335 while (num_bytes > 3) {
336 if (in_buf[3] < 128) {
337 out_buf[0] = B_TRANSPARENT_8_BIT;
339 else {
340 uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00);
341 out_buf[0] = map->index_map[val];
343 out_buf += 1;
344 in_buf += 4;
345 num_bytes -= 4;
348 break;
349 case B_GRAY8:
350 while (num_bytes > 3) { /* There are better algorithms than Y = .25B+.50G+.25R */
351 /* but hardly faster -- and it's still better than (B+G+R)/3 ! */
352 out_buf[0] = (in_buf[0]+in_buf[1]*2+in_buf[2])>>2;
353 out_buf += 1;
354 in_buf += 4;
355 num_bytes -= 4;
357 break;
358 case B_GRAY1: {
359 uchar ob = 0;
360 int cnt = 0;
361 uchar c = 0;
362 while (num_bytes > 3) {
363 if (cnt == 8) {
364 out_buf[0] = ob;
365 out_buf += 1;
366 cnt = 0;
367 ob = 0;
369 c = ((in_buf[0]+in_buf[1]*2+in_buf[2])&0x200)>>(2+cnt);
370 ob = ob | c;
371 cnt++;
372 in_buf += 4;
373 num_bytes -= 4;
375 if (cnt > 0) {
376 out_buf[0] = ob;
377 out_buf += 1;
379 } break;
380 /* big endian version, when the encoding is not endianess independant */
381 case B_RGB32_BIG:
382 while (num_bytes > 3) {
383 out_buf[3] = in_buf[0];
384 out_buf[2] = in_buf[1];
385 out_buf[1] = in_buf[2];
386 out_buf += 4;
387 in_buf += 4;
388 num_bytes -= 4;
390 break;
391 case B_RGBA32_BIG:
392 while (num_bytes > 3) {
393 out_buf[3] = in_buf[0];
394 out_buf[2] = in_buf[1];
395 out_buf[1] = in_buf[2];
396 out_buf[0] = in_buf[3];
397 out_buf += 4;
398 in_buf += 4;
399 num_bytes -= 4;
401 break;
402 case B_RGB24_BIG:
403 while (num_bytes > 3) {
404 out_buf[2] = in_buf[0];
405 out_buf[1] = in_buf[1];
406 out_buf[0] = in_buf[2];
407 out_buf += 3;
408 in_buf += 4;
409 num_bytes -= 4;
411 break;
412 case B_RGB16_BIG:
413 while (num_bytes > 3) {
414 uint16 val = (in_buf[0]>>3)|((in_buf[1]<<3)&0x7e0)|((in_buf[2]<<8)&0xf800);
415 out_buf[0] = val>>8;
416 out_buf[1] = val;
417 out_buf += 2;
418 in_buf += 4;
419 num_bytes -= 4;
421 break;
422 case B_RGB15_BIG:
423 while (num_bytes > 3) {
424 uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00)|0x8000;
425 out_buf[0] = val>>8;
426 out_buf[1] = val;
427 out_buf += 2;
428 in_buf += 4;
429 num_bytes -= 4;
431 break;
432 case B_RGBA15_BIG:
433 while (num_bytes > 3) {
434 uint16 val = (in_buf[0]>>3)|((in_buf[1]<<2)&0x3e0)|((in_buf[2]<<7)&0x7c00);
435 if (in_buf[3] > 127) {
436 val = val | 0x8000;
438 out_buf[0] = val>>8;
439 out_buf[1] = val;
440 out_buf += 2;
441 in_buf += 4;
442 num_bytes -= 4;
444 break;
445 case B_CMY24:
446 while (num_bytes > 3) {
447 out_buf[0] = 255-in_buf[2];
448 out_buf[1] = 255-in_buf[1];
449 out_buf[2] = 255-in_buf[0];
450 out_buf += 3;
451 in_buf += 4;
452 num_bytes -= 4;
454 break;
455 case B_CMY32:
456 while (num_bytes > 3) {
457 out_buf[0] = 255-in_buf[2];
458 out_buf[1] = 255-in_buf[1];
459 out_buf[2] = 255-in_buf[0];
460 out_buf += 4;
461 in_buf += 4;
462 num_bytes -= 4;
464 break;
465 case B_CMYA32:
466 while (num_bytes > 3) {
467 out_buf[0] = 255-in_buf[2];
468 out_buf[1] = 255-in_buf[1];
469 out_buf[2] = 255-in_buf[0];
470 out_buf[3] = in_buf[3];
471 out_buf += 4;
472 in_buf += 4;
473 num_bytes -= 4;
475 break;
476 case B_CMYK32:
477 while (num_bytes > 3) { /* We do direct gray removal */
478 int c = 255-in_buf[2];
479 int m = 255-in_buf[1];
480 int y = 255-in_buf[0];
481 int k = (c>m)?((y>c)?y:c):((y>m)?y:m);
482 out_buf[0] = c-k;
483 out_buf[1] = m-k;
484 out_buf[2] = y-k;
485 out_buf[3] = k;
486 out_buf += 4;
487 in_buf += 4;
488 num_bytes -= 4;
490 break;
491 default:
492 break;
494 return out_buf-in_out;
498 #if DEBUG_DATA
499 static void
500 print_data(
501 unsigned char * ptr,
502 int n)
504 while (n-- > 0) {
505 printf("%02x ", *(ptr++));
507 printf("\n");
509 #endif
512 status_t
513 convert_space(
514 color_space in_space,
515 color_space out_space,
516 unsigned char * in_data,
517 int rowbytes,
518 unsigned char * out_data)
520 ASSERT(in_data != out_data);
522 /* Instead of coding each transformation separately, which would create */
523 /* a very large number of conversion functions, we write one function to */
524 /* convert to RGBA32, and another function to convert from RGBA32, and */
525 /* put them together to get a manageable program, at a slight expense in */
526 /* conversion speed. */
528 int n;
529 #if DEBUG_DATA
530 printf("convert_space(%x, %x, %x)\n", in_space, out_space, rowbytes);
531 printf("raw data: ");
532 print_data(in_data, rowbytes);
533 #endif
534 /* If we convert from a format to itself, well... */
535 if (in_space == out_space) {
536 memcpy(out_data, in_data, rowbytes);
537 return B_OK;
539 /* When the input format is RGBA32, we don't need the first conversion. */
540 if (in_space == B_RGBA32) {
541 n = collapse_data(in_data, rowbytes, out_space, out_data);
542 #if DEBUG_DATA
543 printf("collapsed data: ");
544 print_data(out_data, n);
545 #endif
546 return B_OK;
548 /* When the output format is RGBA32, we don't need any second conversion. */
549 if (out_space == B_RGB32 || out_space == B_RGBA32) {
550 n = expand_data(in_space, in_data, rowbytes, out_data);
551 #if DEBUG_DATA
552 printf("expanded data: ");
553 print_data(out_data, n);
554 #endif
555 return B_OK;
557 /* Figure out byte expansion rate -- usually isn't more than 4 */
558 int mul = 4;
559 if (in_space == B_GRAY1) {
560 mul = 32;
562 unsigned char * buf = (unsigned char *)malloc(rowbytes*mul);
563 if (buf == NULL) {
564 /* oops! */
565 return B_NO_MEMORY;
567 n = expand_data(in_space, in_data, rowbytes, buf);
568 #if DEBUG_DATA
569 printf("expanded data: ");
570 print_data(out_data, n);
571 #endif
572 n = collapse_data(buf, n, out_space, out_data);
573 #if DEBUG_DATA
574 printf("collapsed data: ");
575 print_data(out_data, n);
576 #endif
577 free(buf);
578 return B_OK;
583 /* Figure out what the rowbytes is for a given width in a given color space. */
584 /* Rowbytes is bytes per pixel times width, rounded up to nearest multiple of 4. */
586 calc_rowbytes(
587 color_space space,
588 int width)
590 int v = width*4;
591 switch (space) {
592 default:
593 /* 4 is fine */
594 break;
595 case B_RGB24:
596 case B_CMY24:
597 case B_RGB24_BIG:
598 v = width*3;
599 break;
600 case B_RGB15:
601 case B_RGBA15:
602 case B_RGB16:
603 case B_RGB15_BIG:
604 case B_RGBA15_BIG:
605 case B_RGB16_BIG:
606 v = width*2;
607 break;
608 case B_CMAP8:
609 case B_GRAY8:
610 v = width;
611 break;
612 case B_GRAY1:
613 v = (width+7)/8; /* whole bytes only, please */
614 break;
616 v = (v+3)&~3;
617 return v;