This commit was manufactured by cvs2svn to create tag 'mac102'.
[python/dscho.git] / Modules / imageop.c
blob57cb90b7e7d6089afec07eaee2ba11927e6e0795
1 /***********************************************************
2 Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3 Amsterdam, The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* imageopmodule - Various operations on pictures */
27 #ifdef sun
28 #define signed
29 #endif
31 #include "allobjects.h"
32 #include "modsupport.h"
34 #define CHARP(cp, xmax, x, y) ((char *)(cp+y*xmax+x))
35 #define LONGP(cp, xmax, x, y) ((long *)(cp+4*(y*xmax+x)))
37 static object *ImageopError;
39 static object *
40 imageop_crop(self, args)
41 object *self;
42 object *args;
44 char *cp, *ncp;
45 long *nlp;
46 int len, size, x, y, newx1, newx2, newy1, newy2;
47 int ix, iy, xstep, ystep;
48 object *rv;
50 if ( !getargs(args, "(s#iiiiiii)", &cp, &len, &size, &x, &y,
51 &newx1, &newy1, &newx2, &newy2) )
52 return 0;
54 if ( size != 1 && size != 4 ) {
55 err_setstr(ImageopError, "Size should be 1 or 4");
56 return 0;
58 if ( len != size*x*y ) {
59 err_setstr(ImageopError, "String has incorrect length");
60 return 0;
62 xstep = (newx1 < newx2)? 1 : -1;
63 ystep = (newy1 < newy2)? 1 : -1;
65 rv = newsizedstringobject(NULL,
66 (abs(newx2-newx1)+1)*(abs(newy2-newy1)+1)*size);
67 if ( rv == 0 )
68 return 0;
69 ncp = (char *)getstringvalue(rv);
70 nlp = (long *)ncp;
71 newy2 += ystep;
72 newx2 += xstep;
73 for( iy = newy1; iy != newy2; iy+=ystep ) {
74 for ( ix = newx1; ix != newx2; ix+=xstep ) {
75 if ( iy < 0 || iy >= y || ix < 0 || ix >= x ) {
76 if ( size == 1 ) *ncp++ = 0;
77 else *nlp++ = 0;
78 } else {
79 if ( size == 1 ) *ncp++ = *CHARP(cp, x, ix, iy);
80 else *nlp++ = *LONGP(cp, x, ix, iy);
84 return rv;
87 static object *
88 imageop_scale(self, args)
89 object *self;
90 object *args;
92 char *cp, *ncp;
93 long *nlp;
94 int len, size, x, y, newx, newy;
95 int ix, iy;
96 int oix, oiy;
97 object *rv;
99 if ( !getargs(args, "(s#iiiii)", &cp, &len, &size, &x, &y, &newx, &newy) )
100 return 0;
102 if ( size != 1 && size != 4 ) {
103 err_setstr(ImageopError, "Size should be 1 or 4");
104 return 0;
106 if ( len != size*x*y ) {
107 err_setstr(ImageopError, "String has incorrect length");
108 return 0;
111 rv = newsizedstringobject(NULL, newx*newy*size);
112 if ( rv == 0 )
113 return 0;
114 ncp = (char *)getstringvalue(rv);
115 nlp = (long *)ncp;
116 for( iy = 0; iy < newy; iy++ ) {
117 for ( ix = 0; ix < newx; ix++ ) {
118 oix = ix * x / newx;
119 oiy = iy * y / newy;
120 if ( size == 1 ) *ncp++ = *CHARP(cp, x, oix, oiy);
121 else *nlp++ = *LONGP(cp, x, oix, oiy);
124 return rv;
127 /* Note: this routine can use a bit of optimizing */
129 static object *
130 imageop_tovideo(self, args)
131 object *self;
132 object *args;
134 int maxx, maxy, x, y, len;
135 int i;
136 unsigned char *cp, *ncp, cdata;
137 int width;
138 object *rv;
141 if ( !getargs(args, "(s#iii)", &cp, &len, &width, &maxx, &maxy) )
142 return 0;
144 if ( width != 1 && width != 4 ) {
145 err_setstr(ImageopError, "Size should be 1 or 4");
146 return 0;
148 if ( maxx*maxy*width != len ) {
149 err_setstr(ImageopError, "String has incorrect length");
150 return 0;
153 rv = newsizedstringobject(NULL, len);
154 if ( rv == 0 )
155 return 0;
156 ncp = (unsigned char *)getstringvalue(rv);
158 if ( width == 1 ) {
159 memcpy(ncp, cp, maxx); /* Copy first line */
160 ncp += maxx;
161 for (y=1; y<maxy; y++) { /* Interpolate other lines */
162 for(x=0; x<maxx; x++) {
163 i = y*maxx + x;
164 *ncp++ = ((int)cp[i] + (int)cp[i-maxx]) >> 1;
167 } else {
168 memcpy(ncp, cp, maxx*4); /* Copy first line */
169 ncp += maxx*4;
170 for (y=1; y<maxy; y++) { /* Interpolate other lines */
171 for(x=0; x<maxx; x++) {
172 i = (y*maxx + x)*4 + 1;
173 *ncp++ = 0; /* Skip alfa comp */
174 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
175 i++;
176 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
177 i++;
178 *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1;
182 return rv;
185 static object *
186 imageop_grey2mono(self, args)
187 object *self;
188 object *args;
190 int tres, x, y, len;
191 unsigned char *cp, *ncp;
192 unsigned char ovalue;
193 object *rv;
194 int i, bit;
197 if ( !getargs(args, "(s#iii)", &cp, &len, &x, &y, &tres) )
198 return 0;
200 if ( x*y != len ) {
201 err_setstr(ImageopError, "String has incorrect length");
202 return 0;
205 rv = newsizedstringobject(NULL, (len+7)/8);
206 if ( rv == 0 )
207 return 0;
208 ncp = (unsigned char *)getstringvalue(rv);
210 bit = 0x80;
211 ovalue = 0;
212 for ( i=0; i < len; i++ ) {
213 if ( (int)cp[i] > tres )
214 ovalue |= bit;
215 bit >>= 1;
216 if ( bit == 0 ) {
217 *ncp++ = ovalue;
218 bit = 0x80;
219 ovalue = 0;
222 if ( bit != 0x80 )
223 *ncp++ = ovalue;
224 return rv;
227 static object *
228 imageop_grey2grey4(self, args)
229 object *self;
230 object *args;
232 int x, y, len;
233 unsigned char *cp, *ncp;
234 unsigned char ovalue;
235 object *rv;
236 int i;
237 int pos;
240 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
241 return 0;
243 if ( x*y != len ) {
244 err_setstr(ImageopError, "String has incorrect length");
245 return 0;
248 rv = newsizedstringobject(NULL, (len+1)/2);
249 if ( rv == 0 )
250 return 0;
251 ncp = (unsigned char *)getstringvalue(rv);
252 pos = 0;
253 ovalue = 0;
254 for ( i=0; i < len; i++ ) {
255 ovalue |= ((int)cp[i] & 0xf0) >> pos;
256 pos += 4;
257 if ( pos == 8 ) {
258 *ncp++ = ovalue;
259 ovalue = 0;
260 pos = 0;
263 if ( pos != 0 )
264 *ncp++ = ovalue;
265 return rv;
268 static object *
269 imageop_grey2grey2(self, args)
270 object *self;
271 object *args;
273 int x, y, len;
274 unsigned char *cp, *ncp;
275 unsigned char ovalue;
276 object *rv;
277 int i;
278 int pos;
281 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
282 return 0;
284 if ( x*y != len ) {
285 err_setstr(ImageopError, "String has incorrect length");
286 return 0;
289 rv = newsizedstringobject(NULL, (len+3)/4);
290 if ( rv == 0 )
291 return 0;
292 ncp = (unsigned char *)getstringvalue(rv);
293 pos = 0;
294 ovalue = 0;
295 for ( i=0; i < len; i++ ) {
296 ovalue |= ((int)cp[i] & 0xc0) >> pos;
297 pos += 2;
298 if ( pos == 8 ) {
299 *ncp++ = ovalue;
300 ovalue = 0;
301 pos = 0;
304 if ( pos != 0 )
305 *ncp++ = ovalue;
306 return rv;
309 static object *
310 imageop_dither2mono(self, args)
311 object *self;
312 object *args;
314 int sum, x, y, len;
315 unsigned char *cp, *ncp;
316 unsigned char ovalue;
317 object *rv;
318 int i, bit;
321 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
322 return 0;
324 if ( x*y != len ) {
325 err_setstr(ImageopError, "String has incorrect length");
326 return 0;
329 rv = newsizedstringobject(NULL, (len+7)/8);
330 if ( rv == 0 )
331 return 0;
332 ncp = (unsigned char *)getstringvalue(rv);
334 bit = 0x80;
335 ovalue = 0;
336 sum = 0;
337 for ( i=0; i < len; i++ ) {
338 sum += cp[i];
339 if ( sum >= 256 ) {
340 sum -= 256;
341 ovalue |= bit;
343 bit >>= 1;
344 if ( bit == 0 ) {
345 *ncp++ = ovalue;
346 bit = 0x80;
347 ovalue = 0;
350 if ( bit != 0x80 )
351 *ncp++ = ovalue;
352 return rv;
355 static object *
356 imageop_dither2grey2(self, args)
357 object *self;
358 object *args;
360 int x, y, len;
361 unsigned char *cp, *ncp;
362 unsigned char ovalue;
363 object *rv;
364 int i;
365 int pos;
366 int sum, nvalue;
369 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
370 return 0;
372 if ( x*y != len ) {
373 err_setstr(ImageopError, "String has incorrect length");
374 return 0;
377 rv = newsizedstringobject(NULL, (len+3)/4);
378 if ( rv == 0 )
379 return 0;
380 ncp = (unsigned char *)getstringvalue(rv);
381 pos = 1;
382 ovalue = 0;
383 for ( i=0; i < len; i++ ) {
384 sum += cp[i];
385 nvalue = sum & 0x180;
386 sum -= nvalue;
387 ovalue |= nvalue >> pos;
388 pos += 2;
389 if ( pos == 9 ) {
390 *ncp++ = ovalue;
391 ovalue = 0;
392 pos = 1;
395 if ( pos != 0 )
396 *ncp++ = ovalue;
397 return rv;
400 static object *
401 imageop_mono2grey(self, args)
402 object *self;
403 object *args;
405 int v0, v1, x, y, len, nlen;
406 unsigned char *cp, *ncp;
407 unsigned char ovalue;
408 object *rv;
409 int i, bit, value;
411 if ( !getargs(args, "(s#iiii)", &cp, &len, &x, &y, &v0, &v1) )
412 return 0;
414 nlen = x*y;
415 if ( (nlen+7)/8 != len ) {
416 err_setstr(ImageopError, "String has incorrect length");
417 return 0;
420 rv = newsizedstringobject(NULL, nlen);
421 if ( rv == 0 )
422 return 0;
423 ncp = (unsigned char *)getstringvalue(rv);
425 bit = 0x80;
426 for ( i=0; i < nlen; i++ ) {
427 if ( *cp & bit )
428 *ncp++ = v1;
429 else
430 *ncp++ = v0;
431 bit >>= 1;
432 if ( bit == 0 ) {
433 bit = 0x80;
434 cp++;
437 return rv;
440 static object *
441 imageop_grey22grey(self, args)
442 object *self;
443 object *args;
445 int x, y, len, nlen;
446 unsigned char *cp, *ncp;
447 unsigned char ovalue;
448 object *rv;
449 int i, pos, value, nvalue;
451 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
452 return 0;
454 nlen = x*y;
455 if ( (nlen+3)/4 != len ) {
456 err_setstr(ImageopError, "String has incorrect length");
457 return 0;
460 rv = newsizedstringobject(NULL, nlen);
461 if ( rv == 0 )
462 return 0;
463 ncp = (unsigned char *)getstringvalue(rv);
465 pos = 0;
466 for ( i=0; i < nlen; i++ ) {
467 if ( pos == 0 ) {
468 value = *cp++;
469 pos = 8;
471 pos -= 2;
472 nvalue = (value >> pos) & 0x03;
473 *ncp++ = nvalue | (nvalue << 2) | (nvalue << 4) | (nvalue << 6);
475 return rv;
478 static object *
479 imageop_grey42grey(self, args)
480 object *self;
481 object *args;
483 int x, y, len, nlen;
484 unsigned char *cp, *ncp;
485 unsigned char ovalue;
486 object *rv;
487 int i, pos, value, nvalue;
489 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
490 return 0;
492 nlen = x*y;
493 if ( (nlen+1)/2 != len ) {
494 err_setstr(ImageopError, "String has incorrect length");
495 return 0;
498 rv = newsizedstringobject(NULL, nlen);
499 if ( rv == 0 )
500 return 0;
501 ncp = (unsigned char *)getstringvalue(rv);
503 pos = 0;
504 for ( i=0; i < nlen; i++ ) {
505 if ( pos == 0 ) {
506 value = *cp++;
507 pos = 8;
509 pos -= 4;
510 nvalue = (value >> pos) & 0x0f;
511 *ncp++ = nvalue | (nvalue << 4);
513 return rv;
516 static object *
517 imageop_rgb2rgb8(self, args)
518 object *self;
519 object *args;
521 int x, y, len, nlen;
522 unsigned long *cp;
523 unsigned char *ncp;
524 object *rv;
525 int i, r, g, b;
526 unsigned long value, nvalue;
528 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
529 return 0;
531 nlen = x*y;
532 if ( nlen*4 != len ) {
533 err_setstr(ImageopError, "String has incorrect length");
534 return 0;
537 rv = newsizedstringobject(NULL, nlen);
538 if ( rv == 0 )
539 return 0;
540 ncp = (unsigned char *)getstringvalue(rv);
542 for ( i=0; i < nlen; i++ ) {
543 /* Bits in source: aaaaaaaa BBbbbbbb GGGggggg RRRrrrrr */
544 value = *cp++;
545 #if 0
546 r = (value >> 5) & 7;
547 g = (value >> 13) & 7;
548 b = (value >> 22) & 3;
549 #else
550 r = (int) ((value & 0xff) / 255. * 7. + .5);
551 g = (int) (((value >> 8) & 0xff) / 255. * 7. + .5);
552 b = (int) (((value >> 16) & 0xff) / 255. * 3. + .5);
553 #endif
554 nvalue = (r<<5) | (b<<3) | g;
555 *ncp++ = nvalue;
557 return rv;
560 static object *
561 imageop_rgb82rgb(self, args)
562 object *self;
563 object *args;
565 int x, y, len, nlen;
566 unsigned char *cp;
567 unsigned long *ncp;
568 object *rv;
569 int i, r, g, b;
570 unsigned long value, nvalue;
572 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
573 return 0;
575 nlen = x*y;
576 if ( nlen != len ) {
577 err_setstr(ImageopError, "String has incorrect length");
578 return 0;
581 rv = newsizedstringobject(NULL, nlen*4);
582 if ( rv == 0 )
583 return 0;
584 ncp = (unsigned long *)getstringvalue(rv);
586 for ( i=0; i < nlen; i++ ) {
587 /* Bits in source: RRRBBGGG
588 ** Red and Green are multiplied by 36.5, Blue by 85
590 value = *cp++;
591 r = (value >> 5) & 7;
592 g = (value ) & 7;
593 b = (value >> 3) & 3;
594 r = (r<<5) | (r<<3) | (r>>1);
595 g = (g<<5) | (g<<3) | (g>>1);
596 b = (b<<6) | (b<<4) | (b<<2) | b;
597 nvalue = r | (g<<8) | (b<<16);
598 *ncp++ = nvalue;
600 return rv;
603 static object *
604 imageop_rgb2grey(self, args)
605 object *self;
606 object *args;
608 int x, y, len, nlen;
609 unsigned long *cp;
610 unsigned char *ncp;
611 object *rv;
612 int i, r, g, b;
613 unsigned long value, nvalue;
615 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
616 return 0;
618 nlen = x*y;
619 if ( nlen*4 != len ) {
620 err_setstr(ImageopError, "String has incorrect length");
621 return 0;
624 rv = newsizedstringobject(NULL, nlen);
625 if ( rv == 0 )
626 return 0;
627 ncp = (unsigned char *)getstringvalue(rv);
629 for ( i=0; i < nlen; i++ ) {
630 value = *cp++;
631 r = (value ) & 0xff;
632 g = (value >> 8) & 0xff;
633 b = (value >> 16) & 0xff;
634 nvalue = (int)(0.30*r + 0.59*g + 0.11*b);
635 if ( nvalue > 255 ) nvalue = 255;
636 *ncp++ = nvalue;
638 return rv;
641 static object *
642 imageop_grey2rgb(self, args)
643 object *self;
644 object *args;
646 int x, y, len, nlen;
647 unsigned char *cp;
648 unsigned long *ncp;
649 object *rv;
650 int i;
651 unsigned long value;
653 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
654 return 0;
656 nlen = x*y;
657 if ( nlen != len ) {
658 err_setstr(ImageopError, "String has incorrect length");
659 return 0;
662 rv = newsizedstringobject(NULL, nlen*4);
663 if ( rv == 0 )
664 return 0;
665 ncp = (unsigned long *)getstringvalue(rv);
667 for ( i=0; i < nlen; i++ ) {
668 value = *cp++;
669 *ncp++ = value | (value << 8 ) | (value << 16);
671 return rv;
675 static object *
676 imageop_mul(self, args)
677 object *self;
678 object *args;
680 char *cp, *ncp;
681 int len, size, x, y;
682 object *rv;
683 int i;
685 if ( !getargs(args, "(s#iii)", &cp, &len, &size, &x, &y) )
686 return 0;
688 if ( size != 1 && size != 4 ) {
689 err_setstr(ImageopError, "Size should be 1 or 4");
690 return 0;
692 if ( len != size*x*y ) {
693 err_setstr(ImageopError, "String has incorrect length");
694 return 0;
697 rv = newsizedstringobject(NULL, XXXX);
698 if ( rv == 0 )
699 return 0;
700 ncp = (char *)getstringvalue(rv);
703 for ( i=0; i < len; i += size ) {
705 return rv;
709 static struct methodlist imageop_methods[] = {
710 { "crop", imageop_crop },
711 { "scale", imageop_scale },
712 { "grey2mono", imageop_grey2mono },
713 { "grey2grey2", imageop_grey2grey2 },
714 { "grey2grey4", imageop_grey2grey4 },
715 { "dither2mono", imageop_dither2mono },
716 { "dither2grey2", imageop_dither2grey2 },
717 { "mono2grey", imageop_mono2grey },
718 { "grey22grey", imageop_grey22grey },
719 { "grey42grey", imageop_grey42grey },
720 { "tovideo", imageop_tovideo },
721 { "rgb2rgb8", imageop_rgb2rgb8 },
722 { "rgb82rgb", imageop_rgb82rgb },
723 { "rgb2grey", imageop_rgb2grey },
724 { "grey2rgb", imageop_grey2rgb },
725 { 0, 0 }
729 void
730 initimageop()
732 object *m, *d;
733 m = initmodule("imageop", imageop_methods);
734 d = getmoduledict(m);
735 ImageopError = newstringobject("imageop.error");
736 if ( ImageopError == NULL || dictinsert(d,"error",ImageopError) )
737 fatal("can't define imageop.error");