ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/CV/CV.xs
Revision: 1.28
Committed: Mon Aug 22 00:30:58 2005 UTC (18 years, 9 months ago) by root
Branch: MAIN
Changes since 1.27: +6 -101 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.18 #include <string.h>
6 root 1.17 #include <setjmp.h>
7    
8     #include <jpeglib.h>
9 root 1.23 #include <glib.h>
10     #include <gtk/gtk.h>
11 root 1.2 #include <gdk-pixbuf/gdk-pixbuf.h>
12    
13     #include <gperl.h>
14     #include <gtk2perl.h>
15    
16 root 1.17 #define IW 80 /* MUST match Schnauer.pm! */
17     #define IH 60 /* MUST match Schnauer.pm! */
18 root 1.5
19     #define RAND (seed = (seed + 7141) * 54773 % 134456)
20    
21 root 1.7 #define LINELENGTH 240
22    
23 root 1.6 #define ELLIPSIS "\xe2\x80\xa6"
24    
25 root 1.17 struct jpg_err_mgr
26     {
27     struct jpeg_error_mgr err;
28     jmp_buf setjmp_buffer;
29     };
30    
31     static void
32     cv_error_exit (j_common_ptr cinfo)
33     {
34     longjmp (((struct jpg_err_mgr *)cinfo->err)->setjmp_buffer, 99);
35     }
36    
37     static void
38     cv_error_output (j_common_ptr cinfo)
39     {
40     return;
41     }
42    
43     static void
44     rgb_to_hsv (unsigned int r, unsigned int g, unsigned int b,
45     unsigned int *h, unsigned int *s, unsigned int *v)
46     {
47     unsigned int mx = r; if (g > mx) mx = g; if (b > mx) mx = b;
48     unsigned int mn = r; if (g < mn) mn = g; if (b < mn) mn = b;
49     unsigned int delta = mx - mn;
50    
51     *v = mx;
52    
53     *s = mx ? delta * 255 / mx : 0;
54    
55     if (delta == 0)
56     *h = 0;
57     else
58     {
59     if (r == mx)
60     *h = ((int)g - (int)b) * 255 / (int)(delta * 3);
61     else if (g == mx)
62     *h = ((int)b - (int)r) * 255 / (int)(delta * 3) + 52;
63     else if (b == mx)
64     *h = ((int)r - (int)g) * 255 / (int)(delta * 3) + 103;
65    
66     *h &= 255;
67     }
68     }
69    
70 root 1.4 static guint32 a85_val;
71     static guint a85_cnt;
72 root 1.7 static guchar a85_buf[LINELENGTH], *a85_ptr;
73 root 1.4
74     static void
75     a85_init (void)
76     {
77     a85_cnt = 4;
78     a85_ptr = a85_buf;
79     }
80    
81     static void
82     a85_push (PerlIO *fp, guchar c)
83     {
84     a85_val = a85_val << 8 | c;
85    
86     if (!--a85_cnt)
87     {
88     a85_cnt = 4;
89     if (a85_val)
90     {
91     a85_ptr[4] = (a85_val % 85) + 33; a85_val /= 85;
92     a85_ptr[3] = (a85_val % 85) + 33; a85_val /= 85;
93     a85_ptr[2] = (a85_val % 85) + 33; a85_val /= 85;
94     a85_ptr[1] = (a85_val % 85) + 33; a85_val /= 85;
95     a85_ptr[0] = (a85_val ) + 33;
96    
97     a85_ptr += 5;
98     }
99     else
100     *a85_ptr++ = 'z';
101    
102     if (a85_ptr >= a85_buf + sizeof (a85_buf) - 7)
103     {
104     *a85_ptr++ = '\n';
105     PerlIO_write (fp, a85_buf, a85_ptr - a85_buf);
106     a85_ptr = a85_buf;
107     }
108     }
109    
110     }
111    
112 root 1.8 static void
113 root 1.4 a85_finish (PerlIO *fp)
114     {
115     while (a85_cnt != 4)
116     a85_push (fp, 0);
117    
118     *a85_ptr++ = '~'; // probably buggy end-marker
119     *a85_ptr++ = '>'; // probably buggy end-marker
120     *a85_ptr++ = '\n';
121    
122     PerlIO_write (fp, a85_buf, a85_ptr - a85_buf);
123     }
124    
125 root 1.6 /////////////////////////////////////////////////////////////////////////////
126    
127 root 1.9 MODULE = Gtk2::CV PACKAGE = Gtk2::CV
128 root 1.1
129     PROTOTYPES: ENABLE
130 root 1.2
131 root 1.22 # missing in Gtk2 perl module
132    
133     gboolean
134     gdk_net_wm_supports (GdkAtom property)
135     CODE:
136     #if defined(GDK_WINDOWING_X11) && !defined(GDK_MULTIHEAD_SAFE)
137     RETVAL = gdk_net_wm_supports (property);
138     #else
139     RETVAL = 0;
140     #endif
141     OUTPUT:
142     RETVAL
143    
144 root 1.3 GdkPixbuf_noinc *
145 root 1.26 dealpha_expose (GdkPixbuf *pb)
146     CODE:
147     {
148     int w = gdk_pixbuf_get_width (pb);
149     int h = gdk_pixbuf_get_height (pb);
150     int bpp = gdk_pixbuf_get_n_channels (pb);
151     int x, y, i;
152     guchar *src = gdk_pixbuf_get_pixels (pb), *dst;
153     int sstr = gdk_pixbuf_get_rowstride (pb), dstr;
154    
155     RETVAL = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, w, h);
156    
157     dst = gdk_pixbuf_get_pixels (RETVAL);
158     dstr = gdk_pixbuf_get_rowstride (RETVAL);
159    
160     for (x = 0; x < w; x++)
161     for (y = 0; y < h; y++)
162     for (i = 0; i < 3; i++)
163     dst[x * 3 + y * dstr + i] = src[x * bpp + y * sstr + i];
164     }
165     OUTPUT:
166     RETVAL
167    
168     GdkPixbuf_noinc *
169 root 1.28 rotate (GdkPixbuf *pb, int angle)
170 root 1.2 CODE:
171 root 1.28 RETVAL = gdk_pixbuf_rotate_simple (pb, angle == 0 ? GDK_PIXBUF_ROTATE_NONE
172     : angle == 90 ? GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
173     : angle == 180 ? GDK_PIXBUF_ROTATE_UPSIDEDOWN
174     : angle == 270 ? GDK_PIXBUF_ROTATE_CLOCKWISE
175     : angle);
176 root 1.2 OUTPUT:
177     RETVAL
178    
179 root 1.17 GdkPixbuf_noinc *
180 root 1.23 load_jpeg (SV *path, int thumbnail=0)
181 root 1.17 CODE:
182     {
183     struct jpeg_decompress_struct cinfo;
184     struct jpg_err_mgr jerr;
185     guchar *data;
186     int rs;
187     FILE *fp;
188     volatile GdkPixbuf *pb = 0;
189 root 1.23 gchar *filename;
190    
191 root 1.17 RETVAL = 0;
192    
193 root 1.23 filename = g_filename_from_utf8 (SvPVutf8_nolen (path), -1, 0, 0, 0);
194     fp = fopen (filename, "rb");
195     g_free (filename);
196    
197     if (!fp)
198 root 1.17 XSRETURN_UNDEF;
199    
200     cinfo.err = jpeg_std_error (&jerr.err);
201    
202     jerr.err.error_exit = cv_error_exit;
203     jerr.err.output_message = cv_error_output;
204    
205     if ((rs = setjmp (jerr.setjmp_buffer)))
206     {
207     fclose (fp);
208     jpeg_destroy_decompress (&cinfo);
209    
210     if (pb)
211     g_object_unref ((gpointer)pb);
212    
213     XSRETURN_UNDEF;
214     }
215    
216     jpeg_create_decompress (&cinfo);
217    
218     jpeg_stdio_src (&cinfo, fp);
219     jpeg_read_header (&cinfo, TRUE);
220    
221     cinfo.dct_method = JDCT_DEFAULT;
222     cinfo.do_fancy_upsampling = FALSE; /* worse quality, but nobody compained so far, and gdk-pixbuf does the same */
223     cinfo.do_block_smoothing = FALSE;
224     cinfo.out_color_space = JCS_RGB;
225     cinfo.quantize_colors = FALSE;
226    
227     cinfo.scale_num = 1;
228     cinfo.scale_denom = 1;
229    
230     jpeg_calc_output_dimensions (&cinfo);
231    
232     if (thumbnail)
233     {
234     cinfo.dct_method = JDCT_FASTEST;
235     cinfo.do_fancy_upsampling = FALSE;
236    
237     while (cinfo.scale_denom < 8
238 root 1.21 && cinfo.output_width >= IW*4
239     && cinfo.output_height >= IH*4)
240 root 1.17 {
241     cinfo.scale_denom <<= 1;
242     jpeg_calc_output_dimensions (&cinfo);
243     }
244     }
245    
246     pb = RETVAL = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, cinfo.output_width, cinfo.output_height);
247     if (!RETVAL)
248     longjmp (jerr.setjmp_buffer, 2);
249    
250     data = gdk_pixbuf_get_pixels (RETVAL);
251     rs = gdk_pixbuf_get_rowstride (RETVAL);
252    
253     if (cinfo.output_components != 3)
254     longjmp (jerr.setjmp_buffer, 3);
255    
256     jpeg_start_decompress (&cinfo);
257    
258     while (cinfo.output_scanline < cinfo.output_height)
259     {
260     int remaining = cinfo.output_height - cinfo.output_scanline;
261     JSAMPROW rp[4];
262    
263     rp [0] = data + cinfo.output_scanline * rs;
264     rp [1] = (guchar *)rp [0] + rs;
265     rp [2] = (guchar *)rp [1] + rs;
266     rp [3] = (guchar *)rp [2] + rs;
267    
268     jpeg_read_scanlines (&cinfo, rp, remaining < 4 ? remaining : 4);
269     }
270    
271     jpeg_finish_decompress (&cinfo);
272     fclose (fp);
273     jpeg_destroy_decompress (&cinfo);
274     }
275     OUTPUT:
276     RETVAL
277    
278 root 1.6 #############################################################################
279    
280 root 1.2 MODULE = Gtk2::CV PACKAGE = Gtk2::CV::Schnauzer
281    
282 root 1.18 SV *
283     foldcase (SV *pathsv)
284     PROTOTYPE: $
285     CODE:
286     {
287     STRLEN plen;
288 root 1.25 U8 *path = (U8 *)SvPVutf8 (pathsv, plen);
289 root 1.18 U8 *pend = path + plen;
290     U8 dst [plen * 6 * 3], *dstp = dst;
291    
292     while (path < pend)
293     {
294 root 1.19 U8 ch = *path;
295    
296     if (ch >= 'a' && ch <= 'z')
297     *dstp++ = *path++;
298     else if (ch >= '0' && ch <= '9')
299 root 1.18 {
300     STRLEN el, nl = 0;
301 root 1.19 while (*path >= '0' && *path <= '9' && path < pend)
302 root 1.18 path++, nl++;
303    
304     for (el = nl; el < 6; el++)
305     *dstp++ = '0';
306    
307     memcpy (dstp, path - nl, nl);
308     dstp += nl;
309     }
310     else
311     {
312     STRLEN cl;
313     to_utf8_fold (path, dstp, &cl);
314     dstp += cl;
315     path += is_utf8_char (path);
316     }
317     }
318    
319 root 1.25 RETVAL = newSVpvn ((const char *)dst, dstp - dst);
320 root 1.18 }
321     OUTPUT:
322     RETVAL
323    
324 root 1.3 GdkPixbuf_noinc *
325 root 1.24 p7_to_pb (int w, int h, SV *src_sv)
326 root 1.21 PROTOTYPE: @
327 root 1.2 CODE:
328     {
329     int x, y;
330     guchar *dst, *d;
331     int dstr;
332 root 1.25 guchar *src = (guchar *)SvPVbyte_nolen (src_sv);
333 root 1.2
334     RETVAL = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, w, h);
335     dst = gdk_pixbuf_get_pixels (RETVAL);
336     dstr = gdk_pixbuf_get_rowstride (RETVAL);
337    
338     for (y = 0; y < h; y++)
339     for (d = dst + y * dstr, x = 0; x < w; x++)
340     {
341 root 1.3 *d++ = (((*src >> 5) & 7) * 255 + 4) / 7;
342     *d++ = (((*src >> 2) & 7) * 255 + 4) / 7;
343     *d++ = (((*src >> 0) & 3) * 255 + 2) / 3;
344 root 1.2
345     src++;
346     }
347 root 1.3 }
348     OUTPUT:
349     RETVAL
350    
351 root 1.6 #############################################################################
352 root 1.4
353     MODULE = Gtk2::CV PACKAGE = Gtk2::CV::PostScript
354    
355     void
356 root 1.7 dump_ascii85 (PerlIO *fp, GdkPixbuf *pb)
357 root 1.4 CODE:
358     {
359     int w = gdk_pixbuf_get_width (pb);
360     int h = gdk_pixbuf_get_height (pb);
361     int x, y, i;
362     guchar *dst;
363 root 1.7 int bpp = gdk_pixbuf_get_n_channels (pb);
364 root 1.4 guchar *src = gdk_pixbuf_get_pixels (pb);
365     int sstr = gdk_pixbuf_get_rowstride (pb);
366    
367     a85_init ();
368    
369     for (y = 0; y < h; y++)
370     for (x = 0; x < w; x++)
371 root 1.7 for (i = 0; i < (bpp < 3 ? 1 : 3); i++)
372 root 1.4 a85_push (fp, src [x * bpp + y * sstr + i]);
373    
374     a85_finish (fp);
375 root 1.7 }
376    
377     void
378     dump_binary (PerlIO *fp, GdkPixbuf *pb)
379     CODE:
380     {
381     int w = gdk_pixbuf_get_width (pb);
382     int h = gdk_pixbuf_get_height (pb);
383     int x, y, i;
384     guchar *dst;
385     int bpp = gdk_pixbuf_get_n_channels (pb);
386     guchar *src = gdk_pixbuf_get_pixels (pb);
387     int sstr = gdk_pixbuf_get_rowstride (pb);
388    
389     for (y = 0; y < h; y++)
390     for (x = 0; x < w; x++)
391     for (i = 0; i < (bpp < 3 ? 1 : 3); i++)
392     PerlIO_putc (fp, src [x * bpp + y * sstr + i]);
393 root 1.4 }
394 root 1.8
395     #############################################################################
396    
397     MODULE = Gtk2::CV PACKAGE = Gtk2::CV
398    
399     SV *
400     pb_to_hv84 (GdkPixbuf *pb)
401     CODE:
402     {
403     int w = gdk_pixbuf_get_width (pb);
404     int h = gdk_pixbuf_get_height (pb);
405     int x, y;
406     guchar *dst;
407     int bpp = gdk_pixbuf_get_n_channels (pb);
408     guchar *src = gdk_pixbuf_get_pixels (pb);
409     int sstr = gdk_pixbuf_get_rowstride (pb);
410    
411     RETVAL = newSV (6 * 8 * 12 / 8);
412     SvPOK_only (RETVAL);
413     SvCUR_set (RETVAL, 6 * 8 * 12 / 8);
414    
415 root 1.25 dst = (guchar *)SvPVX (RETVAL);
416 root 1.8
417     /* some primitive error distribution + random dithering */
418    
419     for (y = 0; y < h; y++)
420     {
421     guchar *p = src + y * sstr;
422    
423     for (x = 0; x < w; x += 2)
424     {
425     unsigned int r, g, b, h, s, v, H, V1, V2;
426    
427     if (bpp == 3)
428     r = *p++, g = *p++, b = *p++;
429     else if (bpp == 1)
430     r = g = b = *p++;
431     else
432     abort ();
433    
434     rgb_to_hsv (r, g, b, &h, &s, &v);
435    
436     H = (h * 15 / 255) << 4;
437     V1 = v;
438    
439     if (bpp == 3)
440     r = *p++, g = *p++, b = *p++;
441     else if (bpp == 1)
442     r = g = b = *p++;
443     else
444     abort ();
445    
446     rgb_to_hsv (r, g, b, &h, &s, &v);
447    
448     H |= h * 15 / 255;
449     V2 = v;
450    
451     *dst++ = H;
452     *dst++ = V1;
453     *dst++ = V2;
454     }
455     }
456     }
457     OUTPUT:
458     RETVAL
459 root 1.4
460 root 1.9 SV *
461     hv84_to_av (unsigned char *hv84)
462     CODE:
463     {
464     int i = 72 / 3;
465     AV *av = newAV ();
466    
467     RETVAL = (SV *)newRV_noinc ((SV *)av);
468     while (i--)
469     {
470     int h = *hv84++;
471     int v1 = *hv84++;
472     int v2 = *hv84++;
473    
474     av_push (av, newSViv (v1));
475     av_push (av, newSViv ((h >> 4) * 255 / 15));
476     av_push (av, newSViv (v2));
477     av_push (av, newSViv ((h & 15) * 255 / 15));
478     }
479     }
480     OUTPUT:
481     RETVAL
482 root 1.2
483 root 1.20 #############################################################################
484    
485     MODULE = Gtk2::CV PACKAGE = Gtk2::CV::Plugin::RCluster
486    
487     SV *
488     make_histograms (SV *ar)
489     CODE:
490     {
491     int i;
492     AV *av, *result;
493    
494     if (!SvROK (ar) || SvTYPE (SvRV (ar)) != SVt_PVAV)
495     croak ("Not an array ref as first argument to make_histogram");
496    
497     av = (AV *) SvRV (ar);
498     result = newAV ();
499    
500     for (i = 0; i <= av_len (av); ++i)
501     {
502     const int HISTSIZE = 64;
503    
504     int j;
505     SV *sv = *av_fetch (av, i, 1);
506     STRLEN len;
507     char *buf = SvPVbyte (sv, len);
508    
509     int tmphist[HISTSIZE];
510     float *hist;
511    
512     SV *histsv = newSV (HISTSIZE * sizeof (float) + 1);
513     SvPOK_on (histsv);
514     SvCUR_set (histsv, HISTSIZE * sizeof (float));
515     hist = (float *)SvPVX (histsv);
516    
517     Zero (tmphist, sizeof (tmphist), char);
518    
519     for (j = len; j--; )
520     {
521     unsigned int idx
522     = ((*buf & 0xc0) >> 2)
523     | ((*buf & 0x18) >> 1)
524     | (*buf & 0x03);
525    
526     ++tmphist[idx];
527     ++buf;
528     }
529    
530     for (j = 0; j < HISTSIZE; ++j)
531     hist[j] = (float)tmphist[j] / (len + 1e-30);
532    
533     av_push (result, histsv);
534     }
535    
536     RETVAL = newRV_noinc ((SV *)result);
537     }
538     OUTPUT:
539     RETVAL
540 root 1.1
541