1 /* webcollage-helper --- scales and pastes one image into another
2 * xscreensaver, Copyright (c) 2002 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
17 #if defined(HAVE_GDK_PIXBUF) && defined(HAVE_JPEGLIB) /* whole file */
23 #include <sys/types.h>
27 #include <gdk-pixbuf/gdk-pixbuf.h>
31 static int verbose_p = 0;
33 static void add_jpeg_comment (struct jpeg_compress_struct *cinfo);
34 static void write_pixbuf (GdkPixbuf *pb, const char *file);
37 load_pixbuf (const char *file)
43 pb = gdk_pixbuf_new_from_file (file, &err);
44 #else /* !HAVE_GTK2 */
45 pb = gdk_pixbuf_new_from_file (file);
46 #endif /* HAVE_GTK2 */
51 fprintf (stderr, "%s: %s\n", progname, err->message);
53 #else /* !HAVE_GTK2 */
54 fprintf (stderr, "%s: unable to load %s\n", progname, file);
55 #endif /* !HAVE_GTK2 */
63 paste (const char *paste_file,
64 const char *base_file,
67 int from_x, int from_y, int to_x, int to_y,
76 paste_pb = load_pixbuf (paste_file);
77 base_pb = load_pixbuf (base_file);
79 paste_w = gdk_pixbuf_get_width (paste_pb);
80 paste_h = gdk_pixbuf_get_height (paste_pb);
82 base_w = gdk_pixbuf_get_width (base_pb);
83 base_h = gdk_pixbuf_get_height (base_pb);
87 fprintf (stderr, "%s: loaded %s: %dx%d\n",
88 progname, base_file, base_w, base_h);
89 fprintf (stderr, "%s: loaded %s: %dx%d\n",
90 progname, paste_file, paste_w, paste_h);
93 if (from_scale != 1.0)
95 int new_w = paste_w * from_scale;
96 int new_h = paste_h * from_scale;
97 GdkPixbuf *new_pb = gdk_pixbuf_scale_simple (paste_pb, new_w, new_h,
99 gdk_pixbuf_unref (paste_pb);
101 paste_w = gdk_pixbuf_get_width (paste_pb);
102 paste_h = gdk_pixbuf_get_height (paste_pb);
105 fprintf (stderr, "%s: %s: scaled to %dx%d (%.2f)\n",
106 progname, paste_file, paste_w, paste_h, from_scale);
109 if (w == 0) w = paste_w - from_x;
110 if (h == 0) h = paste_h - from_y;
122 if (from_x < 0) /* from left out of bounds */
129 if (from_y < 0) /* from top out of bounds */
136 if (to_x < 0) /* to left out of bounds */
144 if (to_y < 0) /* to top out of bounds */
152 if (from_x + w > paste_w) /* from right out of bounds */
154 w = paste_w - from_x;
158 if (from_y + h > paste_h) /* from bottom out of bounds */
160 h = paste_h - from_y;
164 if (to_x + w > base_w) /* to right out of bounds */
170 if (to_y + h > base_h) /* to bottom out of bounds */
177 if (clipped && verbose_p)
179 fprintf (stderr, "clipped from: %dx%d %d,%d %d,%d\n",
180 ow, oh, ofx, ofy, otx, oty);
181 fprintf (stderr, "clipped to: %dx%d %d,%d %d,%d\n",
182 w, h, from_x, from_y, to_x, to_y);
187 gdk_pixbuf_copy_area (paste_pb,
188 from_x, from_y, w, h,
192 gdk_pixbuf_composite (paste_pb, base_pb,
194 to_x - from_x, to_y - from_y,
200 fprintf (stderr, "%s: pasted %dx%d from %d,%d to %d,%d\n",
201 progname, paste_w, paste_h, from_x, from_y, to_x, to_y);
203 gdk_pixbuf_unref (paste_pb);
204 write_pixbuf (base_pb, base_file);
205 gdk_pixbuf_unref (base_pb);
210 write_pixbuf (GdkPixbuf *pb, const char *file)
212 int jpeg_quality = 85;
214 int w = gdk_pixbuf_get_width (pb);
215 int h = gdk_pixbuf_get_height (pb);
216 guchar *data = gdk_pixbuf_get_pixels (pb);
217 int ww = gdk_pixbuf_get_rowstride (pb);
218 int channels = gdk_pixbuf_get_n_channels (pb);
220 struct jpeg_compress_struct cinfo;
221 struct jpeg_error_mgr jerr;
226 fprintf (stderr, "%s: %d channels?\n", progname, channels);
230 cinfo.err = jpeg_std_error (&jerr);
231 jpeg_create_compress (&cinfo);
233 out = fopen (file, "wb");
237 sprintf (buf, "%.100s: %.100s", progname, file);
242 fprintf (stderr, "%s: writing %s...", progname, file);
244 jpeg_stdio_dest (&cinfo, out);
246 cinfo.image_width = w;
247 cinfo.image_height = h;
248 cinfo.input_components = channels;
249 cinfo.in_color_space = JCS_RGB;
251 jpeg_set_defaults (&cinfo);
252 jpeg_simple_progression (&cinfo);
253 jpeg_set_quality (&cinfo, jpeg_quality, TRUE);
255 jpeg_start_compress (&cinfo, TRUE);
256 add_jpeg_comment (&cinfo);
260 guchar *end = d + (ww * h);
263 jpeg_write_scanlines (&cinfo, &d, 1);
268 jpeg_finish_compress (&cinfo);
269 jpeg_destroy_compress (&cinfo);
275 if (fstat (fileno (out), &st))
278 sprintf (buf, "%.100s: %.100s", progname, file);
282 fprintf (stderr, " %ldK\n", (st.st_size + 1023) / 1024);
290 add_jpeg_comment (struct jpeg_compress_struct *cinfo)
292 time_t now = time ((time_t *) 0);
293 struct tm *tm = localtime (&now);
296 " Generated by WebCollage: Exterminate All Rational Thought. \r\n"
297 " Copyright (c) 1999-%Y by Jamie Zawinski <jwz@jwz.org> \r\n"
299 " http://www.jwz.org/webcollage/ \r\n"
301 " This is what the web looked like on %d %b %Y at %I:%M:%S %p %Z. \r\n"
303 char comment[sizeof(fmt) + 100];
304 strftime (comment, sizeof(comment)-1, fmt, tm);
305 jpeg_write_marker (cinfo, JPEG_COM, comment, strlen (comment));
312 fprintf (stderr, "usage: %s [-v] paste-file base-file\n"
313 "\t from-scale opacity\n"
314 "\t from-x from-y to-x to-y w h\n"
316 "\t Pastes paste-file into base-file.\n"
317 "\t base-file will be overwritten (with JPEG data.)\n"
318 "\t scaling is applied first: coordinates apply to scaled image.\n",
325 main (int argc, char **argv)
328 char *paste_file, *base_file, *s, dummy;
329 double from_scale, opacity;
330 int from_x, from_y, to_x, to_y, w, h;
333 progname = argv[i++];
334 s = strrchr (progname, '/');
335 if (s) progname = s+1;
337 if (argc != 11 && argc != 12) usage();
339 if (!strcmp(argv[i], "-v"))
342 paste_file = argv[i++];
343 base_file = argv[i++];
345 if (*paste_file == '-') usage();
346 if (*base_file == '-') usage();
349 if (1 != sscanf (s, " %lf %c", &from_scale, &dummy)) usage();
350 if (from_scale <= 0 || from_scale > 100) usage();
353 if (1 != sscanf (s, " %lf %c", &opacity, &dummy)) usage();
354 if (opacity <= 0 || opacity > 1) usage();
356 s = argv[i++]; if (1 != sscanf (s, " %d %c", &from_x, &dummy)) usage();
357 s = argv[i++]; if (1 != sscanf (s, " %d %c", &from_y, &dummy)) usage();
358 s = argv[i++]; if (1 != sscanf (s, " %d %c", &to_x, &dummy)) usage();
359 s = argv[i++]; if (1 != sscanf (s, " %d %c", &to_y, &dummy)) usage();
360 s = argv[i++]; if (1 != sscanf (s, " %d %c", &w, &dummy)) usage();
361 s = argv[i++]; if (1 != sscanf (s, " %d %c", &h, &dummy)) usage();
368 #endif /* HAVE_GTK2 */
370 paste (paste_file, base_file,
372 from_x, from_y, to_x, to_y,
377 #endif /* HAVE_GDK_PIXBUF && HAVE_JPEGLIB -- whole file */