-
Notifications
You must be signed in to change notification settings - Fork 0
/
thumb.py
157 lines (130 loc) · 5.01 KB
/
thumb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# $Id: thumb.py,v 1.4 2006/05/30 09:24:18 stephen Exp $
"""Template for a thumbnail generation program. This provides a Python
class which you extend to generate a thumbnail image for a type of file.
An example is included which generates thumbnails for text files. A more
useful implemetation is VideoThumbnail.
"""
import os, sys
import md5
import rox
# Class for thumbnail programs
class Thumbnailler:
"""Base class for programs which generate thumbnails. You should
override the method get_image() to create the image. You can also
override post_process_image()."""
def __init__(self, name, fname, use_wdir=False, debug=False):
"""Initialise the thumbnailler.
name - name of the program
fname - a string to use in generated temp file names
use_wdir - if true then use a temp directory to store files
debug - if false then suppress most error messages
"""
self.name=name
self.fname=fname
self.use_wdir=use_wdir
self.debug=debug
def run(self, inname, outname=None, rsize=96, jpeg=False):
"""Generate the thumbnail from the file
inname - source file
outname - path to store thumbnail image
rsize - maximum size of thumbnail (in either axis)
"""
if not outname:
uri='file://'+inname
tmp=md5.new(uri).digest()
leaf=''
for c in tmp:
leaf+='%02x' % ord(c)
outname=os.path.join(os.environ['HOME'], '.thumbnails',
'normal', leaf+'.png')
elif not os.path.isabs(outname):
outname=os.path.abspath(outname)
if self.use_wdir:
self.make_working_dir()
try:
img=self.get_image(inname, rsize)
ow=img.get_width()
oh=img.get_height()
img=self.process_image(img, rsize)
self.store_image(img, inname, outname, ow, oh, jpeg)
except:
self.report_exception()
if self.use_wdir:
self.remove_working_dir()
def get_image(self, inname, rsize):
"""Method you must define for your thumbnailler to do anything"""
raise _("Thumbnail not implemented")
def process_image(self, img, rsize):
"""Take the raw image and scale it to the correct size.
Returns the result of scaling img and passing it to
post_process_image()"""
ow=img.get_width()
oh=img.get_height()
if ow>oh:
s=float(rsize)/float(ow)
else:
s=float(rsize)/float(oh)
w=int(s*ow)
h=int(s*oh)
img=img.scale_simple(w, h, rox.g.gdk.INTERP_BILINEAR)
return self.post_process_image(img, w, h)
def post_process_image(self, img, w, h):
"""Perform some post-processing on the image.
img - gdk-pixbuf of the image
w - width
h - height
Return: modified image
The default implementation just returns the image unchanged."""
return img
def store_image(self, img, inname, outname, ow, oh, jpeg):
"""Store the thumbnail image it the correct location, adding
the extra data required by the thumbnail spec."""
s=os.stat(inname)
if jpeg:
img.save(outname+self.fname, 'jpeg',
{'quality': '77'})
else:
img.save(outname+self.fname, 'png',
{'tEXt::Thumb::Image::Width': str(ow),
'tEXt::Thumb::Image::Height': str(oh),
"tEXt::Thumb::Size": str(s.st_size),
"tEXt::Thumb::MTime": str(s.st_mtime),
'tEXt::Thumb::URI': rox.escape('file://'+inname),
'tEXt::Software': self.name})
os.rename(outname+self.fname, outname)
def make_working_dir(self):
"""Create the temporary directory and change into it."""
self.work_dir=os.path.join('/tmp',
'%s.%d' % (self.fname, os.getpid()))
#print work_dir
try:
os.makedirs(self.work_dir)
except:
self.report_exception()
self.work_dir=None
return
self.old_dir=os.getcwd()
os.chdir(self.work_dir)
def remove_working_dir(self):
"""Remove our temporary directory, after changing back to the
previous one"""
if not self.work_dir:
return
os.chdir(self.old_dir)
for f in os.listdir(self.work_dir):
path=os.path.join(self.work_dir, f)
try:
os.remove(path)
except:
self.report_exception()
try:
os.rmdir(self.work_dir)
except:
self.report_exception()
def report_exception(self):
"""Report an exception (if debug enabled)"""
if self.debug<1:
return
#exc=sys.exc_info()[:2]
#sys.stderr.write('%s: %s %s\n' % (sys.argv[0], exc[0], exc[1]))
rox.report_exception()