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 Config is a class containing all the configuration of the imagizer suite.
29 Technically it is a Borg (design Pattern) so every instance of Config has exactly the same contents.
30 """
31
32 import os, locale, logging, ConfigParser
33 installdir = os.path.dirname(os.path.abspath(__file__))
34
35
36 if os.name == 'nt':
37 ConfFile = [os.path.join(os.getenv("ALLUSERSPROFILE"), "imagizer.conf"), os.path.join(os.getenv("USERPROFILE"), "imagizer.conf"), "imagizer.conf"]
38 elif os.name == 'posix':
39 ConfFile = ["/etc/imagizer.conf", os.path.join(os.getenv("HOME"), ".imagizer"), ".imagizer"]
40 else:
41 raise OSError("Your platform does not seem to be an Unix nor a M$ Windows.\nI am sorry but the exiftran binary is necessary to run selector, and exiftran is probably not available for you plateform. If you have exiftran installed, please contact the developper to correct that bug, kieffer at terre-adelie dot org")
42
43
44
45
46
47
49 """this class is a Borg : always returns the same values regardless to the instance of the object"""
50 __shared_state = {}
52 """
53 This is a Borg, so the constructor is more or less empty
54 """
55 self.__dict__ = self.__shared_state
56 if len(self.__dict__) < 5:
57 logging.debug("Config: initializition of the class")
58 self.ScreenSize = 500
59 self.NbrPerPage = 20
60 self.PagePrefix = "page"
61 self.TrashDirectory = "Trash"
62 self.SelectedDirectory = "Selected"
63 self.Selected_save = ".selected-photos"
64 self.Extensions = [".jpg", ".jpeg", ".jpe", ".jfif"]
65 self.RawExtensions = [".cr2", ".arw", ".mrw", ".dng", ".pef", ".nef"]
66 self.AutoRotate = False
67 self.DefaultMode = "664"
68 self.DefaultRepository = os.getcwd()
69 self.CommentFile = "index.desc"
70 self.Interpolation = 1
71 self.DefaultFileMode = int(self.DefaultMode, 8)
72 self.DefaultDirMode = self.DefaultFileMode + 3145
73 self.Filigrane = False
74 self.FiligraneSource = os.path.join(installdir, "signature.png")
75 self.FiligranePosition = 5
76 self.FiligraneQuality = 75
77 self.FiligraneOptimize = False
78 self.FiligraneProgressive = False
79 self.WebDirIndexStyle = "list"
80 self.MediaSize = 680
81 self.Burn = "grave-rep $Selected"
82 self.WebServer = "cp -r $Selected/* $WebRepository && generator"
83 self.WebRepository = "/var/www/imagizer"
84 self.Locale, self.Coding = locale.getdefaultlocale()
85 self.ExportSingleDir = False
86 self.GraphicMode = "Normal"
87 self.WebPageAnchor = "end"
88 self.SlideShowDelay = 5.0
89 self.SlideShowType = "chronological"
90 self.SynchronizeRep = "user@host:/mnt/photo"
91 self.SynchronizeType = "Newer"
92 self.ImageCache = 100
93 self.ImageWidth = None
94 self.ImageHeight = None
95 self.DEBUG = None
96 self.Gimp = "gimp"
97 self.Dcraw = "dcraw -w -c"
98 self.Thumbnails = {
99 "Size":160,
100 "Suffix": "thumb",
101 "Interpolation":1,
102 "Progressive":False,
103 "Optimize":False,
104 "ExifExtraction":True,
105 "Quality": 75
106 }
107 self.ScaledImages = {
108 "Size":800,
109 "Suffix": "scaled",
110 "Interpolation":1,
111 "Progressive":False,
112 "Optimize":False,
113 "ExifExtraction":False,
114 "Quality": 75
115 }
116
117 - def load(self, filenames):
118 """retrieves the the default options, if the filenames does not exist, uses the default instead
119 @param filenames: list of filename
120 @type filenames: list of strings or unicode
121 """
122 logging.debug("Config.load")
123 configparser = ConfigParser.ConfigParser()
124 files = []
125 for i in filenames:
126 if os.path.isfile(i):files.append(i)
127 if len(files) == 0:
128 logging.warning("No configuration file found. Falling back on defaults")
129 return
130
131 configparser.read(files)
132 for i in configparser.items("Selector"):
133 j = i[0]
134 if j == "ScreenSize".lower(): self.ScreenSize = int(i[1])
135 elif j == "Interpolation".lower(): self.Interpolation = int(i[1])
136 elif j == "PagePrefix".lower(): self.PagePrefix = i[1]
137 elif j == "NbrPerPage".lower(): self.NbrPerPage = int(i[1])
138 elif j == "TrashDirectory".lower(): self.TrashDirectory = i[1]
139 elif j == "SelectedDirectory".lower():self.SelectedDirectory = i[1]
140 elif j == "Selected_save".lower(): self.Selected_save = i[1]
141 elif j == "AutoRotate".lower(): self.AutoRotate = configparser.getboolean("Selector", "AutoRotate")
142 elif j == "Filigrane".lower(): self.Filigrane = configparser.getboolean("Selector", "Filigrane")
143 elif j == "FiligraneSource".lower(): self.FiligraneSource = i[1]
144 elif j == "FiligranePosition".lower():self.FiligranePosition = int(i[1])
145 elif j == "FiligraneQuality".lower(): self.FiligraneQuality = int(i[1])
146 elif j == "FiligraneOptimize".lower():self.FiligraneOptimize = configparser.getboolean("Selector", "FiligraneOptimize")
147 elif j == "FiligraneProgressive".lower():self.FiligraneProgressive = configparser.getboolean("Selector", "FiligraneProgressive")
148 elif j == "CommentFile".lower(): self.CommentFile = i[1]
149 elif j == "WebDirIndexStyle".lower(): self.WebDirIndexStyle = i[1]
150 elif j == "DefaultFileMode".lower():
151 self.DefaultFileMode = int(i[1], 8)
152 self.DefaultDirMode = self.DefaultFileMode + 3145
153 elif j == "RawExtensions".lower(): self.RawExtensions = i[1].split()
154 elif j == "Extensions".lower(): self.Extensions = i[1].split()
155 elif j == "DefaultRepository".lower():self.DefaultRepository = i[1]
156 elif j == "MediaSize".lower(): self.MediaSize = float(i[1])
157 elif j == "Burn".lower(): self.Burn = i[1]
158 elif j == "WebServer".lower(): self.WebServer = i[1]
159 elif j == "WebRepository".lower(): self.WebRepository = i[1]
160 elif j == "Locale".lower(): self.Locale = i[1]
161 elif j == "Coding".lower(): self.Coding = i[1]
162 elif j == "ExportSingleDir".lower(): self.ExportSingleDir = configparser.getboolean("Selector", "ExportSingleDir")
163 elif j == "WebPageAnchor".lower(): self.WebPageAnchor = i[1]
164 elif j == "SlideShowDelay".lower(): self.SlideShowDelay = float(i[1])
165 elif j == "SlideShowType".lower(): self.SlideShowType = i[1]
166 elif j == "SynchronizeRep".lower(): self.SynchronizeRep = i[1]
167 elif j == "SynchronizeType".lower(): self.SynchronizeType = i[1]
168 elif j == "ImageCache".lower(): self.ImageCache = int(i[1])
169 elif j == "ImageWidth".lower(): self.ImageWidth = int(i[1])
170 elif j == "ImageHeight".lower(): self.ImageHeight = int(i[1])
171 elif j == "gimp".lower(): self.Gimp = i[1]
172 elif j == "dcraw".lower(): self.Dcraw = i[1]
173 else: logging.warning("Config.load: unknown key %s" % j)
174
175
176 for k in ["ScaledImages", "Thumbnails"]:
177 try:
178 dico = eval(k)
179 except:
180 dico = {}
181 for i in configparser.items(k):
182 j = i[0]
183 if j == "Size".lower():dico["Size"] = int(i[1])
184 elif j == "Suffix".lower():dico["Suffix"] = i[1]
185 elif j == "Interpolation".lower():dico["Interpolation"] = int(i[1])
186 elif j == "Progressive".lower():dico["Progressive"] = configparser.getboolean(k, "Progressive")
187 elif j == "Optimize".lower():dico["Optimize"] = configparser.getboolean(k, "Optimize")
188 elif j == "ExifExtraction".lower():dico["ExifExtraction"] = configparser.getboolean(k, "ExifExtraction")
189 elif j == "Quality".lower():dico["Quality"] = int(i[1])
190 exec("self.%s=dico" % k)
191
193 logging.debug("Config.__repr__")
194 listtxt = ["",
195 "Size on the images on the Screen: %s pixels in the largest dimension" % self.ScreenSize,
196 "Page prefix:\t\t\t %s" % self.PagePrefix,
197 "Number of images per page:\t %s" % self.NbrPerPage,
198 "Use Exif for Auto-Rotate:\t %s" % self.AutoRotate,
199 "Default mode for files (octal):\t %o" % self.DefaultFileMode,
200 "JPEG extensions:\t\t %s" % self.Extensions,
201 "Default photo repository:\t %s" % self.DefaultRepository,
202 "Add signature for exported images:%s" % self.Filigrane,
203 "Backup media size (CD,DVD):\t %s MByte" % self.MediaSize,
204 "Scaled imagesSize:\t\t %s pixels in the largest dimension" % self.ScaledImages["Size"],
205 "Thumbnail Size:\t\t\t %s pixels in the largest dimension" % self.Thumbnails["Size"],
206 "Caching of %s images " % self.ImageCache
207 ]
208 return os.linesep.join(listtxt)
209
210
212 """
213 Print out the
214 """
215 logging.debug("Config.printConfig")
216 logging.info(self.__repr__())
217
218
220 """
221 Saves the default options to file
222
223 @param filename: name of the file to save the configuration to
224 @type filename: string or unicode
225 """
226 logging.debug("Config.saveConfig")
227 lsttxt = ["[Selector]",
228 "#Size of the image on the Screen, by default", "ScreenSize: %s" % self.ScreenSize, "",
229 "#Downsampling quality [0=nearest, 1=tiles, 2=bilinear, 3=hyperbolic]", "Interpolation: %s" % self.Interpolation, "",
230 "#Page prefix (used when there are too many images per day to fit on one web page)", "PagePrefix: %s" % self.PagePrefix, "",
231 "#Maximum number of images per web page", "NbrPerPage: %s" % self.NbrPerPage, "",
232 "#Trash sub-directory", "TrashDirectory: %s" % self.TrashDirectory, "",
233 "#Selected/processed images sub-directory", "SelectedDirectory: %s" % self.SelectedDirectory, "",
234 "#File containing the list of selected but unprocessed images", "Selected_save: %s" % self.Selected_save, "",
235 "#Use Exif data for auto-rotation of the images (canon cameras mainly)", "AutoRotate: %s" % self.AutoRotate, "",
236 "#Default mode for files (in octal)", "DefaultFileMode: %o" % self.DefaultFileMode, "",
237 "#Default JPEG extensions", "Extensions: " + " ".join(self.Extensions), "",
238 "#Default Raw images extensions", "RawExtensions: " + " ".join(self.RawExtensions), "",
239 "#Default photo repository", "DefaultRepository: %s" % self.DefaultRepository, "",
240 "#Size of the backup media (in MegaByte)", "MediaSize: %s" % self.MediaSize, "",
241 "#Add signature to web published images", "Filigrane: %s" % self.Filigrane, "",
242 "#File containing the image of the signature for the filigrane", "FiligraneSource: %s" % self.FiligraneSource, "",
243 "#Position of the filigrane : 0=center 12=top center 1=upper-right 3=center-right...", "FiligranePosition: %s" % self.FiligranePosition, "",
244 "#Quality of the saved image in filigrane mode (JPEG quality)", "FiligraneQuality: %s" % self.FiligraneQuality, "",
245 "#Optimize the filigraned image (2 pass JPEG encoding)", "FiligraneOptimize: %s" % self.FiligraneOptimize, "",
246 "#Progressive JPEG for saving filigraned images", "FiligraneProgressive: %s" % self.FiligraneProgressive, "",
247 "#File containing the description of the day in each directory", "CommentFile: %s" % self.CommentFile, "",
248 "#Style of the dirindex web pages, either <<list>> or <<table>>, the latest includes thumbnail photos", "WebDirIndexStyle: %s" % self.WebDirIndexStyle, "",
249 "#System command to use to burn a CD or a DVD", "# $Selected will be replaced by the directory where the files are", "Burn: %s" % self.Burn, "",
250 "#System command to copy the selection to the server", "# $Selected will be replaced by the directory where the files are", "# $WebRepository will be replaced by the directory of the root of generator", "WebServer: %s" % self.WebServer, "",
251 "#The location of the root of generator", "WebRepository: %s" % self.WebRepository, "",
252 "#The localization code, fr_FR is suggested for unix or FR for win32", "Locale: %s" % self.Locale, "",
253 "#Default encoding for text files, latin-1 is suggested,UTF-8 should be possible", "Coding: %s" % self.Coding, "",
254 "#All selected photos should be exported in a single directory", "ExportSingleDir: %s" % self.ExportSingleDir, "",
255 "#Where should the dirindex page start-up ? [begin/end] ", "WebPageAnchor: %s" % self.WebPageAnchor, "",
256 "#Delay between imges in the slideshow? ", "SlideShowDelay: %s" % self.SlideShowDelay, "",
257 "#Type of slideshow : chronological, anti-chronological or random ?", "SlideShowType: %s" % self.SlideShowType, "",
258 "#Remote repository to synchronize with (rsync like)", "SynchronizeRep: %s" % self.SynchronizeRep, "",
259 "#Synchronization type, acceptable values are Newer, Older, Selected and All", "SynchronizeType: %s" % self.SynchronizeType, "",
260 "#Allow the creation of a Cache of images with the given size in number of images", "ImageCache: %s" % self.ImageCache, "",
261 "#Gnu Image Manipulation Program (GIMP) path to executable", "Gimp: %s" % self.Gimp, "",
262 "#Digital Camera Raw (dcraw) extraction program and option (-w -c is suggested)", "Dcraw: %s" % self.Dcraw, ""]
263 if self.ImageWidth is not None:
264 lsttxt += ["#Width of the last image displayed ... should not be modified", "ImageWidth:%s" % self.ImageWidth, ""]
265 if self.ImageHeight is not None:
266 lsttxt += ["#Height of the last image displayed ... should not be modified", "ImageHeight:%s" % self.ImageHeight, ""]
267
268
269 for i in ["ScaledImages", "Thumbnails"]:
270 lsttxt += ["[%s]" % i, ""]
271 j = eval("self.%s" % i)
272 lsttxt += ["#%s size" % i, "Size: %s" % j["Size"], ""]
273 lsttxt += ["#%s suffix" % i, "Suffix: %s" % j["Suffix"], ""]
274 lsttxt += ["#%s downsampling quality [0=nearest, 1=antialias 2=bilinear, 3=bicubic]" % i, "Interpolation: %s" % j["Interpolation"], ""]
275 lsttxt += ["#%s progressive JPEG files" % i, "Progressive: %s" % j["Progressive"], ""]
276 lsttxt += ["#%s optimized JPEG (2 pass encoding)" % i, "Optimize: %s" % j["Optimize"], ""]
277 lsttxt += ["#%s quality (in percent)" % i, "Quality: %s" % j["Quality"], ""]
278 lsttxt += ["#%s image can be obtained by Exif extraction ?" % i, "ExifExtraction: %s" % j["ExifExtraction"], ""]
279 w = open(filename, "w")
280 w.write(os.linesep.join(lsttxt))
281 w.close()
282 if self.DEBUG:
283 logging.info("Configuration saved to file %s" % filename)
284