Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 7th, 2012  |  syntax: None  |  size: 6.78 KB  |  hits: 15  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. From a664d1c72c389caa3ea6cb67c50a039380cf2555 Mon Sep 17 00:00:00 2001
  2. From: Till Hartmann <ich@till-hartmann.de>
  3. Date: Sun, 25 Jul 2010 14:58:44 +0200
  4. Subject: [PATCH] Thumbnail storage and retrieval now follow FDO specs.
  5.  See http://jens.triq.net/thumbnail-spec/introduction.html for the
  6.  complete freedesktop.org thumbnail specification.
  7.  
  8. ---
  9.  gui/filehandling.py |   31 ++++-------------
  10.  lib/helpers.py      |   91 +++++++++++++++++++++++++++++++++++++++++---------
  11.  2 files changed, 82 insertions(+), 40 deletions(-)
  12.  
  13. diff --git a/gui/filehandling.py b/gui/filehandling.py
  14. index 871f071..336727b 100644
  15. --- a/gui/filehandling.py
  16. +++ b/gui/filehandling.py
  17. @@ -17,7 +17,6 @@ from gettext import ngettext
  18.  from lib import document, helpers
  19.  import drawwindow
  20.  
  21. -import zipfile
  22.  import mimetypes
  23.  
  24.  SAVE_FORMAT_ANY = 0
  25. @@ -253,30 +252,16 @@ class FileHandler(object):
  26.  
  27.      def update_preview_cb(self, file_chooser, preview):
  28.          filename = file_chooser.get_preview_filename()
  29. -        pixbuf = self.get_preview_image(filename)
  30. -        preview.set_from_pixbuf(pixbuf)
  31. -        file_chooser.set_preview_widget_active(pixbuf != None)
  32. -
  33. -    def get_preview_image(self, filename):
  34.          if filename:
  35. -            if os.path.splitext(filename)[1].lower() == ".ora":
  36. -                ora = zipfile.ZipFile(file(filename))
  37. -                try:
  38. -                    data = ora.read("Thumbnails/thumbnail.png")
  39. -                except KeyError:
  40. -                    return None
  41. -                loader = gtk.gdk.PixbufLoader("png")
  42. -                loader.write(data)
  43. -                loader.close()
  44. -                pixbuf = loader.get_pixbuf()
  45. -                return pixbuf
  46. +            pixbuf = helpers.get_freedesktop_thumbnail(filename)
  47. +            if pixbuf:
  48. +                # if pixbuf is smaller than 128px in width, copy it onto a transparent 128x128 pixbuf
  49. +                pixbuf = helpers.pixbuf_thumbnail(pixbuf, 128, 128, True)
  50. +                preview.set_from_pixbuf(pixbuf)
  51. +                file_chooser.set_preview_widget_active(True)
  52.              else:
  53. -                try:
  54. -                    #TODO do not scale images smaller than 256x256 up.
  55. -                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(filename, 256, 256)
  56. -                    return pixbuf
  57. -                except:
  58. -                    pass
  59. +                #TODO display "no preview available" image
  60. +                pass
  61.  
  62.      def open_cb(self, action):
  63.          if not self.confirm_destructive_action():
  64. diff --git a/lib/helpers.py b/lib/helpers.py
  65. index f6ca5af..767c845 100644
  66. --- a/lib/helpers.py
  67. +++ b/lib/helpers.py
  68. @@ -12,6 +12,10 @@ import colorsys, urllib, gc
  69.  from gtk import gdk # for gdk_pixbuf stuff
  70.  import mypaintlib
  71.  
  72. +import hashlib
  73. +import os
  74. +import zipfile
  75. +
  76.  try:
  77.      from json import dumps as json_dumps, loads as json_loads
  78.      print "builtin python 2.6 json support"
  79. @@ -111,26 +115,79 @@ def gdkpixbuf2numpy(pixbuf):
  80.      arr = pixbuf.get_pixels_array()
  81.      return mypaintlib.gdkpixbuf_numeric2numpy(arr)
  82.  
  83. -def pixbuf_thumbnail(src, w, h):
  84. +def get_freedesktop_thumbnail(filename):
  85.      """
  86. -    Creates a centered thumbnail of a gdk.pixbuf.
  87. +    Tries to fetch a thumbnail from ~/.thumbnails.
  88. +    If there is no thumbnail for the specified filename,
  89. +    a new thumbnail will be generated and stored according to the FDO spec.
  90. +    A thumbnail will also get regenerated if the MTimes (as in "modified")
  91. +    of thumbnail and original image do not match.
  92.      """
  93. -    src_w = src.get_width()
  94. -    src_h = src.get_height()
  95. -
  96. -    w2, h2 = src_w, src_h
  97. -    if w2 > w:
  98. -        h2 = h2*w/w2
  99. -        w2 = w
  100. -    if h2 > h:
  101. -        w2 = w2*h/h2
  102. -        h2 = h
  103. -    assert w2 <= w and h2 <= h
  104. -    src2 = src.scale_simple(w2, h2, gdk.INTERP_BILINEAR)
  105. -    
  106. -    dst = gdk.Pixbuf(gdk.COLORSPACE_RGB, False, 8, w, h)
  107. -    dst.fill(0xffffffff) # white background
  108. +    file_hash = hashlib.md5('file://'+filename).hexdigest()
  109. +    tb_filename_normal = os.path.join(os.path.expanduser('~/.thumbnails/normal'), file_hash) + '.png'
  110. +    tb_filename_large = os.path.join(os.path.expanduser('~/.thumbnails/large'), file_hash) + '.png'
  111. +    if os.path.isfile(tb_filename_normal):
  112. +        pixbuf = gdk.pixbuf_new_from_file(tb_filename_normal)
  113. +    elif os.path.isfile(tb_filename_large):
  114. +        pixbuf = gdk.pixbuf_new_from_file(tb_filename_large)
  115. +    else:
  116. +        pixbuf = None
  117. +    pixbuf = save_freedesktop_thumbnail(pixbuf, filename) # save thumbnail or regenerate if MTimes do not match
  118. +    return pixbuf
  119. +
  120. +def save_freedesktop_thumbnail(pixbuf, filename):
  121. +    """
  122. +    Saves a thumbnail according to the FDO spec.
  123. +    """
  124. +    file_hash = hashlib.md5('file://'+filename).hexdigest()
  125. +    tb_filename_normal = os.path.join(os.path.expanduser('~/.thumbnails/normal'), file_hash) + '.png'
  126. +    file_mtime = str(int(os.stat(filename).st_mtime))
  127. +    if (not os.path.isfile(tb_filename_normal)) or (not pixbuf) or (file_mtime != pixbuf.get_option("tEXt::Thumb::MTime")):
  128. +        pixbuf = get_pixbuf(filename)
  129. +        if pixbuf:
  130. +            pixbuf = scale_proportionally(pixbuf, 128,128)
  131. +            pixbuf.save(tb_filename_normal, 'png', {"tEXt::Thumb::MTime" : file_mtime, "tEXt::Thumb::URI" : ('file://'+filename)})
  132. +            return pixbuf
  133. +    else:
  134. +        return pixbuf
  135.  
  136. +def get_pixbuf(filename):
  137. +    try:
  138. +        if os.path.splitext(filename)[1].lower() == ".ora":
  139. +            ora = zipfile.ZipFile(file(filename))
  140. +            data = ora.read("Thumbnails/thumbnail.png")
  141. +            loader = gdk.PixbufLoader("png")
  142. +            loader.write(data)
  143. +            loader.close()
  144. +            pixbuf = loader.get_pixbuf()
  145. +            return pixbuf
  146. +        else:
  147. +            pixbuf = gdk.pixbuf_new_from_file(filename)
  148. +            return pixbuf;
  149. +    except:
  150. +        pass
  151. +
  152. +def scale_proportionally(pixbuf, w, h, shrink_only=True):
  153. +    width, height = pixbuf.get_width(), pixbuf.get_height()
  154. +    scale = min(w / float(width), h / float(height))
  155. +    if shrink_only and scale >= 1:
  156. +        return pixbuf
  157. +    new_width, new_height = int(width * scale), int(height * scale)
  158. +    if new_width > 0 and new_height > 0:
  159. +        pixbuf = pixbuf.scale_simple(new_width, new_height, gdk.INTERP_BILINEAR)
  160. +    return pixbuf
  161. +
  162. +def pixbuf_thumbnail(src, w, h, alpha=False):
  163. +    """
  164. +    Creates a centered thumbnail of a gdk.pixbuf.
  165. +    """
  166. +    src2 = scale_proportionally(src, w, h)
  167. +    w2, h2 = src2.get_width(), src2.get_height()
  168. +    dst = gdk.Pixbuf(gdk.COLORSPACE_RGB, alpha, 8, w, h)
  169. +    if alpha:
  170. +        dst.fill(0xffffff00) # transparent background
  171. +    else:
  172. +        dst.fill(0xffffffff) # white background
  173.      src2.copy_area(0, 0, w2, h2, dst, (w-w2)/2, (h-h2)/2)
  174.      return dst
  175.  
  176. --
  177. 1.7.0.4