blob: 67aa9fc7486d4cb84a13bd1bd6c8afe963c393a8 [file] [log] [blame]
Guido van Rossum0317a471992-10-26 13:40:15 +00001/***********************************************************
Guido van Rossum34679b71993-01-26 13:33:44 +00002Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
3Amsterdam, The Netherlands.
Guido van Rossum0317a471992-10-26 13:40:15 +00004
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* imageopmodule - Various operations on pictures */
26
27#ifdef sun
28#define signed
29#endif
30
31#include "allobjects.h"
32#include "modsupport.h"
33
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)))
36
37static object *ImageopError;
38
39static object *
40imageop_crop(self, args)
41 object *self;
42 object *args;
43{
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;
49
50 if ( !getargs(args, "(s#iiiiiii)", &cp, &len, &size, &x, &y,
51 &newx1, &newy1, &newx2, &newy2) )
52 return 0;
53
54 if ( size != 1 && size != 4 ) {
55 err_setstr(ImageopError, "Size should be 1 or 4");
56 return 0;
57 }
58 if ( len != size*x*y ) {
59 err_setstr(ImageopError, "String has incorrect length");
60 return 0;
61 }
62 xstep = (newx1 < newx2)? 1 : -1;
63 ystep = (newy1 < newy2)? 1 : -1;
64
Guido van Rossum5f59d601992-12-14 16:59:51 +000065 rv = newsizedstringobject(NULL,
66 (abs(newx2-newx1)+1)*(abs(newy2-newy1)+1)*size);
Guido van Rossum0317a471992-10-26 13:40:15 +000067 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);
81 }
82 }
83 }
84 return rv;
85}
86
87static object *
88imageop_scale(self, args)
89 object *self;
90 object *args;
91{
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;
98
99 if ( !getargs(args, "(s#iiiii)", &cp, &len, &size, &x, &y, &newx, &newy) )
100 return 0;
101
102 if ( size != 1 && size != 4 ) {
103 err_setstr(ImageopError, "Size should be 1 or 4");
104 return 0;
105 }
106 if ( len != size*x*y ) {
107 err_setstr(ImageopError, "String has incorrect length");
108 return 0;
109 }
110
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);
122 }
123 }
124 return rv;
125}
126
Jack Jansend26b4581993-01-22 15:34:43 +0000127/* Note: this routine can use a bit of optimizing */
128
129static object *
130imageop_tovideo(self, args)
131 object *self;
132 object *args;
133{
134 int maxx, maxy, x, y, len;
135 int i;
136 unsigned char *cp, *ncp, cdata;
137 int width;
138 object *rv;
139
140
141 if ( !getargs(args, "(s#iii)", &cp, &len, &width, &maxx, &maxy) )
142 return 0;
143
144 if ( width != 1 && width != 4 ) {
145 err_setstr(ImageopError, "Size should be 1 or 4");
146 return 0;
147 }
148 if ( maxx*maxy*width != len ) {
149 err_setstr(ImageopError, "String has incorrect length");
150 return 0;
151 }
152
153 rv = newsizedstringobject(NULL, len);
154 if ( rv == 0 )
155 return 0;
156 ncp = (unsigned char *)getstringvalue(rv);
157
158 if ( width == 1 ) {
159 bcopy(cp, ncp, 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++ = (cp[i] + cp[i-maxx]) >> 1;
165 }
166 }
167 } else {
168 bcopy(cp, ncp, 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++ = (cp[i] + cp[i-4*maxx]) >> 1;
175 i++;
176 *ncp++ = (cp[i] + cp[i-4*maxx]) >> 1;
177 i++;
178 *ncp++ = (cp[i] + cp[i-4*maxx]) >> 1;
179 }
180 }
181 }
182 return rv;
183}
184
Guido van Rossum5f59d601992-12-14 16:59:51 +0000185static object *
186imageop_grey2mono(self, args)
187 object *self;
188 object *args;
189{
190 int tres, x, y, len;
191 unsigned char *cp, *ncp;
192 unsigned char ovalue;
193 object *rv;
194 int i, bit;
195
196
197 if ( !getargs(args, "(s#iii)", &cp, &len, &x, &y, &tres) )
198 return 0;
199
200 if ( x*y != len ) {
201 err_setstr(ImageopError, "String has incorrect length");
202 return 0;
203 }
204
205 rv = newsizedstringobject(NULL, (len+7)/8);
206 if ( rv == 0 )
207 return 0;
208 ncp = (unsigned char *)getstringvalue(rv);
209
210 bit = 0x80;
211 ovalue = 0;
212 for ( i=0; i < len; i++ ) {
213 if ( cp[i] > tres )
214 ovalue |= bit;
215 bit >>= 1;
216 if ( bit == 0 ) {
217 *ncp++ = ovalue;
218 bit = 0x80;
219 ovalue = 0;
220 }
221 }
222 if ( bit != 0x80 )
223 *ncp++ = ovalue;
224 return rv;
225}
226
227static object *
Jack Jansende3adf91992-12-22 14:05:55 +0000228imageop_grey2grey4(self, args)
229 object *self;
230 object *args;
231{
232 int x, y, len;
233 unsigned char *cp, *ncp;
234 unsigned char ovalue;
235 object *rv;
236 int i;
237 int pos;
238
239
240 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
241 return 0;
242
243 if ( x*y != len ) {
244 err_setstr(ImageopError, "String has incorrect length");
245 return 0;
246 }
247
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 |= (cp[i] & 0xf0) >> pos;
256 pos += 4;
257 if ( pos == 8 ) {
258 *ncp++ = ovalue;
259 ovalue = 0;
260 pos = 0;
261 }
262 }
263 if ( pos != 0 )
264 *ncp++ = ovalue;
265 return rv;
266}
267
268static object *
269imageop_grey2grey2(self, args)
270 object *self;
271 object *args;
272{
273 int x, y, len;
274 unsigned char *cp, *ncp;
275 unsigned char ovalue;
276 object *rv;
277 int i;
278 int pos;
279
280
281 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
282 return 0;
283
284 if ( x*y != len ) {
285 err_setstr(ImageopError, "String has incorrect length");
286 return 0;
287 }
288
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 |= (cp[i] & 0xc0) >> pos;
297 pos += 2;
298 if ( pos == 8 ) {
299 *ncp++ = ovalue;
300 ovalue = 0;
301 pos = 0;
302 }
303 }
304 if ( pos != 0 )
305 *ncp++ = ovalue;
306 return rv;
307}
308
309static object *
Guido van Rossum5f59d601992-12-14 16:59:51 +0000310imageop_dither2mono(self, args)
311 object *self;
312 object *args;
313{
314 int sum, x, y, len;
315 unsigned char *cp, *ncp;
316 unsigned char ovalue;
317 object *rv;
318 int i, bit;
319
320
321 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
322 return 0;
323
324 if ( x*y != len ) {
325 err_setstr(ImageopError, "String has incorrect length");
326 return 0;
327 }
328
329 rv = newsizedstringobject(NULL, (len+7)/8);
330 if ( rv == 0 )
331 return 0;
332 ncp = (unsigned char *)getstringvalue(rv);
333
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;
342 }
343 bit >>= 1;
344 if ( bit == 0 ) {
345 *ncp++ = ovalue;
346 bit = 0x80;
347 ovalue = 0;
348 }
349 }
350 if ( bit != 0x80 )
351 *ncp++ = ovalue;
352 return rv;
353}
354
355static object *
Jack Jansende3adf91992-12-22 14:05:55 +0000356imageop_dither2grey2(self, args)
357 object *self;
358 object *args;
359{
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;
367
368
369 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
370 return 0;
371
372 if ( x*y != len ) {
373 err_setstr(ImageopError, "String has incorrect length");
374 return 0;
375 }
376
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;
393 }
394 }
395 if ( pos != 0 )
396 *ncp++ = ovalue;
397 return rv;
398}
399
400static object *
Guido van Rossum5f59d601992-12-14 16:59:51 +0000401imageop_mono2grey(self, args)
402 object *self;
403 object *args;
404{
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;
410
411 if ( !getargs(args, "(s#iiii)", &cp, &len, &x, &y, &v0, &v1) )
412 return 0;
413
414 nlen = x*y;
415 if ( (nlen+7)/8 != len ) {
416 err_setstr(ImageopError, "String has incorrect length");
417 return 0;
418 }
419
420 rv = newsizedstringobject(NULL, nlen);
421 if ( rv == 0 )
422 return 0;
423 ncp = (unsigned char *)getstringvalue(rv);
424
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++;
435 }
436 }
437 return rv;
438}
439
Jack Jansende3adf91992-12-22 14:05:55 +0000440static object *
441imageop_grey22grey(self, args)
442 object *self;
443 object *args;
444{
445 int x, y, len, nlen;
446 unsigned char *cp, *ncp;
447 unsigned char ovalue;
448 object *rv;
449 int i, pos, value, nvalue;
450
451 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
452 return 0;
453
454 nlen = x*y;
455 if ( (nlen+3)/4 != len ) {
456 err_setstr(ImageopError, "String has incorrect length");
457 return 0;
458 }
459
460 rv = newsizedstringobject(NULL, nlen);
461 if ( rv == 0 )
462 return 0;
463 ncp = (unsigned char *)getstringvalue(rv);
464
465 pos = 0;
466 for ( i=0; i < nlen; i++ ) {
467 if ( pos == 0 ) {
468 value = *cp++;
469 pos = 8;
470 }
471 pos -= 2;
472 nvalue = (value >> pos) & 0x03;
473 *ncp++ = nvalue | (nvalue << 2) | (nvalue << 4) | (nvalue << 6);
474 }
475 return rv;
476}
477
478static object *
479imageop_grey42grey(self, args)
480 object *self;
481 object *args;
482{
483 int x, y, len, nlen;
484 unsigned char *cp, *ncp;
485 unsigned char ovalue;
486 object *rv;
487 int i, pos, value, nvalue;
488
489 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
490 return 0;
491
492 nlen = x*y;
493 if ( (nlen+1)/2 != len ) {
494 err_setstr(ImageopError, "String has incorrect length");
495 return 0;
496 }
497
498 rv = newsizedstringobject(NULL, nlen);
499 if ( rv == 0 )
500 return 0;
501 ncp = (unsigned char *)getstringvalue(rv);
502
503 pos = 0;
504 for ( i=0; i < nlen; i++ ) {
505 if ( pos == 0 ) {
506 value = *cp++;
507 pos = 8;
508 }
509 pos -= 4;
510 nvalue = (value >> pos) & 0x0f;
511 *ncp++ = nvalue | (nvalue << 4);
512 }
513 return rv;
514}
515
Jack Jansen4fada9c1993-02-19 15:51:41 +0000516static object *
517imageop_rgb2rgb8(self, args)
518 object *self;
519 object *args;
520{
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;
527
528 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
529 return 0;
530
531 nlen = x*y;
532 if ( nlen*4 != len ) {
533 err_setstr(ImageopError, "String has incorrect length");
534 return 0;
535 }
536
537 rv = newsizedstringobject(NULL, nlen);
538 if ( rv == 0 )
539 return 0;
540 ncp = (unsigned char *)getstringvalue(rv);
541
542 for ( i=0; i < nlen; i++ ) {
543 /* Bits in source: aaaaaaaa BBbbbbbb GGGggggg RRRrrrrr */
544 value = *cp++;
545 r = (value >> 5) & 7;
546 g = (value >> 13) & 7;
547 b = (value >> 22) & 3;
548 nvalue = (r<<5) | (b<<3) | g;
549 *ncp++ = nvalue;
550 }
551 return rv;
552}
553
554static object *
555imageop_rgb82rgb(self, args)
556 object *self;
557 object *args;
558{
559 int x, y, len, nlen;
560 unsigned char *cp;
561 unsigned long *ncp;
562 object *rv;
563 int i, r, g, b;
564 unsigned long value, nvalue;
565
566 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
567 return 0;
568
569 nlen = x*y;
570 if ( nlen != len ) {
571 err_setstr(ImageopError, "String has incorrect length");
572 return 0;
573 }
574
575 rv = newsizedstringobject(NULL, nlen*4);
576 if ( rv == 0 )
577 return 0;
578 ncp = (unsigned long *)getstringvalue(rv);
579
580 for ( i=0; i < nlen; i++ ) {
581 /* Bits in source: RRRBBGGG
582 ** Red and Green are multiplied by 36.5, Blue by 85
583 */
584 value = *cp++;
585 r = (value >> 5) & 7;
586 g = (value ) & 7;
587 b = (value >> 3) & 3;
588 r = (r<<5) | (r<<3) | (r>>1);
589 g = (g<<5) | (g<<3) | (g>>1);
590 b = (b<<6) | (b<<4) | (b<<2) | b;
591 nvalue = r | (g<<8) | (b<<16);
592 *ncp++ = nvalue;
593 }
594 return rv;
595}
596
597static object *
598imageop_rgb2grey(self, args)
599 object *self;
600 object *args;
601{
602 int x, y, len, nlen;
603 unsigned long *cp;
604 unsigned char *ncp;
605 object *rv;
606 int i, r, g, b;
607 unsigned long value, nvalue;
608
609 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
610 return 0;
611
612 nlen = x*y;
613 if ( nlen*4 != len ) {
614 err_setstr(ImageopError, "String has incorrect length");
615 return 0;
616 }
617
618 rv = newsizedstringobject(NULL, nlen);
619 if ( rv == 0 )
620 return 0;
621 ncp = (unsigned char *)getstringvalue(rv);
622
623 for ( i=0; i < nlen; i++ ) {
624 value = *cp++;
625 r = (value ) & 0xff;
626 g = (value >> 8) & 0xff;
627 b = (value >> 16) & 0xff;
628 nvalue = (int)(0.30*r + 0.59*g + 0.11*b);
629 if ( nvalue > 255 ) nvalue = 255;
630 *ncp++ = nvalue;
631 }
632 return rv;
633}
634
635static object *
636imageop_grey2rgb(self, args)
637 object *self;
638 object *args;
639{
640 int x, y, len, nlen;
641 unsigned char *cp;
642 unsigned long *ncp;
643 object *rv;
644 int i;
645 unsigned long value;
646
647 if ( !getargs(args, "(s#ii)", &cp, &len, &x, &y) )
648 return 0;
649
650 nlen = x*y;
651 if ( nlen != len ) {
652 err_setstr(ImageopError, "String has incorrect length");
653 return 0;
654 }
655
656 rv = newsizedstringobject(NULL, nlen*4);
657 if ( rv == 0 )
658 return 0;
659 ncp = (unsigned long *)getstringvalue(rv);
660
661 for ( i=0; i < nlen; i++ ) {
662 value = *cp++;
663 *ncp++ = value | (value << 8 ) | (value << 16);
664 }
665 return rv;
666}
667
Guido van Rossum0317a471992-10-26 13:40:15 +0000668/*
669static object *
670imageop_mul(self, args)
671 object *self;
672 object *args;
673{
674 char *cp, *ncp;
675 int len, size, x, y;
676 object *rv;
677 int i;
678
679 if ( !getargs(args, "(s#iii)", &cp, &len, &size, &x, &y) )
680 return 0;
681
682 if ( size != 1 && size != 4 ) {
683 err_setstr(ImageopError, "Size should be 1 or 4");
684 return 0;
685 }
686 if ( len != size*x*y ) {
687 err_setstr(ImageopError, "String has incorrect length");
688 return 0;
689 }
690
691 rv = newsizedstringobject(NULL, XXXX);
692 if ( rv == 0 )
693 return 0;
694 ncp = (char *)getstringvalue(rv);
695
696
697 for ( i=0; i < len; i += size ) {
698 }
699 return rv;
700}
701*/
702
703static struct methodlist imageop_methods[] = {
704 { "crop", imageop_crop },
705 { "scale", imageop_scale },
Guido van Rossum5f59d601992-12-14 16:59:51 +0000706 { "grey2mono", imageop_grey2mono },
Jack Jansende3adf91992-12-22 14:05:55 +0000707 { "grey2grey2", imageop_grey2grey2 },
708 { "grey2grey4", imageop_grey2grey4 },
Guido van Rossum5f59d601992-12-14 16:59:51 +0000709 { "dither2mono", imageop_dither2mono },
Jack Jansende3adf91992-12-22 14:05:55 +0000710 { "dither2grey2", imageop_dither2grey2 },
Guido van Rossum5f59d601992-12-14 16:59:51 +0000711 { "mono2grey", imageop_mono2grey },
Jack Jansende3adf91992-12-22 14:05:55 +0000712 { "grey22grey", imageop_grey22grey },
713 { "grey42grey", imageop_grey42grey },
Jack Jansend26b4581993-01-22 15:34:43 +0000714 { "tovideo", imageop_tovideo },
Jack Jansen4fada9c1993-02-19 15:51:41 +0000715 { "rgb2rgb8", imageop_rgb2rgb8 },
716 { "rgb82rgb", imageop_rgb82rgb },
717 { "rgb2grey", imageop_rgb2grey },
718 { "grey2rgb", imageop_grey2rgb },
Guido van Rossum0317a471992-10-26 13:40:15 +0000719 { 0, 0 }
720};
721
722
723void
724initimageop()
725{
726 object *m, *d;
727 m = initmodule("imageop", imageop_methods);
728 d = getmoduledict(m);
729 ImageopError = newstringobject("imageop.error");
730 if ( ImageopError == NULL || dictinsert(d,"error",ImageopError) )
731 fatal("can't define imageop.error");
732}