1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 const string LOG_DOMAIN
= "ImageAsync";
28 * Operations you can do on the image.
29 * The modified pixbuf will be stored in cache.
31 public enum ModificationType
33 NONE
= 0, // Add nothing
34 CASING
= 1, // Add border and or casing
35 DARKEN
= 2, // Darken the image (for backdrop)
36 DECOLOR
= 4, // Remove color from image.
39 public class PixbufLoaderAsync
: GLib
.Object
41 public string uri
= null;
42 public Gdk
.Pixbuf pixbuf
{set; get; default=null;}
43 private Gtk
.TreeRowReference rref
= null;
47 public signal void pixbuf_update(Gdk
.Pixbuf? pixbuf
);
49 public void set_rref(Gtk
.TreeRowReference rreference
)
51 this
.rref
= rreference
;
54 private void call_row_changed()
58 var model
= rref
.get_model();
59 var path
= rref
.get_path();
61 if(model
.get_iter(out iter
, path
))
63 model
.row_changed(path
, iter
);
70 GLib
.log(LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
,"Create the image loading\n" );
74 private Gdk
.Pixbuf?
modify_pixbuf(owned Gdk
.Pixbuf? pix
, int size
,ModificationType casing
)
76 if(pix
== null) return null;
77 if((casing
&ModificationType
.CASING
) == ModificationType
.CASING
)
79 if(config
.get_int_with_default("metaimage", "addcase", 1) == 1)
81 int width
= pix
.width
;
82 int height
= pix
.height
;
83 double spineRatio
= 5.0/65.0;
85 var ii
= Gtk
.IconTheme
.get_default().lookup_icon("stylized-cover", size
, 0);
88 var path
= ii
.get_filename();
91 var case_image
= new Gdk
.Pixbuf
.from_file_at_scale(path
, size
, size
, true);
93 var tempw
= (int)(case_image
.width
*(1.0-spineRatio
));
95 if((case_image
.height
/(double)height
)*width
< tempw
)
97 pix2
= pix
.scale_simple(tempw
, (int)((height
*tempw
)/width
), Gdk
.InterpType
.BILINEAR
);
101 pix2
= pix
.scale_simple((int)(width
*(case_image
.height
/(double)height
)), case_image
.height
, Gdk
.InterpType
.BILINEAR
);
103 var blank
= new Gdk
.Pixbuf(Gdk
.Colorspace
.RGB
, true, 8, case_image
.width
, case_image
.height
);
104 blank
.fill(0x000000FF);
105 tempw
= (tempw
>= pix2
.width
)? pix2
.width
:tempw
;
106 var temph
= (case_image
.height
> pix2
.height
)?pix2
.height
:case_image
.height
;
107 pix2
.copy_area(0,0, tempw
-1, temph
-2, blank
, case_image
.width
-tempw
, 1);
108 case_image
.composite(blank
, 0,0,case_image
.width
, case_image
.height
, 0,0,1,1,Gdk
.InterpType
.BILINEAR
, 250);
113 GLib
.log(LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_WARNING
,
114 "Failed to get the stylized-cover image");
121 Gmpc
.Fix
.add_border(pix
);
124 if ((casing
&ModificationType
.DARKEN
) == ModificationType
.DARKEN
)
126 Gmpc
.Misc
.darken_pixbuf(pix
, 2);
128 if ((casing
&ModificationType
.DECOLOR
) == ModificationType
.DECOLOR
)
130 Gmpc
.Misc
.decolor_pixbuf(pix
, pix
);
132 if ((casing
&ModificationType
.BORDER
) == ModificationType
.BORDER
)
134 Gmpc
.Misc
.border_pixbuf(pix
);
141 private uint loader_timeout
= 0;
142 private Gdk
.PixbufLoader? loader
= null;
143 private uchar[] loader_data
= null;
144 private uint loader_data_offset
= 0;
145 private uchar[] loader_md5sum
= null;
146 private ModificationType loader_border
= ModificationType
.NONE
;
150 GLib
.log(LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
,"Free the image loading");
151 // Cancel previous load.
152 if ( loader_timeout
> 0)
154 GLib
.Source
.remove(loader_timeout
);
157 loader_md5sum
= null;
173 public void set_from_raw(uchar[] data
, int req_width
, int req_height
, ModificationType border
, [CCode (array_length
= false)]uchar[] md5sum
)
178 // Cancel previous load.
179 if ( loader_timeout
> 0)
181 GLib
.Source
.remove(loader_timeout
);
184 loader_md5sum
= null;
198 var pb
= Gmpc
.PixbufCache
.lookup_icon(int.max(width
,height
), md5sum
);
202 pixbuf_update(pixbuf
);
207 loader
= new Gdk
.PixbufLoader();
208 loader
.size_prepared
.connect(size_prepare
);
211 loader_data_offset
= 0;
212 loader_md5sum
= md5sum
[0:16];
213 loader_border
= border
;
216 loader_timeout
= GLib
.Idle
.add(loader_idle_callback
);
217 // loader_timeout = GLib.Timeout.add(200, loader_idle_callback);
221 private bool loader_idle_callback()
226 uint end
= uint.min(loader_data_offset
+2048, loader_data
.length
);
227 Gmpc
.Fix
.write_loader(loader
, (string)loader_data
[loader_data_offset
:end
], end
-loader_data_offset
);
228 loader_data_offset
= end
;;
232 warning("Error trying to load image: %s::%s", e
.message
,uri
);
234 if(loader_data_offset
< loader_data
.length
) return true;
242 debug("Error trying to parse image: %s::%s? query cancelled?", err
.message
,uri
);
247 loader_md5sum
= null;
253 Gdk
.Pixbuf pix
= loader
.get_pixbuf();
254 /* Maybe another thread allready fetched it in the mean time, we want to use that... */
255 var final
= Gmpc
.PixbufCache
.lookup_icon(int.max(height
, width
), loader_md5sum
);
258 final
= this
.modify_pixbuf((owned
)pix
, int.max(height
, width
),loader_border
);
259 Gmpc
.PixbufCache
.add_icon(int.max(height
, width
),loader_md5sum
, final
);
263 pixbuf_update(pixbuf
);
269 loader_md5sum
= null;
274 private void size_prepare(Gdk
.PixbufLoader loader
,int gwidth
, int gheight
)
276 double dsize
= (double)(int.max(width
,height
));
277 int nwidth
= 0, nheight
= 0;
280 double scale
= width
/(double)gwidth
;
282 nheight
= (int)(gheight
*scale
);
286 double scale
= height
/(double)gheight
;
288 nwidth
= (int)(gwidth
*scale
);
292 nwidth
= (gheight
>gwidth
)?
(int)((dsize
/gheight
)*gwidth
): (int)dsize
;
293 nheight
= (gwidth
> gheight
)?
(int)((dsize
/gwidth
)*gheight
): (int)dsize
;
295 loader
.set_size(nwidth
, nheight
);
298 public class MetaImageAsync
: Gtk
.Image
300 private Gmpc
.PixbufLoaderAsync? loader
= null;
301 public string uri
= null;
309 GLib
.log(LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
,"Freeing metaimageasync\n");
311 public new
void set_from_raw(uchar[] data
, int size
, ModificationType border
, [CCode (array_length
= false)] uchar[] md5sum
)
315 loader
= new
PixbufLoaderAsync();
316 loader
.pixbuf_update
.connect((source
, pixbuf
)=>
318 this
.set_from_pixbuf(pixbuf
);
321 loader
.set_from_raw(data
, size
,size
, border
,md5sum
);
324 public void clear_now()
331 public void set_pixbuf(Gdk
.Pixbuf? pb
)
337 this
.set_from_pixbuf(pb
);