source: trunk/third/xscreensaver/hacks/webcollage-helper.c @ 20148

Revision 20148, 9.3 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* webcollage-helper --- scales and pastes one image into another
2 * xscreensaver, Copyright (c) 2002, 2003 Jamie Zawinski <jwz@jwz.org>
3 *
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
10 * implied warranty.
11 */
12
13#ifdef HAVE_CONFIG_H
14# include "config.h"
15#endif
16
17#if defined(HAVE_GDK_PIXBUF) && defined(HAVE_JPEGLIB)  /* whole file */
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <time.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25
26#include <jpeglib.h>
27#include <gdk-pixbuf/gdk-pixbuf.h>
28
29
30char *progname;
31static int verbose_p = 0;
32
33static void add_jpeg_comment (struct jpeg_compress_struct *cinfo);
34static void write_pixbuf (GdkPixbuf *pb, const char *file);
35
36static GdkPixbuf *
37load_pixbuf (const char *file)
38{
39  GdkPixbuf *pb;
40#ifdef HAVE_GTK2
41  GError *err = NULL;
42
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 */
47
48  if (!pb)
49    {
50#ifdef HAVE_GTK2
51      fprintf (stderr, "%s: %s\n", progname, err->message);
52      g_error_free (err);
53#else  /* !HAVE_GTK2 */
54      fprintf (stderr, "%s: unable to load %s\n", progname, file);
55#endif /* !HAVE_GTK2 */
56      exit (1);
57    }
58
59  return pb;
60}
61
62static void
63paste (const char *paste_file,
64       const char *base_file,
65       double from_scale,
66       double opacity,
67       int from_x, int from_y, int to_x, int to_y,
68       int w, int h)
69{
70  GdkPixbuf *paste_pb;
71  GdkPixbuf *base_pb;
72
73  int paste_w, paste_h;
74  int base_w, base_h;
75
76  paste_pb = load_pixbuf (paste_file);
77  base_pb  = load_pixbuf (base_file);
78
79  paste_w = gdk_pixbuf_get_width (paste_pb);
80  paste_h = gdk_pixbuf_get_height (paste_pb);
81
82  base_w = gdk_pixbuf_get_width (base_pb);
83  base_h = gdk_pixbuf_get_height (base_pb);
84
85  if (verbose_p)
86    {
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);
91    }
92
93  if (from_scale != 1.0)
94    {
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,
98                                                   GDK_INTERP_HYPER);
99      gdk_pixbuf_unref (paste_pb);
100      paste_pb = new_pb;
101      paste_w = gdk_pixbuf_get_width (paste_pb);
102      paste_h = gdk_pixbuf_get_height (paste_pb);
103
104      if (verbose_p)
105        fprintf (stderr, "%s: %s: scaled to %dx%d (%.2f)\n",
106                 progname, paste_file, paste_w, paste_h, from_scale);
107    }
108
109  if (w == 0) w = paste_w - from_x;
110  if (h == 0) h = paste_h - from_y;
111
112  {
113    int ofx = from_x;
114    int ofy = from_y;
115    int otx = to_x;
116    int oty = to_y;
117    int ow = w;
118    int oh = h;
119
120    int clipped = 0;
121
122    if (from_x < 0)             /* from left out of bounds */
123      {
124        w += from_x;
125        from_x = 0;
126        clipped = 1;
127      }
128
129    if (from_y < 0)             /* from top out of bounds */
130      {
131        h += from_y;
132        from_y = 0;
133        clipped = 1;
134      }
135
136    if (to_x < 0)               /* to left out of bounds */
137      {
138        w += to_x;
139        from_x -= to_x;
140        to_x = 0;
141        clipped = 1;
142      }
143
144    if (to_y < 0)               /* to top out of bounds */
145      {
146        h += to_y;
147        from_y -= to_y;
148        to_y = 0;
149        clipped = 1;
150      }
151
152    if (from_x + w > paste_w)   /* from right out of bounds */
153      {
154        w = paste_w - from_x;
155        clipped = 1;
156      }
157
158    if (from_y + h > paste_h)   /* from bottom out of bounds */
159      {
160        h = paste_h - from_y;
161        clipped = 1;
162      }
163
164    if (to_x + w > base_w)      /* to right out of bounds */
165      {
166        w = base_w - to_x;
167        clipped = 1;
168      }
169
170    if (to_y + h > base_h)      /* to bottom out of bounds */
171      {
172        h = base_h - to_y;
173        clipped = 1;
174      }
175
176
177    if (clipped && verbose_p)
178      {
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);
183      }
184  }
185
186  if (opacity == 1.0)
187    gdk_pixbuf_copy_area (paste_pb,
188                          from_x, from_y, w, h,
189                          base_pb,
190                          to_x, to_y);
191  else
192    gdk_pixbuf_composite (paste_pb, base_pb,
193                          to_x, to_y, w, h,
194                          to_x - from_x, to_y - from_y,
195                          1.0, 1.0,
196                          GDK_INTERP_HYPER,
197                          opacity * 255);
198
199  if (verbose_p)
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);
202
203  gdk_pixbuf_unref (paste_pb);
204  write_pixbuf (base_pb, base_file);
205  gdk_pixbuf_unref (base_pb);
206}
207
208
209static void
210write_pixbuf (GdkPixbuf *pb, const char *file)
211{
212  int jpeg_quality = 85;
213
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);
219
220  struct jpeg_compress_struct cinfo;
221  struct jpeg_error_mgr jerr;
222  FILE *out;
223
224  if (channels != 3)
225    {
226      fprintf (stderr, "%s: %d channels?\n", progname, channels);
227      exit (1);
228    }
229
230  cinfo.err = jpeg_std_error (&jerr);
231  jpeg_create_compress (&cinfo);
232
233  out = fopen (file, "wb");
234  if (!out)
235    {
236      char buf[255];
237      sprintf (buf, "%.100s: %.100s", progname, file);
238      perror (buf);
239      exit (1);
240    }
241  else if (verbose_p)
242    fprintf (stderr, "%s: writing %s...", progname, file);
243
244  jpeg_stdio_dest (&cinfo, out);
245
246  cinfo.image_width = w;
247  cinfo.image_height = h;
248  cinfo.input_components = channels;
249  cinfo.in_color_space = JCS_RGB;
250
251  jpeg_set_defaults (&cinfo);
252  jpeg_simple_progression (&cinfo);
253  jpeg_set_quality (&cinfo, jpeg_quality, TRUE);
254
255  jpeg_start_compress (&cinfo, TRUE);
256  add_jpeg_comment (&cinfo);
257
258  {
259    guchar *d = data;
260    guchar *end = d + (ww * h);
261    while (d < end)
262      {
263        jpeg_write_scanlines (&cinfo, &d, 1);
264        d += ww;
265      }
266  }
267
268  jpeg_finish_compress (&cinfo);
269  jpeg_destroy_compress (&cinfo);
270
271  if (verbose_p)
272    {
273      struct stat st;
274      fflush (out);
275      if (fstat (fileno (out), &st))
276        {
277          char buf[255];
278          sprintf (buf, "%.100s: %.100s", progname, file);
279          perror (buf);
280          exit (1);
281        }
282      fprintf (stderr, " %luK\n", (st.st_size + 1023) / 1024);
283    }
284
285  fclose (out);
286}
287
288
289static void
290add_jpeg_comment (struct jpeg_compress_struct *cinfo)
291{
292  time_t now = time ((time_t *) 0);
293  struct tm *tm = localtime (&now);
294  const char fmt[] =
295    "\r\n"
296    "    Generated by WebCollage: Exterminate All Rational Thought. \r\n"
297    "    Copyright (c) 1999-%Y by Jamie Zawinski <jwz@jwz.org> \r\n"
298    "\r\n"
299    "        http://www.jwz.org/webcollage/ \r\n"
300    "\r\n"
301    "    This is what the web looked like on %d %b %Y at %I:%M:%S %p %Z. \r\n"
302    "\r\n";
303  char comment[sizeof(fmt) + 100];
304  strftime (comment, sizeof(comment)-1, fmt, tm);
305  jpeg_write_marker (cinfo, JPEG_COM,
306                     (unsigned char *) comment,
307                     strlen (comment));
308}
309
310
311static void
312usage (void)
313{
314  fprintf (stderr, "usage: %s [-v] paste-file base-file\n"
315           "\t from-scale opacity\n"
316           "\t from-x from-y to-x to-y w h\n"
317           "\n"
318           "\t Pastes paste-file into base-file.\n"
319           "\t base-file will be overwritten (with JPEG data.)\n"
320           "\t scaling is applied first: coordinates apply to scaled image.\n",
321           progname);
322  exit (1);
323}
324
325
326int
327main (int argc, char **argv)
328{
329  int i;
330  char *paste_file, *base_file, *s, dummy;
331  double from_scale, opacity;
332  int from_x, from_y, to_x, to_y, w, h;
333
334  i = 0;
335  progname = argv[i++];
336  s = strrchr (progname, '/');
337  if (s) progname = s+1;
338
339  if (argc != 11 && argc != 12) usage();
340
341  if (!strcmp(argv[i], "-v"))
342    verbose_p++, i++;
343
344  paste_file = argv[i++];
345  base_file = argv[i++];
346
347  if (*paste_file == '-') usage();
348  if (*base_file == '-') usage();
349
350  s = argv[i++];
351  if (1 != sscanf (s, " %lf %c", &from_scale, &dummy)) usage();
352  if (from_scale <= 0 || from_scale > 100) usage();
353
354  s = argv[i++];
355  if (1 != sscanf (s, " %lf %c", &opacity, &dummy)) usage();
356  if (opacity <= 0 || opacity > 1) usage();
357
358  s = argv[i++]; if (1 != sscanf (s, " %d %c", &from_x, &dummy)) usage();
359  s = argv[i++]; if (1 != sscanf (s, " %d %c", &from_y, &dummy)) usage();
360  s = argv[i++]; if (1 != sscanf (s, " %d %c", &to_x, &dummy)) usage();
361  s = argv[i++]; if (1 != sscanf (s, " %d %c", &to_y, &dummy)) usage();
362  s = argv[i++]; if (1 != sscanf (s, " %d %c", &w, &dummy)) usage();
363  s = argv[i++]; if (1 != sscanf (s, " %d %c", &h, &dummy)) usage();
364
365  if (w < 0) usage();
366  if (h < 0) usage();
367
368#ifdef HAVE_GTK2
369  g_type_init ();
370#endif /* HAVE_GTK2 */
371
372  paste (paste_file, base_file,
373         from_scale, opacity,
374         from_x, from_y, to_x, to_y,
375         w, h);
376  exit (0);
377}
378
379#endif /* HAVE_GDK_PIXBUF && HAVE_JPEGLIB -- whole file */
Note: See TracBrowser for help on using the repository browser.