102 (name, exif[tag]) for tag, name in self.config.exif_tags if exif and tag in exif |
102 (name, exif[tag]) for tag, name in self.config.exif_tags if exif and tag in exif |
103 )) |
103 )) |
104 |
104 |
105 return self.metadata |
105 return self.metadata |
106 |
106 |
107 def render_image (self) : |
107 @lazy_load |
|
108 def thumb (self) : |
108 """ |
109 """ |
109 Renders new thumbnails/previews for this image. |
110 Load and update the thumbnail if needed |
110 |
|
111 Note: this does not check for the existance of the thumbs/previews subdirs! |
|
112 """ |
111 """ |
113 |
|
114 # load origional image |
|
115 img = self.load_image() |
|
116 |
112 |
117 # renderer to use |
113 # renderer to use |
118 # XXX: get from elsewhere |
114 # XXX: get from elsewhere |
119 render_machine = self.config.get_renderer() |
115 render_machine = self.config.get_renderer() |
120 |
116 |
121 # lazy-render both thumb and preview |
117 # render if needed |
122 self.thumb = render_machine.render_lazy(self |
118 return render_machine.render_lazy(self |
123 self.config.thumb_size, self.parent.load_thumb_dir.subnode(self.name) |
119 self.config.thumb_size, self.parent.load_thumb_dir.subnode(self.name) |
124 ) |
120 ) |
|
121 |
|
122 @lazy_load |
|
123 def preview (self) : |
|
124 """ |
|
125 Load and update the preview if needed |
|
126 """ |
125 |
127 |
126 self.preview = render_machine.render_lazy(self, |
128 # renderer to use |
|
129 # XXX: get from elsewhere |
|
130 render_machine = self.config.get_renderer() |
|
131 |
|
132 return render_machine.render_lazy(self, |
127 self.config.preview_size, self.parent.load_preview_dir.subnode(self.name) |
133 self.config.preview_size, self.parent.load_preview_dir.subnode(self.name) |
128 ) |
134 ) |
129 |
135 |
130 class Image (object) : |
|
131 def __init__ (self, dir, name) : |
|
132 # the image filename, e.g. DSC3948.JPG |
|
133 self.name = unicode(name) |
|
134 |
|
135 # the Folder object that we are in |
|
136 self.dir = dir |
|
137 |
|
138 # the relative path from the root to us |
|
139 self.path = dir.pathFor(self.name) |
|
140 |
|
141 # the basename+ext, e.g. DSCR3948, .JPG |
|
142 self.base_name, self.ext = os.path.splitext(self.name) |
|
143 |
|
144 # our user-friendly title |
|
145 self.title = self.name |
|
146 |
|
147 # our long-winded description |
|
148 self.descr = '' |
|
149 |
|
150 # the image before and after us, both may be None |
|
151 self.prev = self.next = None |
|
152 |
|
153 # the image-relative names for the html page, thumb and preview images |
|
154 self.html_name = self.name + ".html" |
|
155 self.thumb_name = utils.url_join(settings.THUMB_DIR, self.name) |
|
156 self.preview_name = utils.url_join(settings.PREVIEW_DIR, self.name) |
|
157 |
|
158 # the root-relative paths to the html page, thumb and preview images |
|
159 self.html_path = self.dir.pathFor(self.html_name) |
|
160 self.thumb_path = self.dir.pathFor(settings.THUMB_DIR, self.name) |
|
161 self.preview_path = self.dir.pathFor(settings.PREVIEW_DIR, self.name) |
|
162 |
|
163 # |
|
164 # Figured out after prepare |
|
165 # |
|
166 |
|
167 # (w, h) tuple |
|
168 self.img_size = None |
|
169 |
|
170 # the ShortURL code for this image |
|
171 self.shorturl_code = None |
|
172 |
|
173 # EXIF data |
|
174 self.exif_data = {} |
|
175 |
|
176 # what to use in the rendered templates, intended to be overridden by subclasses |
|
177 self.series_act = "add" |
|
178 self.series_verb = "Add to" |
|
179 |
|
180 def getObjInfo (self) : |
|
181 """ |
|
182 Metadata for shorturl2.db |
|
183 """ |
|
184 return 'img', self.dir.path, self.name |
|
185 |
|
186 def breadcrumb (self) : |
|
187 """ |
|
188 Returns a [(fname, title)] list of this image's parents |
|
189 """ |
|
190 |
|
191 return self.dir.breadcrumb(forImg=self) + [(self.html_name, self.title)] |
|
192 |
|
193 def render (self) : |
|
194 """ |
|
195 Write out the .html file |
|
196 """ |
|
197 |
|
198 # stat the image file to get the filesize and mtime |
|
199 st = os.stat(self.path) |
|
200 |
|
201 self.filesize = st.st_size |
|
202 self.timestamp = st.st_mtime |
|
203 |
|
204 # open the image in PIL to get image attributes + generate thumbnails |
|
205 img = PIL.Image.open(self.path) |
|
206 |
|
207 self.img_size = img.size |
|
208 |
|
209 for out_path, geom in ((self.thumb_path, settings.THUMB_GEOM), (self.preview_path, settings.PREVIEW_GEOM)) : |
|
210 # if it doesn't exist, or it's older than the image itself, generate |
|
211 if utils.mtime(out_path) < self.timestamp : |
|
212 log.info("render [%sx%s]", geom[0], geom[1], wait=True) |
|
213 |
|
214 # XXX: is this the most efficient way to do this? It seems slow |
|
215 out_img = img.copy() |
|
216 out_img.thumbnail(geom, resample=True) |
|
217 out_img.save(out_path) |
|
218 |
|
219 log.done() |
|
220 |
|
221 # look for the metadata file |
|
222 title_path = self.dir.pathFor(self.base_name + '.txt') |
|
223 |
|
224 self.title, self.descr = utils.readTitleDescr(title_path) |
|
225 |
|
226 if not self.title : |
|
227 self.title = self.name |
|
228 |
|
229 if utils.mtime(self.html_path) < self.timestamp : |
|
230 log.info("render %s.html", self.name) |
|
231 |
|
232 # parse the exif data from the file |
|
233 try : |
|
234 self.exif_data = dexif.parse_exif(self.path) |
|
235 except dexif.ExifError, message: |
|
236 log.warning("Reading EXIF data for %s failed: %s" % (self.filename, message)) |
|
237 self.exif_data = {} |
|
238 |
|
239 |
|
240 image_tpl.render_to(self.html_path, |
|
241 stylesheet_url = self.dir.inRoot('style.css'), |
|
242 title = self.title, |
|
243 breadcrumb = self.breadcrumb(), |
|
244 |
|
245 prev = self.prev, |
|
246 next = self.next, |
|
247 img = self, |
|
248 |
|
249 description = self.descr, |
|
250 |
|
251 filename = self.name, |
|
252 img_size = self.img_size, |
|
253 file_size = self.filesize, |
|
254 timestamp = self.timestamp, |
|
255 exif_data = self.exif_data, |
|
256 |
|
257 shorturl = self.dir.inRoot('s', self.shorturl_code), |
|
258 shorturl_code = self.shorturl_code, |
|
259 |
|
260 series_url = self.dir.inRoot('series/%s/%s' % (self.series_act, self.shorturl_code)), |
|
261 series_verb = self.series_verb, |
|
262 ) |
|
263 |
|
264 def __str__ (self) : |
|
265 return "Image `%s' in `%s'" % (self.name, self.dir.path) |
|
266 |
|