Mercurial > moin > extensions
annotate data/plugin/macro/Image.py @ 275:2a92ddf8a7c8
Image._get_description: strip whitespae from image name
author  Reimar Bauer <rb.proj AT googlemail DOT com> 

date  Tue, 16 Sep 2008 11:48:52 +0200 
parents  1e3e876e38fb 
children  03071c3569d8 
rev  line source 

262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

1 # * coding: iso88591 * 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

2 """ 
267
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

3 MoinMoin  Image rendering support class and a simple macro using it. 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

4 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

5 Features: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

6 * rendering (and caching) of thumbnails/webnails/originals 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

7 * gives readytouse image urls 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

8 * autorotation based on EXIF information 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

9 * determines creation time from EXIF or file system 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

10 * easy access to some EXIF data (cached) 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

11 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

12 Requires PIL and ExifTags libs. 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

13 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

14 @copyright: 2008 MoinMoin:ThomasWaldmann, 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

15 2008 MoinMoin:ReimarBauer 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

16 @license: GNU GPL, see COPYING for details. 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

17 """ 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

18 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

19 import os, time 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

20 import StringIO 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

21 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

22 from MoinMoin import caching, wikiutil 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

23 from MoinMoin.action import AttachFile, cache 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

24 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

25 try: 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

26 from PIL import Image as PILImage 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

27 except ImportError: 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

28 PILImage = None 
264
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

29 try: 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

30 from PIL import IptcImagePlugin as PILIptc 
264
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

31 except ImportError: 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

32 PILIptc = None 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

33 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

34 try: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

35 import ExifTags 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

36 except ImportError: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

37 ExifTags = None 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

38 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

39 class Image(object): 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

40 # predefined sizes (width, height)  use them if you like: 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

41 WEBNAIL_SIZE = (640, 480) 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

42 THUMBNAIL_SIZE = (128, 128) 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

43 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

44 # we don't process and cache all EXIF infos, but just these: 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

45 EXIF_CACHED = set(['DateTimeOriginal', 'TimeZoneOffset', 'Orientation', ]) 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

46 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

47 def __init__(self, request, 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

48 item_name, # PageName/AttachName for now, later this is just the item name 
267
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

49 headline=None, 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

50 caption=None, 
269
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

51 raw=None, 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

52 ): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

53 self.request = request 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

54 self.pagename, self.attachname = item_name.rsplit('/', 1) 
269
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

55 self.raw = raw 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

56 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

57 # cached property values: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

58 self.__filename = None 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

59 self.__content_type = None 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

60 self.__cache_key = None 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

61 self.__image = None 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

62 self.__exif = None 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

63 self.__ctime = None 
267
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

64 self.__headline = headline 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

65 self.__caption = caption 
269
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

66 self.__description = self.attachname 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

67 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

68 def _get_description(self): 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

69 quotes = self.raw.split('\n') 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

70 quotes = [quote.strip() for quote in quotes] 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

71 quotes = [quote[2:] for quote in quotes if quote.startswith('* ')] 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

72 image_alias = self.attachname 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

73 for line in quotes: 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

74 if line.startswith('[[') and line.endswith(']]'): 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

75 img, alias = line[2:2].split('', 1) 
275
2a92ddf8a7c8
Image._get_description: strip whitespae from image name
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
269
diff
changeset

76 if img.strip() == self.attachname: 
269
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

77 self.__description = alias.strip() 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

78 break 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

79 return self.__description 
1e3e876e38fb
moved readout of description from text_x_arnica to Image
Reimar Bauer <rb.proj AT googlemail DOT com>
parents:
267
diff
changeset

80 description = property(_get_description) 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

81 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

82 def _get_filename(self): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

83 if self.__filename is None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

84 self.__filename = AttachFile.getFilename(self.request, self.pagename, self.attachname) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

85 return self.__filename 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

86 _filename = property(_get_filename) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

87 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

88 def _get_content_type(self): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

89 if self.__content_type is None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

90 self.__content_type = wikiutil.MimeType(filename=self._filename).mime_type() 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

91 return self.__content_type 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

92 content_type = property(_get_content_type) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

93 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

94 def _get_image(self): 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

95 if self.__image is None and PILImage is not None: 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

96 self.__image = PILImage.open(self._filename) 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

97 return self.__image 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

98 image = property(_get_image) # the original image (PIL Image object) or None 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

99 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

100 def _get_cache_key(self): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

101 if self.__cache_key is None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

102 self.__cache_key = cache.key(self.request, itemname=self.pagename, attachname=self.attachname) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

103 return self.__cache_key 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

104 _cache_key = property(_get_cache_key) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

105 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

106 def _get_exif_data(self): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

107 """ return exif data for this image, use a cache for them """ 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

108 if self.__exif is None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

109 key = self._cache_key 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

110 exif_cache = caching.CacheEntry(self.request, 'exif', key, 'wiki', 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

111 use_pickle=True, do_locking=False) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

112 if not exif_cache.exists(): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

113 # we don't want to cache all EXIF data, just a few interesting values 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

114 try: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

115 exif_data = {} 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

116 if self.image is not None: # we have PIL 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

117 for tag, value in self.image._getexif().items(): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

118 tag_name = ExifTags.TAGS.get(tag) 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

119 if tag_name in self.EXIF_CACHED: 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

120 exif_data[tag_name] = value 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

121 try: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

122 time_str = exif_data['DateTimeOriginal'] 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

123 tm = time.strptime(time_str, "%Y:%m:%d %H:%M:%S") 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

124 t = time.mktime(tm) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

125 try: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

126 tz_str = exif_data['TimeZoneOffset'] 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

127 tz_offset = int(tz_str) * 3600 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

128 except: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

129 tz_offset = 0 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

130 # mktime is inverse function of (our) localtime, adjust by time.timezone 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

131 t = time.timezone + tz_offset 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

132 except: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

133 t = 0 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

134 exif_data['DateTimeOriginal'] = t 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

135 except (IOError, AttributeError): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

136 exif_data = {} 
264
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

137 try: 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

138 iptc_data = {} 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

139 if self.image is not None and PILIptc: # we have PIL and the IPTC plugin 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

140 iptc = PILIptc.getiptcinfo(self.image) or {} 
264
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

141 for name, key in [ 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

142 ('headline', (2, 105)), 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

143 ('caption', (2, 120)), 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

144 ('copyright', (2, 116)), 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

145 ('keywords', (2, 25)), ]: 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

146 try: 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

147 iptc_data[name] = iptc[key] 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

148 except KeyError: 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

149 pass 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

150 except: 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

151 iptc_data = {} 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

152 cache_data = (exif_data, iptc_data) 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

153 exif_cache.update(cache_data) 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

154 self.__exif, self.__iptc = cache_data 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

155 else: 
264
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

156 self.__exif, self.__iptc = exif_cache.content() 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

157 return self.__exif, self.__iptc 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

158 exif = property(lambda self: self._get_exif_data()[0]) # dict of preprocessed EXIF data (string > value) 
b7e7be4340b0
MoinImage: add IPTC support
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
263
diff
changeset

159 iptc = property(lambda self: self._get_exif_data()[1]) # dict of preprocessed IPTC data (string > value) 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

160 
267
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

161 def _get_headline(self): 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

162 if self.__headline is None: 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

163 self.__headline = self.iptc.get('headline', u'') 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

164 return self.__headline 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

165 headline = property(_get_headline) 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

166 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

167 def _get_caption(self): 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

168 if self.__caption is None: 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

169 self.__caption = self.iptc.get('caption', u'') 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

170 return self.__caption 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

171 caption = property(_get_caption) 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

172 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

173 def _get_ctime(self): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

174 """ return creation time of image (either from EXIF or file date) as UNIX timestamp """ 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

175 if self.__ctime is None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

176 try: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

177 ctime = self.exif['DateTimeOriginal'] 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

178 except KeyError: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

179 ctime = os.path.getctime(self._filename) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

180 self.__ctime = ctime 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

181 return self.__ctime 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

182 ctime = property(_get_ctime) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

183 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

184 def _transform(self, size=None, content_type=None, transpose_op=None): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

185 """ resize to new size (optional), transpose according to exif infos, 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

186 return data as content_type (default: same ct as original image) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

187 """ 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

188 if content_type is None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

189 content_type = self.content_type 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

190 if content_type == 'image/jpeg': 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

191 output_type = 'JPEG' 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

192 elif content_type == 'image/png': 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

193 output_type = 'PNG' 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

194 elif content_type == 'image/gif': 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

195 output_type = 'GIF' 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

196 else: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

197 raise ValueError("content_type %r not supported" % content_type) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

198 image = self.image 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

199 if image is not None: # we have PIL 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

200 try: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

201 # if we have EXIF data, we can transpose (e.g. rotate left), 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

202 # so the rendered image is correctly oriented: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

203 transpose_op = transpose_op or self.exif['Orientation'] 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

204 except KeyError: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

205 transpose_op = 1 # no change 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

206 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

207 if size is not None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

208 image = image.copy() # create copy first as thumbnail works inplace 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

209 image.thumbnail(size, PILImage.ANTIALIAS) 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

210 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

211 transpose_func = { 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

212 1: lambda image: image, 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

213 2: lambda image: image.transpose(PILImage.FLIP_LEFT_RIGHT), 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

214 3: lambda image: image.transpose(PILImage.ROTATE_180), 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

215 4: lambda image: image.transpose(PILImage.FLIP_TOP_BOTTOM), 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

216 5: lambda image: image.transpose(PILImage.ROTATE_90).transpose(PILImage.FLIP_TOP_BOTTOM), 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

217 6: lambda image: image.transpose(PILImage.ROTATE_270), 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

218 7: lambda image: image.transpose(PILImage.ROTATE_90).transpose(PILImage.FLIP_LEFT_RIGHT), 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

219 8: lambda image: image.transpose(PILImage.ROTATE_90), 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

220 } 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

221 image = transpose_func[transpose_op](image) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

222 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

223 buf = StringIO.StringIO() 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

224 image.save(buf, output_type) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

225 buf.flush() # XXX needed? 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

226 data = buf.getvalue() 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

227 buf.close() 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

228 else: # XXX what to do without PIL? 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

229 data = '' 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

230 return content_type, data 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

231 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

232 def url(self, size=None): 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

233 """ return a cache url for a rendering of this image with specified size  
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

234 the code automatically makes sure that the cache contains that rendering. 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

235 If size is None, it gives a url for the full image size rendering. 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

236 Otherwise, size has to be a tuple (w, h)  if you like, you can use 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

237 these class level constant sizes: 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

238 WEBNAIL_SIZE  medium size, one of those likely to fit in a browser window 
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

239 THUMBNAIL_SIZE  small size, for showing collections 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

240 """ 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

241 request = self.request 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

242 content_type = self.content_type 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

243 if size is None: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

244 size_str = 'orig' 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

245 else: 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

246 size_str = '%d_%d' % size 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

247 key = '%s_%s_%s' % (content_type.replace('/', '_'), size_str, self._cache_key) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

248 if not cache.exists(request, key): 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

249 content_type, data = self._transform(size=size, content_type=content_type) 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

250 cache.put(request, key, data, content_type=content_type) 
263
448a086d840c
MoinImage: simplify API
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
262
diff
changeset

251 return cache.url(request, key) 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

252 
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

253 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

254 def macro_Image(macro, itemname=wikiutil.required_arg(unicode), width=9999, height=9999, alt=u''): 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

255 """ Embed an Image into a wiki page. 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

256 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

257 We use a very high default value for width and height, because PIL will calculate the 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

258 image dimensions to not be larger than (width, height) and also not be larger than 
266
3e4eaae2f7df
add support for just giving the attachment name, fix typo
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
265
diff
changeset

259 the original image. Thus, by not giving width or height, you'll get the original image, 
265
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

260 and if you specify width or height you will get an image of that width or that height. 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

261 
37b96db69d0e
MoinImage macro: renamed to Image
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
264
diff
changeset

262 <<Image(PageName/attachname,width=100,alt="sample image")>> 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

263 """ 
266
3e4eaae2f7df
add support for just giving the attachment name, fix typo
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
265
diff
changeset

264 if '/' not in itemname: 
3e4eaae2f7df
add support for just giving the attachment name, fix typo
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
265
diff
changeset

265 itemname = macro.formatter.page.page_name + '/' + itemname 
267
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

266 img = Image(macro.request, itemname, caption=alt) 
de2f265a9ac5
Image: add headline/caption support, read from iptc data if not given
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
266
diff
changeset

267 return macro.formatter.image(src=img.url((width, height)), alt=img.caption) 
262
c605998e1123
added MoinImage class and test macro
Thomas Waldmann <tw AT waldmannedv DOT de>
parents:
diff
changeset

268 