~ubuntu-branches/debian/jessie/f-spot/jessie

« back to all changes in this revision

Viewing changes to src/PixbufUtils.cs

  • Committer: Bazaar Package Importer
  • Author(s): Iain Lane
  • Date: 2010-08-11 22:17:42 UTC
  • mfrom: (2.4.9 experimental)
  • Revision ID: james.westby@ubuntu.com-20100811221742-2qv3a5uya7gfe1t1
* New upstream release 0.7.2 "Retooled"
  + Third release of the unstable 0.7 development series. Features a
    fully restructured source tree with full Monodevelop build
    support. Solves some of the regressions introduced in 0.7.1.
  + Reorganized source tree for clarity, builds with Monodevelop.
  + Switched from QueuedSqliteDatabase to HyenaSqliteConnection (Mike
    Gemünde)
  + Build tweaks (Christian Krause)
  + More GtkBuilder transition (Eric Faehnrich) 
  + Reliability improvements (lots of them) for metadata handling (Mike
    Gemünde, Ruben Vermeersch)
  + Prune empty directories when deleting photos, import usability
    enhancements (Mike Wallick)
  + Big race-condition fix in import (Paul Wellner Bou)
  + Loads of improvements to Taglib#, in terms of handling broken files,
    extra format support (Pentax, Panasonic, Leica), stability and
    correctness (Ruben Vermeersch)
    - Runs out of memory Importing photo with suspect EXIF data
      (LP: #272822)
    - Metadata parsing of broken file causes large memory allocation
      (LP: #597720)
    - Photo import: cancel & copy have same keyboard shortcut (LP: #244423)
    - Facebook export will not create new album (LP: #563495)
    - Allow export to iPod (LP: #518344)
  + Reporting of import errors.
  + Speedups to repeated imports of the same directory.
  + Piles of cleanups and general stability improvements.
  + Over 50 bugs closed (http://bit.ly/cqpC3y)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// FSpot.PixbufUtils.cs
3
 
//
4
 
// Author(s):
5
 
//      Ettore Perazzoli
6
 
//      Larry Ewing  <lewing@novell.com>
7
 
//      Stephane Delcroix  <stephane@declroix.org>
8
 
//
9
 
// This is free software. See COPYING for details
10
 
//
11
 
 
12
 
using Gdk;
13
 
using System.Collections;
14
 
using System.Runtime.InteropServices;
15
 
using System;
16
 
using System.IO;
17
 
using FSpot;
18
 
using FSpot.Utils;
19
 
using FSpot.Imaging;
20
 
using Hyena;
21
 
using TagLib.Image;
22
 
 
23
 
public static class PixbufUtils {
24
 
        static Pixbuf error_pixbuf = null;
25
 
        public static Pixbuf ErrorPixbuf {
26
 
                get {
27
 
                        if (error_pixbuf == null)
28
 
                                error_pixbuf = GtkUtil.TryLoadIcon (FSpot.Global.IconTheme, "f-spot-question-mark", 256, (Gtk.IconLookupFlags)0);
29
 
                        return error_pixbuf;
30
 
                }
31
 
        }
32
 
        public static Pixbuf LoadingPixbuf = PixbufUtils.LoadFromAssembly ("f-spot-loading.png");
33
 
 
34
 
        public static int GetSize (Pixbuf pixbuf)
35
 
        {
36
 
                return Math.Max (pixbuf.Width, pixbuf.Height);
37
 
        }
38
 
 
39
 
        public static double Fit (Pixbuf pixbuf,
40
 
                                  int dest_width, int dest_height,
41
 
                                  bool upscale_smaller,
42
 
                                  out int fit_width, out int fit_height)
43
 
        {
44
 
                return Fit (pixbuf.Width, pixbuf.Height, 
45
 
                            dest_width, dest_height, 
46
 
                            upscale_smaller, 
47
 
                            out fit_width, out fit_height);
48
 
        }
49
 
 
50
 
        public static double Fit (int orig_width, int orig_height,
51
 
                                  int dest_width, int dest_height,
52
 
                                  bool upscale_smaller,
53
 
                                  out int fit_width, out int fit_height)
54
 
        {
55
 
                if (orig_width == 0 || orig_height == 0) {
56
 
                        fit_width = 0;
57
 
                        fit_height = 0;
58
 
                        return 0.0;
59
 
                }
60
 
 
61
 
                double scale = Math.Min (dest_width / (double)orig_width,
62
 
                                         dest_height / (double)orig_height);
63
 
                
64
 
                if (scale > 1.0 && !upscale_smaller)
65
 
                        scale = 1.0;
66
 
 
67
 
                fit_width = (int) Math.Round (scale * orig_width);
68
 
                fit_height = (int) Math.Round (scale * orig_height);
69
 
                
70
 
                return scale;
71
 
        }
72
 
 
73
 
 
74
 
        // FIXME: These should be in GTK#.  When my patch is committed, these LoadFrom* methods will
75
 
        // go away.
76
 
 
77
 
        public class AspectLoader {
78
 
                Gdk.PixbufLoader loader = new Gdk.PixbufLoader ();
79
 
                int max_width;
80
 
                int max_height;
81
 
                ImageOrientation orientation;
82
 
 
83
 
                public AspectLoader (int max_width, int max_height) 
84
 
                {
85
 
                        this.max_height = max_height;
86
 
                        this.max_width = max_width;
87
 
                        loader.SizePrepared += HandleSizePrepared;
88
 
                }
89
 
 
90
 
                private void HandleSizePrepared (object obj, SizePreparedArgs args)
91
 
                {
92
 
                        switch (orientation) {
93
 
                        case ImageOrientation.LeftTop:
94
 
                        case ImageOrientation.LeftBottom:
95
 
                        case ImageOrientation.RightTop:
96
 
                        case ImageOrientation.RightBottom:
97
 
                                int tmp = max_width;
98
 
                                max_width = max_height;
99
 
                                max_height = tmp;
100
 
                                break;
101
 
                        default:
102
 
                                break;
103
 
                        }
104
 
 
105
 
                        int scale_width = 0;
106
 
                        int scale_height = 0;
107
 
 
108
 
                        double scale = Fit (args.Width, args.Height, max_width, max_height, true, out scale_width, out scale_height);
109
 
 
110
 
                        if (scale < 1.0)
111
 
                                loader.SetSize (scale_width, scale_height);
112
 
                }
113
 
 
114
 
                public Pixbuf Load (System.IO.Stream stream, ImageOrientation orientation)
115
 
                {
116
 
                        int count;
117
 
                        byte [] data = new byte [8192];
118
 
                        while (((count = stream.Read (data, 0, data.Length)) > 0) && loader.Write (data, (ulong)count))
119
 
                                ;
120
 
                        
121
 
                        loader.Close ();
122
 
                        Pixbuf orig = loader.Pixbuf;
123
 
                        Gdk.Pixbuf rotated = FSpot.Utils.PixbufUtils.TransformOrientation (orig, orientation);
124
 
                        
125
 
                        if (orig != rotated) {
126
 
                                orig.Dispose ();
127
 
                        }
128
 
                        loader.Dispose ();
129
 
                        return rotated;
130
 
                }
131
 
                
132
 
                public Pixbuf LoadFromFile (string path)
133
 
                {
134
 
                        try {
135
 
                                orientation = GetOrientation (path);
136
 
                                using (FileStream fs = System.IO.File.OpenRead (path)) {
137
 
                                        return Load (fs, orientation);
138
 
                                }
139
 
                        } catch (Exception) {
140
 
                                Log.ErrorFormat ("Error loading photo {0}", path);
141
 
                                return null;
142
 
                        } 
143
 
                }
144
 
        }
145
 
 
146
 
        public static Pixbuf ScaleToMaxSize (Pixbuf pixbuf, int width, int height)
147
 
        {
148
 
                return ScaleToMaxSize (pixbuf, width, height, true);
149
 
        }       
150
 
 
151
 
        public static Pixbuf ScaleToMaxSize (Pixbuf pixbuf, int width, int height, bool upscale)
152
 
        {
153
 
                int scale_width = 0;
154
 
                int scale_height = 0;
155
 
                double scale = Fit (pixbuf, width, height, upscale, out scale_width, out scale_height);
156
 
 
157
 
                Gdk.Pixbuf result;
158
 
                if (upscale || (scale < 1.0))
159
 
                        result = pixbuf.ScaleSimple (scale_width, scale_height, (scale_width > 20) ? Gdk.InterpType.Bilinear : Gdk.InterpType.Nearest);
160
 
                else
161
 
                        result = pixbuf.Copy ();
162
 
 
163
 
                return result;
164
 
        }
165
 
                
166
 
        static public void GetSize (string path, out int width, out int height)
167
 
        {
168
 
                using (Gdk.Pixbuf pixbuf = new Gdk.Pixbuf (path)) {
169
 
                        width = pixbuf.Width;
170
 
                        height = pixbuf.Height;
171
 
                }
172
 
        }
173
 
 
174
 
        static public Pixbuf LoadAtMaxSize (string path, int max_width, int max_height)
175
 
        {
176
 
                PixbufUtils.AspectLoader loader = new AspectLoader (max_width, max_height);
177
 
                return loader.LoadFromFile (path);
178
 
        }
179
 
 
180
 
        static public Pixbuf LoadFromStream (System.IO.Stream input)
181
 
        {
182
 
                Gdk.PixbufLoader loader = new Gdk.PixbufLoader ();
183
 
                byte [] buffer = new byte [8192];
184
 
                int n;
185
 
 
186
 
                while ((n = input.Read (buffer, 0, 8192)) != 0)
187
 
                        loader.Write (buffer, (ulong) n);
188
 
                
189
 
                loader.Close ();
190
 
                
191
 
                return loader.Pixbuf;
192
 
                
193
 
        }
194
 
 
195
 
        public static Pixbuf TagIconFromPixbuf (Pixbuf source)
196
 
        {
197
 
                return IconFromPixbuf (source, (int) FSpot.Tag.IconSize.Large);
198
 
        }
199
 
 
200
 
        public static Pixbuf IconFromPixbuf (Pixbuf source, int size)
201
 
        {
202
 
                Pixbuf tmp = null;
203
 
                Pixbuf icon = null;
204
 
 
205
 
                if (source.Width > source.Height)
206
 
                        source = tmp = new Pixbuf (source, (source.Width - source.Height) /2, 0, source.Height, source.Height);
207
 
                else if (source.Width < source.Height) 
208
 
                        source = tmp = new Pixbuf (source, 0, (source.Height - source.Width) /2, source.Width, source.Width);
209
 
 
210
 
                if (source.Width == source.Height)
211
 
                        icon = source.ScaleSimple (size, size, InterpType.Bilinear);
212
 
                else
213
 
                        throw new Exception ("Bad logic leads to bad accidents");
214
 
 
215
 
                if (tmp != null)
216
 
                        tmp.Dispose ();
217
 
                
218
 
                return icon;
219
 
        }
220
 
 
221
 
        static Pixbuf LoadFromAssembly (string resource)
222
 
        {
223
 
                try {
224
 
                        return new Pixbuf (System.Reflection.Assembly.GetEntryAssembly (), resource);
225
 
                } catch {
226
 
                        return null;
227
 
                }
228
 
        }
229
 
 
230
 
        public static Gdk.Pixbuf ScaleToAspect (Gdk.Pixbuf orig, int width, int height)
231
 
        {
232
 
                Gdk.Rectangle pos;
233
 
                double scale = Fit (orig, width, height, false, out pos.Width, out pos.Height);
234
 
                pos.X = (width - pos.Width) / 2;
235
 
                pos.Y = (height - pos.Height) / 2;
236
 
 
237
 
                Pixbuf scaled = new Pixbuf (Colorspace.Rgb, false, 8, width, height);
238
 
                scaled.Fill (0x000000); 
239
 
 
240
 
                orig.Composite (scaled, pos.X, pos.Y, 
241
 
                                pos.Width, pos.Height,
242
 
                                pos.X, pos.Y, scale, scale,
243
 
                                Gdk.InterpType.Bilinear,
244
 
                                255);
245
 
 
246
 
                return scaled;
247
 
        }
248
 
 
249
 
        public static Pixbuf Flatten (Pixbuf pixbuf)
250
 
        {
251
 
                if (!pixbuf.HasAlpha)
252
 
                        return null;
253
 
 
254
 
                Pixbuf flattened = new Pixbuf (Colorspace.Rgb, false, 8, pixbuf.Width, pixbuf.Height);
255
 
                pixbuf.CompositeColor (flattened, 0, 0, 
256
 
                                       pixbuf.Width, pixbuf.Height, 
257
 
                                       0, 0, 1, 1, 
258
 
                                       InterpType.Bilinear,
259
 
                                       255, 0, 0, 2000, 0xffffff, 0xffffff);
260
 
 
261
 
                return flattened;
262
 
        }
263
 
 
264
 
        [DllImport ("libfspot")]
265
 
        static extern IntPtr f_pixbuf_unsharp_mask (IntPtr src, double radius, double amount, double threshold);
266
 
 
267
 
        public static Pixbuf UnsharpMask (Pixbuf src, double radius, double amount, double threshold)
268
 
        {
269
 
                IntPtr raw_ret = f_pixbuf_unsharp_mask (src.Handle, radius, amount, threshold);
270
 
                Gdk.Pixbuf ret = (Gdk.Pixbuf) GLib.Object.GetObject(raw_ret, true);
271
 
                return ret;
272
 
        }
273
 
        
274
 
        [DllImport ("libfspot")]
275
 
        static extern IntPtr f_pixbuf_blur (IntPtr src, double radius);
276
 
 
277
 
        public static Pixbuf Blur (Pixbuf src, double radius)
278
 
        {
279
 
                IntPtr raw_ret = f_pixbuf_blur (src.Handle, radius);
280
 
                Gdk.Pixbuf ret = (Gdk.Pixbuf) GLib.Object.GetObject(raw_ret, true);
281
 
                return ret;
282
 
        }       
283
 
 
284
 
        public unsafe static Gdk.Pixbuf RemoveRedeye (Gdk.Pixbuf src, Gdk.Rectangle area)
285
 
        {
286
 
                return RemoveRedeye (src, area, -15);
287
 
        }
288
 
 
289
 
        public unsafe static Gdk.Pixbuf RemoveRedeye (Gdk.Pixbuf src, Gdk.Rectangle area, int threshold)
290
 
        //threshold, factors and comparisons borrowed from the gimp plugin 'redeye.c' by Robert Merkel
291
 
        {
292
 
                Gdk.Pixbuf copy = src.Copy ();
293
 
                Gdk.Pixbuf selection = new Gdk.Pixbuf (copy, area.X, area.Y, area.Width, area.Height);
294
 
                byte *spix = (byte *)selection.Pixels;
295
 
                int h = selection.Height;
296
 
                int w = selection.Width;
297
 
                int channels = src.NChannels;
298
 
 
299
 
                double RED_FACTOR = 0.5133333;
300
 
                double GREEN_FACTOR = 1;
301
 
                double BLUE_FACTOR = 0.1933333;
302
 
 
303
 
                for (int j = 0; j < h; j++) {
304
 
                        byte *s = spix;
305
 
                        for (int i = 0; i < w; i++) {
306
 
                                int adjusted_red = (int)(s[0] * RED_FACTOR);
307
 
                                int adjusted_green = (int)(s[1] * GREEN_FACTOR);
308
 
                                int adjusted_blue = (int)(s[2] * BLUE_FACTOR);
309
 
 
310
 
                                if (adjusted_red >= adjusted_green - threshold
311
 
                                    && adjusted_red >= adjusted_blue - threshold)
312
 
                                        s[0] = (byte)(((double)(adjusted_green + adjusted_blue)) / (2.0 * RED_FACTOR));
313
 
                                s += channels;
314
 
                        }
315
 
                        spix += selection.Rowstride;
316
 
                }
317
 
 
318
 
                return copy;
319
 
        }
320
 
 
321
 
        public static unsafe Pixbuf ColorAdjust (Pixbuf src, double brightness, double contrast,
322
 
                                          double hue, double saturation, int src_color, int dest_color)
323
 
        {
324
 
                Pixbuf adjusted = new Pixbuf (Colorspace.Rgb, src.HasAlpha, 8, src.Width, src.Height);
325
 
                PixbufUtils.ColorAdjust (src, adjusted, brightness, contrast, hue, saturation, src_color, dest_color);
326
 
                return adjusted;
327
 
        }
328
 
 
329
 
        public static Cms.Format PixbufCmsFormat (Pixbuf buf)
330
 
        {
331
 
                return buf.HasAlpha ? Cms.Format.Rgba8Planar : Cms.Format.Rgb8;
332
 
        }
333
 
 
334
 
        public static unsafe void ColorAdjust (Pixbuf src, Pixbuf dest, 
335
 
                                               double brightness, double contrast,
336
 
                                               double hue, double saturation, 
337
 
                                               int src_color, int dest_color)
338
 
        {
339
 
                if (src.Width != dest.Width || src.Height != dest.Height)
340
 
                        throw new Exception ("Invalid Dimensions");
341
 
 
342
 
                //Cms.Profile eos10d = new Cms.Profile ("/home/lewing/ICCProfiles/EOS-10D-True-Color-Non-Linear.icm");
343
 
                Cms.Profile srgb = Cms.Profile.CreateStandardRgb ();
344
 
 
345
 
                Cms.Profile bchsw = Cms.Profile.CreateAbstract (256, 
346
 
                                                                0.0, 
347
 
                                                                brightness, contrast,
348
 
                                                                hue, saturation, src_color, 
349
 
                                                                dest_color);
350
 
 
351
 
                Cms.Profile [] list = new Cms.Profile [] { srgb, bchsw, srgb };
352
 
                Cms.Transform trans = new Cms.Transform (list, 
353
 
                                                         PixbufCmsFormat (src),
354
 
                                                         PixbufCmsFormat (dest),
355
 
                                                         Cms.Intent.Perceptual, 0x0100);
356
 
 
357
 
                ColorAdjust (src, dest, trans);
358
 
 
359
 
                trans.Dispose ();
360
 
                srgb.Dispose ();
361
 
                bchsw.Dispose ();
362
 
        }
363
 
 
364
 
 
365
 
        public static unsafe void ColorAdjust (Gdk.Pixbuf src, Gdk.Pixbuf dest, Cms.Transform trans)
366
 
        {
367
 
                int width = src.Width;
368
 
                byte * srcpix  = (byte *) src.Pixels;
369
 
                byte * destpix = (byte *) dest.Pixels;
370
 
 
371
 
                for (int row = 0; row < src.Height; row++) {
372
 
                        trans.Apply ((IntPtr) (srcpix + row * src.Rowstride),
373
 
                                     (IntPtr) (destpix + row * dest.Rowstride), 
374
 
                                     (uint)width);
375
 
                }
376
 
                
377
 
        }
378
 
 
379
 
        public static unsafe bool IsGray (Gdk.Pixbuf pixbuf, int max_difference)
380
 
        {
381
 
                int chan = pixbuf.NChannels;
382
 
 
383
 
                byte *pix = (byte *)pixbuf.Pixels;
384
 
                int h = pixbuf.Height;
385
 
                int w = pixbuf.Width;
386
 
                int stride = pixbuf.Rowstride;
387
 
 
388
 
                for (int j = 0; j < h; j++) {
389
 
                        byte *p = pix;
390
 
                        for (int i = 0; i < w; i++) {
391
 
                                if (Math.Abs (p[0] - p[1]) > max_difference || Math.Abs (p[0] - p [2]) > max_difference) {
392
 
                                        goto Found;
393
 
                                }
394
 
                                p += chan;
395
 
                        }
396
 
                        pix += stride;
397
 
                }
398
 
 
399
 
                return true;
400
 
 
401
 
        Found:
402
 
                return false;
403
 
        }
404
 
 
405
 
        public static unsafe void ReplaceColor (Gdk.Pixbuf src, Gdk.Pixbuf dest)
406
 
        {
407
 
                if (src.HasAlpha || !dest.HasAlpha || (src.Width != dest.Width) || (src.Height != dest.Height))
408
 
                        throw new ApplicationException ("invalid pixbufs");
409
 
 
410
 
                byte *dpix = (byte *)dest.Pixels;
411
 
                byte *spix = (byte *)src.Pixels;
412
 
                int h = src.Height;
413
 
                int w = src.Width;
414
 
                for (int j = 0; j < h; j++) {
415
 
                        byte *d = dpix;
416
 
                        byte *s = spix;
417
 
                        for (int i = 0; i < w; i++) {
418
 
                                d[0] = s[0];
419
 
                                d[1] = s[1];
420
 
                                d[2] = s[2];
421
 
                                d += 4;
422
 
                                s += 3;
423
 
                        }
424
 
                        dpix += dest.Rowstride;
425
 
                        spix += src.Rowstride;
426
 
                }
427
 
        }
428
 
 
429
 
        public static ImageOrientation GetOrientation (SafeUri uri)
430
 
        {
431
 
                using (var img = ImageFile.Create (uri)) {
432
 
                        return img.Orientation;
433
 
                }       
434
 
        }
435
 
        
436
 
        [Obsolete ("Use GetOrientation (SafeUri) instead")]
437
 
        public static ImageOrientation GetOrientation (string path)
438
 
        {
439
 
        return GetOrientation (new SafeUri (path));
440
 
        }
441
 
 
442
 
        [DllImport("libgnomeui-2-0.dll")]
443
 
        static extern IntPtr gnome_thumbnail_scale_down_pixbuf(IntPtr pixbuf, int dest_width, int dest_height);
444
 
 
445
 
        public static Gdk.Pixbuf ScaleDown (Gdk.Pixbuf src, int width, int height)
446
 
        {
447
 
                IntPtr raw_ret = gnome_thumbnail_scale_down_pixbuf(src.Handle, width, height);
448
 
                Gdk.Pixbuf ret;
449
 
                if (raw_ret == IntPtr.Zero)
450
 
                        ret = null;
451
 
                else
452
 
                        ret = (Gdk.Pixbuf) GLib.Object.GetObject(raw_ret, true);
453
 
                return ret;
454
 
        }
455
 
 
456
 
    public static void CreateDerivedVersion (SafeUri source, SafeUri destination)
457
 
    {
458
 
        CreateDerivedVersion (source, destination, 95);
459
 
    }
460
 
 
461
 
    public static void CreateDerivedVersion (SafeUri source, SafeUri destination, uint jpeg_quality)
462
 
    {
463
 
        if (source.GetExtension () == destination.GetExtension ()) {
464
 
            // Simple copy will do!
465
 
            var file_from = GLib.FileFactory.NewForUri (source);
466
 
            var file_to = GLib.FileFactory.NewForUri (destination);
467
 
            file_from.Copy (file_to, GLib.FileCopyFlags.AllMetadata | GLib.FileCopyFlags.Overwrite, null, null);
468
 
            return;
469
 
        }
470
 
 
471
 
        // Else make a derived copy with metadata copied
472
 
        using (var img = ImageFile.Create (source)) {
473
 
            using (var pixbuf = img.Load ()) {
474
 
                CreateDerivedVersion (source, destination, jpeg_quality, pixbuf);
475
 
            }
476
 
        }
477
 
    }
478
 
 
479
 
    public static void CreateDerivedVersion (SafeUri source, SafeUri destination, uint jpeg_quality, Pixbuf pixbuf)
480
 
    {
481
 
        SaveToSuitableFormat (destination, pixbuf, jpeg_quality);
482
 
 
483
 
        using (var metadata_from = Metadata.Parse (source)) {
484
 
            using (var metadata_to = Metadata.Parse (destination)) {
485
 
                metadata_to.CopyFrom (metadata_from);
486
 
                metadata_to.Save ();
487
 
            }
488
 
        }
489
 
    }
490
 
 
491
 
    private static void SaveToSuitableFormat (SafeUri destination, Pixbuf pixbuf, uint jpeg_quality)
492
 
    {
493
 
        // FIXME: this needs to work on streams rather than filenames. Do that when we switch to
494
 
        // newer GDK.
495
 
        var extension = destination.GetExtension ().ToLower ();
496
 
        if (extension == ".png") {
497
 
            pixbuf.Save (destination.LocalPath, "png");
498
 
        } else if (extension == ".jpg" || extension == ".jpeg") {
499
 
            pixbuf.Save (destination.LocalPath, "jpeg", jpeg_quality);
500
 
        } else {
501
 
            throw new NotImplementedException ("Saving this file format is not supported");
502
 
        }
503
 
    }
504
 
 
505
 
#region Gdk hackery
506
 
 
507
 
    // This hack below is needed because there is no wrapped version of
508
 
    // Save which allows specifying the variable arguments (it's not
509
 
    // possible with p/invoke).
510
 
 
511
 
    [DllImport("libgdk_pixbuf-2.0-0.dll")]
512
 
    static extern bool gdk_pixbuf_save(IntPtr raw, IntPtr filename, IntPtr type, out IntPtr error,
513
 
            IntPtr optlabel1, IntPtr optvalue1, IntPtr dummy);
514
 
 
515
 
    private static bool Save (this Pixbuf pixbuf, string filename, string type, uint jpeg_quality)
516
 
    {
517
 
        IntPtr error = IntPtr.Zero;
518
 
        IntPtr nfilename = GLib.Marshaller.StringToPtrGStrdup (filename);
519
 
        IntPtr ntype = GLib.Marshaller.StringToPtrGStrdup (type);
520
 
        IntPtr optlabel1 = GLib.Marshaller.StringToPtrGStrdup ("quality");
521
 
        IntPtr optvalue1 = GLib.Marshaller.StringToPtrGStrdup (jpeg_quality.ToString ());
522
 
        bool ret = gdk_pixbuf_save(pixbuf.Handle, nfilename, ntype, out error, optlabel1, optvalue1, IntPtr.Zero);
523
 
        GLib.Marshaller.Free (nfilename);
524
 
        GLib.Marshaller.Free (ntype);
525
 
        GLib.Marshaller.Free (optlabel1);
526
 
        GLib.Marshaller.Free (optvalue1);
527
 
        if (error != IntPtr.Zero) throw new GLib.GException (error);
528
 
        return ret;
529
 
    }
530
 
 
531
 
#endregion
532
 
}