Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflavio <fdanesse@gmail.com>2012-12-18 23:58:57 (GMT)
committer flavio <fdanesse@gmail.com>2012-12-18 23:58:57 (GMT)
commit3fa345f645bd591db70b32b487d7bed87a2f3018 (patch)
tree9feb98042227a11c6efa823936be7c111c920984
parente98506d07f590393717250ff0edbcc505517f939 (diff)
Burn video, audio recording, audio and video processing, generate pixbuf and previews
-rw-r--r--glive.py173
-rw-r--r--gplay.py1
-rw-r--r--model.py37
-rw-r--r--record.py41
-rw-r--r--serialize.py4
-rw-r--r--utils.py16
6 files changed, 182 insertions, 90 deletions
diff --git a/glive.py b/glive.py
index 48e28d1..da84e27 100644
--- a/glive.py
+++ b/glive.py
@@ -29,7 +29,6 @@ from gi.repository import GObject
from gi.repository import Gst
from gi.repository import GstVideo
-from sugar3.activity.activity import get_bundle_path
import logging
from instance import Instance
@@ -129,27 +128,29 @@ class Glive:
queue = Gst.ElementFactory.make("queue", "pbqueue")
queue.set_property("leaky", 1)
queue.set_property("max-size-buffers", 1)
-
+
colorspace = Gst.ElementFactory.make("videoconvert", "pbcolorspace")
jpeg = Gst.ElementFactory.make("jpegenc", "pbjpeg")
-
+
sink = Gst.ElementFactory.make("fakesink", "pbsink")
sink.connect("handoff", self._photo_handoff)
sink.set_property("signal-handoffs", True)
-
+
self._photobin = Gst.Bin()
+ self._photobin.set_name('photobin')
+
self._photobin.add(queue)
self._photobin.add(colorspace)
self._photobin.add(jpeg)
self._photobin.add(sink)
-
+
queue.link(colorspace)
colorspace.link(jpeg)
jpeg.link(sink)
-
+
pad = queue.get_static_pad("sink")
self._photobin.add_pad(Gst.GhostPad.new("sink", pad))
-
+
def _create_audiobin(self):
src = Gst.ElementFactory.make("alsasrc", "absrc")
@@ -165,7 +166,7 @@ class Glive:
# WARNING **: 0.10-style raw audio caps are being created. Should be audio/x-raw,format=(string)
srccaps = Gst.Caps.from_string("audio/x-raw-int,rate=16000,channels=1,depth=16")
-
+
# guarantee perfect stream, important for A/V sync
rate = Gst.ElementFactory.make("audiorate", 'audiorate')
@@ -191,9 +192,11 @@ class Glive:
self._audiobin.add(queue)
self._audiobin.add(enc)
self._audiobin.add(sink)
-
- src.link(rate)
- rate.link(queue)
+
+ # FIXME: audiorate - If these elements connect the pipeline does not run.
+ # FIXME: srccaps - If these elements connect the pipeline does not run.
+ src.link(queue)
+ #rate.link(queue)
queue.link(enc)
enc.link(sink)
@@ -225,15 +228,16 @@ class Glive:
self._videobin.add(queue)
self._videobin.add(scale)
- self._videobin.add(scalecapsfilter)
+ #self._videobin.add(scalecapsfilter)
self._videobin.add(colorspace)
self._videobin.add(enc)
self._videobin.add(mux)
self._videobin.add(sink)
queue.link(scale)
- scale.link_pads(None, scalecapsfilter, "sink")
- scalecapsfilter.link_pads("src", colorspace, None)
+ #scale.link_pads(None, scalecapsfilter, "sink") # FIXME: If these elements connect the pipeline does not run.
+ #scalecapsfilter.link_pads("src", colorspace, None)
+ scale.link(colorspace)
colorspace.link(enc)
enc.link(mux)
mux.link(sink)
@@ -267,8 +271,8 @@ class Glive:
vbenc = self._videobin.get_by_name("vbenc")
vbenc.set_property("quality", 16)
- scaps = self._videobin.get_by_name("scalecaps")
- scaps.set_property("caps", Gst.Caps.from_string("video/x-raw-yuv,width=%d,height=%d" % (width, height)))
+ #scaps = self._videobin.get_by_name("scalecaps") # FIXME: If these elements connect the pipeline does not run.
+ #scaps.set_property("caps", Gst.Caps.from_string("video/x-raw-yuv,width=%d,height=%d" % (width, height)))
def _create_pipeline(self):
@@ -295,7 +299,7 @@ class Glive:
# the FPS value.
rate = Gst.ElementFactory.make("videorate", 'videorate')
ratecaps = Gst.Caps.from_string('video/x-raw-yuv,framerate=10/1')
-
+
tee = Gst.ElementFactory.make("tee", "tee")
queue = Gst.ElementFactory.make("queue", "dispqueue")
@@ -360,7 +364,7 @@ class Glive:
queue.link(self._xvsink)
return self._xvsink
-
+
def _configure_x(self):
if self._pipeline.get_by_name("xbin") == self._xbin:
@@ -419,6 +423,8 @@ class Glive:
return self._pipeline.get_state(0)[1]
def stop_recording_audio(self):
+ """ Stops recording audio
+ process begins wav to ogg."""
# We should be able to simply pause and remove the audiobin, but
# this seems to cause a gstreamer segfault. So we stop the whole
@@ -435,17 +441,23 @@ class Glive:
if self._audio_pixbuf:
self.model.still_ready(self._audio_pixbuf)
+
+ command = "filesrc location=%s name=audioFilesrc ! \
+ wavparse name=audioWavparse ! \
+ audioconvert name=audioAudioconvert ! \
+ vorbisenc name=audioVorbisenc ! \
+ oggmux name=audioOggmux ! \
+ filesink name=audioFilesink" % (audio_path)
+
+ audioline = Gst.parse_launch(command)
- line = 'filesrc location=' + audio_path + ' name=audioFilesrc ! wavparse name=audioWavparse ! audioconvert name=audioAudioconvert ! vorbisenc name=audioVorbisenc ! oggmux name=audioOggmux ! filesink name=audioFilesink'
- audioline = Gst.parse_launch(line)
-
- taglist = self._get_tags(constants.TYPE_AUDIO)
+ #taglist = self._get_tags(constants.TYPE_AUDIO)
- if self._audio_pixbuf:
- pixbuf_b64 = utils.getStringFromPixbuf(self._audio_pixbuf)
+ #if self._audio_pixbuf:
+ #pixbuf_b64 = utils.getStringFromPixbuf(self._audio_pixbuf)
#taglist[Gst.TAG_EXTENDED_COMMENT] = "coverart=" + pixbuf_b64
- vorbis_enc = audioline.get_by_name('audioVorbisenc')
+ #vorbis_enc = audioline.get_by_name('audioVorbisenc')
#vorbis_enc.merge_tags(taglist, Gst.TagMergeMode.REPLACE_ALL)
audioFilesink = audioline.get_by_name('audioFilesink')
@@ -454,7 +466,10 @@ class Glive:
audioBus = audioline.get_bus()
audioBus.add_signal_watch()
- self._audio_transcode_handler = audioBus.connect('message', self._onMuxedAudioMessageCb, audioline)
+
+ self._audio_transcode_handler = audioBus.connect(
+ 'message', self._onMuxedAudioMessageCb, audioline)
+
self._transcode_id = GObject.timeout_add(200, self._transcodeUpdateCb, audioline)
audioline.set_state(Gst.State.PLAYING)
@@ -483,10 +498,9 @@ class Glive:
self._photo_mode = photo_mode
self._pic_exposure_open = True
- pad = self._photobin.get_static_pad("sink")
self._pipeline.add(self._photobin)
- self._photobin.set_state(Gst.State.PLAYING)
self._pipeline.get_by_name("tee").link(self._photobin)
+ self._photobin.set_state(Gst.State.PLAYING)
def take_photo(self):
@@ -494,14 +508,14 @@ class Glive:
self._take_photo(self.PHOTO_MODE_PHOTO)
def _photo_handoff(self, fsink, buffer, pad, user_data=None):
+ """Generates the file for photography."""
if not self._pic_exposure_open:
return
-
- pad = self._photobin.get_static_pad("sink")
+
self._pipeline.get_by_name("tee").unlink(self._photobin)
self._pipeline.remove(self._photobin)
-
+
self._pic_exposure_open = False
#pic = GdkPixbuf.PixbufLoader.new_with_mime_type("image/jpeg")
# FIXME: TypeError: Must be sequence, not Buffer
@@ -509,8 +523,18 @@ class Glive:
#pic.close()
#pixBuf = pic.get_pixbuf()
#del pic
-
- #self.save_photo(pixBuf)
+
+ # FIXME: Must provide a pixbuf here.
+ # Attempt to modify the functions to get through
+ # gdkpixbufsink as in the pictures, but there was
+ # no success, so this pixbuf temporarily assigned
+ # to find a solution to this problem.
+ path = os.path.dirname(__file__)
+ pix_file = os.path.join(path, 'gfx', 'media-circle.png')
+ self.thumbBuf = GdkPixbuf.Pixbuf.new_from_file(pix_file)
+ self.model.still_ready(self.thumbBuf)
+
+ self.save_photo(pixBuf)
def save_photo(self, pixbuf):
@@ -521,6 +545,7 @@ class Glive:
self.model.save_photo(pixbuf)
def record_video(self, quality):
+ """Starts recording video."""
if not self._has_camera:
return
@@ -543,6 +568,7 @@ class Glive:
self.play()
def record_audio(self):
+ """Starts recording audio."""
if self._has_camera:
self._audio_pixbuf = None
@@ -569,7 +595,7 @@ class Glive:
self._eos_cb = self._video_eos
self._pipeline.get_by_name('camsrc').send_event(Gst.Event.new_eos())
self._audiobin.get_by_name('absrc').send_event(Gst.Event.new_eos())
-
+
def _video_eos(self):
self._pipeline.set_state(Gst.State.NULL)
@@ -588,27 +614,38 @@ class Glive:
if not os.path.exists(ogg_path) or os.path.getsize(ogg_path) <= 0:
# FIXME: inform model of failure?
return
-
- line = 'filesrc location=' + ogg_path + ' name=thumbFilesrc ! oggdemux name=thumbOggdemux ! theoradec name=thumbTheoradec ! tee name=thumb_tee ! queue name=thumb_queue ! videoconvert name=thumbFfmpegcolorspace ! jpegenc name=thumbJPegenc ! fakesink name=thumb_fakesink'
- thumbline = Gst.parse_launch(line)
+ command = "filesrc location=%s name=thumbFilesrc ! \
+ oggdemux name=thumbOggdemux ! \
+ theoradec name=thumbTheoradec ! \
+ tee name=thumb_tee ! \
+ queue name=thumb_queue ! \
+ videoconvert name=thumbFfmpegcolorspace ! \
+ jpegenc name=thumbJPegenc ! \
+ fakesink name=thumb_fakesink" % (ogg_path)
+
+ thumbline = Gst.parse_launch(command)
thumb_queue = thumbline.get_by_name('thumb_queue')
thumb_queue.set_property("leaky", 1)
thumb_queue.set_property("max-size-buffers", 1)
- thumb_tee = thumbline.get_by_name('thumb_tee')
+
thumb_fakesink = thumbline.get_by_name('thumb_fakesink')
self._thumb_handoff_handler = thumb_fakesink.connect("handoff", self.copyThumbPic)
thumb_fakesink.set_property("signal-handoffs", True)
+
self._thumb_pipes.append(thumbline)
+
self._thumb_exposure_open = True
+
thumbline.set_state(Gst.State.PLAYING)
def copyThumbPic(self, fsink, buffer, pad, user_data=None):
+ """Generates a thumbnail for the video."""
if not self._thumb_exposure_open:
return
-
+
self._thumb_exposure_open = False
#loader = GdkPixbuf.PixbufLoader.new_with_mime_type("image/jpeg")
# FIXME: TypeError: Must be sequence, not Buffer
@@ -616,28 +653,55 @@ class Glive:
#loader.close()
#self.thumbBuf = loader.get_pixbuf()
#self.model.still_ready(self.thumbBuf)
-
+
self._thumb_element('thumb_tee').unlink(self._thumb_element('thumb_queue'))
+ # FIXME: Must provide a pixbuf here.
+ # Attempt to modify the functions to get through
+ # gdkpixbufsink as in the pictures, but there was
+ # no success, so this pixbuf temporarily assigned
+ # to find a solution to this problem.
+ path = os.path.dirname(__file__)
+ pix_file = os.path.join(path, 'gfx', 'media-record.png')
+ self.thumbBuf = GdkPixbuf.Pixbuf.new_from_file(pix_file)
+ self.model.still_ready(self.thumbBuf)
+
+ # Process audio and video to a single file.
oggFilepath = os.path.join(Instance.instancePath, "output.ogg")
wavFilepath = os.path.join(Instance.instancePath, "output.wav")
muxFilepath = os.path.join(Instance.instancePath, "mux.ogg")
-
- muxline = Gst.parse_launch('filesrc location=' + str(oggFilepath) + ' name=muxVideoFilesrc ! oggdemux name=muxOggdemux ! theoraparse ! oggmux name=muxOggmux ! filesink location=' + str(muxFilepath) + ' name=muxFilesink filesrc location=' + str(wavFilepath) + ' name=muxAudioFilesrc ! wavparse name=muxWavparse ! audioconvert name=muxAudioconvert ! vorbisenc name=muxVorbisenc ! muxOggmux.')
-
- taglist = self._get_tags(constants.TYPE_VIDEO)
- vorbis_enc = muxline.get_by_name('muxVorbisenc')
+
+ command = "filesrc location=%s name=muxVideoFilesrc ! \
+ oggdemux name=muxOggdemux ! \
+ oggmux name=muxOggmux ! \
+ filesink location=%s name=muxFilesink \
+ filesrc location=%s name=muxAudioFilesrc ! \
+ wavparse name=muxWavparse ! \
+ audioconvert name=muxAudioconvert ! \
+ vorbisenc name=muxVorbisenc ! \
+ muxOggmux." % ( str(oggFilepath), str(muxFilepath), str(wavFilepath) )
+
+ muxline = Gst.parse_launch(command)
+
+ #taglist = self._get_tags(constants.TYPE_VIDEO)
+ #vorbis_enc = muxline.get_by_name('muxVorbisenc')
#vorbis_enc.merge_tags(taglist, Gst.TagMergeMode.REPLACE_ALL)
muxBus = muxline.get_bus()
muxBus.add_signal_watch()
- self._video_transcode_handler = muxBus.connect('message', self._onMuxedVideoMessageCb, muxline)
+
+ self._video_transcode_handler = muxBus.connect('message',
+ self._onMuxedVideoMessageCb, muxline)
+
self._mux_pipes.append(muxline)
+
#add a listener here to monitor % of transcoding...
- self._transcode_id = GObject.timeout_add(200, self._transcodeUpdateCb, muxline)
+ self._transcode_id = GObject.timeout_add(200,
+ self._transcodeUpdateCb, muxline)
+
muxline.set_state(Gst.State.PLAYING)
-
- def _transcodeUpdateCb( self, pipe ):
+
+ def _transcodeUpdateCb(self, pipe):
position, duration = self._query_position( pipe )
@@ -671,17 +735,22 @@ class Glive:
GObject.source_remove(self._video_transcode_handler)
self._video_transcode_handler = None
+
GObject.source_remove(self._transcode_id)
self._transcode_id = None
+
pipe.set_state(Gst.State.NULL)
+
pipe.get_bus().remove_signal_watch()
pipe.get_bus().disable_sync_message_emission()
wavFilepath = os.path.join(Instance.instancePath, "output.wav")
oggFilepath = os.path.join(Instance.instancePath, "output.ogg")
muxFilepath = os.path.join(Instance.instancePath, "mux.ogg")
+
os.remove( wavFilepath )
os.remove( oggFilepath )
+
self.model.save_video(muxFilepath, self.thumbBuf)
return False
@@ -693,15 +762,20 @@ class Glive:
GObject.source_remove(self._audio_transcode_handler)
self._audio_transcode_handler = None
+
GObject.source_remove(self._transcode_id)
self._transcode_id = None
+
pipe.set_state(Gst.State.NULL)
+
pipe.get_bus().remove_signal_watch()
pipe.get_bus().disable_sync_message_emission()
wavFilepath = os.path.join(Instance.instancePath, "output.wav")
oggFilepath = os.path.join(Instance.instancePath, "output.ogg")
+
os.remove( wavFilepath )
+
self.model.save_audio(oggFilepath, self._audio_pixbuf)
return False
@@ -752,3 +826,4 @@ class Glive:
if os.path.exists(mux_path):
os.remove(mux_path)
+ \ No newline at end of file
diff --git a/gplay.py b/gplay.py
index 52d34cf..f361c25 100644
--- a/gplay.py
+++ b/gplay.py
@@ -120,7 +120,6 @@ class Gplay(GObject.GObject):
value = (float(position) / float(duration)) * 100.0
self._emit_playback_status(value)
-
return True
def _emit_playback_status(self, position):
diff --git a/model.py b/model.py
index 771f08f..36ae819 100644
--- a/model.py
+++ b/model.py
@@ -76,17 +76,22 @@ class Model:
def write_file(self, path):
- ui_serialized = self.activity.serialize()
- self.mediaHashs['ui'] = ui_serialized
- dom = serialize.saveMediaHash(self.mediaHashs, self.activity)
- ui_data = json.dumps(ui_serialized)
- ui_el = dom.createElement('ui')
- ui_el.appendChild(dom.createTextNode(ui_data))
- dom.documentElement.appendChild(ui_el)
-
- fd = open(path, "w")
- dom.writexml(fd)
- fd.close()
+ # FIXME: Error: invalid value (typically too big) for the size of the input (surface, pattern, etc.)
+ # File ". . ./sugar3/activity/activity.py", line 648, in get_preview
+ # dummy_cr = Gdk.cairo_create(window)
+
+ #ui_serialized = self.activity.serialize()
+ #self.mediaHashs['ui'] = ui_serialized
+ #dom = serialize.saveMediaHash(self.mediaHashs, self.activity)
+ #ui_data = json.dumps(ui_serialized)
+ #ui_el = dom.createElement('ui')
+ #ui_el.appendChild(dom.createTextNode(ui_data))
+ #dom.documentElement.appendChild(ui_el)
+
+ #fd = open(path, "w")
+ #dom.writexml(fd)
+ #fd.close()
+ pass
def read_file(self, path):
@@ -312,10 +317,10 @@ class Model:
recd = self.createNewRecorded(constants.TYPE_PHOTO)
imgpath = os.path.join(Instance.instancePath, recd.mediaFilename)
- pixbuf.save(imgpath, "jpeg")
+ pixbuf.savev(imgpath, "jpeg", [], [])
pixbuf = utils.generate_thumbnail(pixbuf)
- pixbuf.save(recd.make_thumb_path(), "png")
+ pixbuf.savev(recd.make_thumb_path(), "png", [], [])
#now that we've saved both the image and its pixbuf, we get their md5s
self.createNewRecordedMd5Sums( recd )
@@ -329,7 +334,7 @@ class Model:
os.rename(path, os.path.join(Instance.instancePath, recd.mediaFilename))
still = utils.generate_thumbnail(still)
- still.save(recd.make_thumb_path(), "png")
+ still.savev(recd.make_thumb_path(), "png", [], [])
self.createNewRecordedMd5Sums( recd )
@@ -344,11 +349,11 @@ class Model:
if still:
image_path = os.path.join(Instance.instancePath, "audioPicture.png")
image_path = utils.getUniqueFilepath(image_path, 0)
- still.save(image_path, "png")
+ still.savev(image_path, "png", [], [])
recd.audioImageFilename = os.path.basename(image_path)
still = utils.generate_thumbnail(still)
- still.save(recd.make_thumb_path(), "png")
+ still.savev(recd.make_thumb_path(), "png", [], [])
self.createNewRecordedMd5Sums( recd )
diff --git a/record.py b/record.py
index 302a783..8c4521c 100644
--- a/record.py
+++ b/record.py
@@ -123,12 +123,6 @@ class Record(activity.Activity):
self.model.write_file(path)
- def close(self):
-
- self.model.gplay.stop()
- self.model.glive.stop()
- super(Record, self).close()
-
def _visibility_changed(self, widget, event):
self.model.set_visible(event.state != Gdk.VisibilityState.FULLY_OBSCURED)
@@ -788,11 +782,25 @@ class CountdownImage(Gtk.Image):
w = 55
h = w
- # FIXME: No more Pixmap
- """
- pixmap = GdK.Pixmap(self.get_window(), w, h, -1)
- ctx = pixmap.cairo_create()
- ctx.rectangle(0, 0, w, h)
+ x, y = self.get_property('window').get_position()
+ rect = self.get_allocation()
+ width, height = rect.width, rect.height
+
+ thumb_surface = Gdk.Window.create_similar_surface(
+ self.get_property('window'),
+ cairo.CONTENT_COLOR,
+ width, height)
+
+ ctx = cairo.Context(thumb_surface)
+
+ Gdk.cairo_set_source_window(
+ cairo_context,
+ self.get_property('window'),
+ x, y)
+
+ ctx.paint()
+
+ ctx.rectangle(x, y, w, h)
ctx.set_source_rgb(0, 0, 0)
ctx.fill()
@@ -819,14 +827,19 @@ class CountdownImage(Gtk.Image):
ctx.translate(-3, 0)
pctx.show_layout(play)
- return pixmap"""
-
+ pixbuf = Gdk.pixbuf_get_from_surface(
+ thumb_surface, 0, 0,
+ thumb_surface.get_width(),
+ thumb_surface.get_height())
+
+ return pixbuf
+
def set_value(self, num):
if num not in self._countdown_images:
self._countdown_images[num] = self._generate_image(num)
- self.set_from_pixmap(self._countdown_images[num], None)
+ self.set_from_pixbuf(self._countdown_images[num], None)
class ShutterButton(Gtk.Button):
diff --git a/serialize.py b/serialize.py
index a52c6ca..551170a 100644
--- a/serialize.py
+++ b/serialize.py
@@ -141,7 +141,7 @@ def fillRecdFromNode(recd, el):
thumbPath = os.path.join(Instance.instancePath, "datastoreThumb.jpg")
thumbPath = utils.getUniqueFilepath(thumbPath, 0)
thumbImg = utils.getPixbufFromString(bt.nodeValue)
- thumbImg.save(thumbPath, "jpeg", {"quality":"85"} )
+ thumbImg.savev(thumbPath, "jpeg", {"quality":"85"} )
recd.thumbFilename = os.path.basename(thumbPath)
logger.debug("saved thumbFilename")
@@ -155,7 +155,7 @@ def fillRecdFromNode(recd, el):
audioImagePath = os.path.join(Instance.instancePath, "audioImage.png")
audioImagePath = utils.getUniqueFilepath( audioImagePath, 0 )
audioImage = utils.getPixbufFromString( ai.nodeValue )
- audioImage.save(audioImagePath, "png", {} )
+ audioImage.savev(audioImagePath, "png", {} )
recd.audioImageFilename = os.path.basename(audioImagePath)
logger.debug("loaded audio image and set audioImageFilename")
diff --git a/utils.py b/utils.py
index 7a3216b..46b3779 100644
--- a/utils.py
+++ b/utils.py
@@ -10,17 +10,15 @@ from gi.repository import GdkPixbuf
from gi.repository import Rsvg
def getStringFromPixbuf(pixbuf):
+ """Converts a pixbuf in a string."""
- data = [""]
- pixbuf.save_to_callback(_saveDataToBufferCb, "png", {}, data)
- return base64.b64encode(str(data[0]))
-
-def _saveDataToBufferCb(buf, data):
+ # Save_to_bufferv return: (bool, string)
+ data = pixbuf.save_to_bufferv('png', [], [])
- data[0] += buf
- return True
+ return base64.b64encode(data[1])
def getPixbufFromString(str):
+ """Converts a string into a pixbuf."""
pbl = GdkPixbuf.PixbufLoader()
data = base64.b64decode( str )
@@ -30,6 +28,8 @@ def getPixbufFromString(str):
return pbl.get_pixbuf()
def load_colored_svg(filename, stroke, fill):
+ """Loads an svg, will change the fill and
+ stroke colors and returns the pixbuf."""
path = os.path.join(constants.GFX_PATH, filename)
data = open(path, 'r').read()
@@ -40,7 +40,7 @@ def load_colored_svg(filename, stroke, fill):
entity = '<!ENTITY stroke_color "%s">' % stroke
data = re.sub('<!ENTITY stroke_color .*>', entity, data)
- Rsvg.Handle.new_from_data(data.encode('utf-8')).get_pixbuf()
+ return Rsvg.Handle.new_from_data(data.encode('utf-8')).get_pixbuf()
def getUniqueFilepath( path, i ):