def init_from_options(self, options): """Populates the UI from options.""" self.iphoto_library.set(options.iphoto) self.export_folder.set(options.export) self.albums.set(su.fsdec(options.albums)) self.events.set(su.fsdec(options.events)) self.smarts.set(su.fsdec(options.smarts)) self.foldertemplate.set(su.unicode_string(options.foldertemplate)) self.nametemplate.set(su.unicode_string(options.nametemplate)) self.captiontemplate.set(su.unicode_string(options.captiontemplate)) self.update_var.set(_int_from_bool(options.update)) self.delete_var.set(_int_from_bool(options.delete)) self.originals_var.set(_int_from_bool(options.originals)) self.link_var.set(_int_from_bool(options.link)) self.folder_hints_var.set(_int_from_bool(options.folderhints)) self.faces_var.set(_int_from_bool(options.faces) and self.exiftool) self.face_keywords_var.set(_int_from_bool(options.face_keywords) and self.exiftool) self.face_albums_var.set(_int_from_bool(options.facealbums)) self.face_albums_text.set(options.facealbum_prefix) if options.iptc and self.exiftool: self.iptc_var.set(1) if options.iptc == 2: self.iptc_all_var.set(1) self.gps_var.set(_int_from_bool(options.gps) and self.exiftool)
def process_albums(self, albums, album_types, folder_prefix, includes, excludes, options, matched=False): """Walks trough an iPhoto album tree, and discovers albums (directories).""" entries = 0 include_pattern = re.compile(su.fsdec(includes)) exclude_pattern = None if excludes: exclude_pattern = re.compile(su.fsdec(excludes)) # first, do the sub-albums for sub_album in albums: if self._check_abort(): return sub_name = sub_album.name if not sub_name: print "Found an album with no name: " + sub_album.albumid sub_name = "xxx" # check the album type if sub_album.albumtype == "Folder": sub_matched = matched if include_pattern.match(sub_name): sub_matched = True self.process_albums( sub_album.albums, album_types, folder_prefix + imageutils.make_foldername(sub_name) + "/", includes, excludes, options, sub_matched) continue elif (sub_album.albumtype == "None" or not sub_album.albumtype in album_types): # print "Ignoring " + sub_album.name + " of type " + \ # sub_album.albumtype continue if not matched and not include_pattern.match(sub_name): continue if exclude_pattern and exclude_pattern.match(sub_name): continue sub_name = folder_prefix + imageutils.make_foldername(sub_name) sub_name = self._find_unused_folder(sub_name) # first, do the sub-albums if self.process_albums(sub_album.albums, album_types, folder_prefix, includes, excludes, options, matched) > 0: entries += 1 # now the album itself picture_directory = PicasaAlbum(sub_name, sub_album) if picture_directory.add_iphoto_images(sub_album.images, options) > 0: self.named_folders[sub_name] = picture_directory entries += 1 return entries
def check_directories(self, directory, rel_path, album_directories, options): """Checks an export directory for obsolete files.""" if options.ignore: exclude_pattern = re.compile(su.fsdec(options.ignore)) if exclude_pattern.match(os.path.split(directory)[1]): return True if not os.path.exists(directory): return True contains_albums = False for f in su.os_listdir_unicode(directory): if self._check_abort(): return album_file = os.path.join(directory, f) if os.path.isdir(album_file): if f == "iPod Photo Cache": su.pout("Skipping " + album_file) continue rel_path_file = os.path.join(rel_path, f) if album_file in album_directories: contains_albums = True elif not self.check_directories(album_file, rel_path_file, album_directories, options): delete_album_file(album_file, directory, "Obsolete directory", options) else: # we won't touch some files if imageutils.is_ignore(f): continue delete_album_file(album_file, directory, "Obsolete", options) return contains_albums
def load_album(self, options): """Loads an existing album (export folder).""" online_albums = {} for album in self.client.gd_client.GetUserFeed().entry: if online_albums.has_key(album.title.text): self.delete_online_album(album, "duplicate album", options) else: online_albums[su.unicode_string(album.title.text)] = album album_directories = {} for folder_name in sorted(self.named_folders): folder = self.named_folders.get(folder_name) if self._check_abort(): return album_directories[folder.name] = True folder.load_album(self.client, online_albums, options) ignore_pattern = None if options.ignore: ignore_pattern = re.compile(su.fsdec(options.ignore)) for album_name in online_albums: if self._check_abort(): return if album_name in album_directories: continue if ignore_pattern and ignore_pattern.match(album_name): continue # We won't touch some albums if imageutils.is_ignore(album_name): continue self.delete_online_album(online_albums[album_name], "obsolete album", options)
def check_directories(self, directory, rel_path, album_directories, options): """Checks an export directory for obsolete files.""" if options.ignore: exclude_pattern = re.compile(su.fsdec(options.ignore)) if exclude_pattern.match(os.path.split(directory)[1]): return True if not os.path.exists(directory): return True contains_albums = False for f in su.os_listdir_unicode(directory): if self._check_abort(): return album_file = os.path.join(directory, f) if os.path.isdir(album_file): if f == "iPod Photo Cache": su.pout("Skipping " + album_file) continue rel_path_file = os.path.join(rel_path, f) if album_file in album_directories: contains_albums = True elif not self.check_directories(album_file, rel_path_file, album_directories, options): delete_album_file(album_file, directory, "Obsolete directory", options) else: contains_albums = True else: # we won't touch some files if imageutils.is_ignore(f): continue delete_album_file(album_file, directory, "Obsolete", options) return contains_albums
def resize_image(source, output, height_width_max, out_format='jpeg', enlarge=False): """Converts an image to a new format and resizes it. Args: source: path to inputimage file. output: path to output image file. height_width_max: resize image so height and width aren't greater than this value. out_format: output file format (like "jpeg") enlarge: if set, enlarge images that are smaller than height_width_max. Returns: Output from running "sips" command if it failed, None on success. """ # To use ImageMagick: #result = su.execandcombine( # [imageutils.CONVERT_TOOL, source, '-delete', '1--1', '-quality', '90%', # '-resize', "%dx%d^" % (height_width_max, height_width_max),output]) out_height_width_max = 0 if enlarge: out_height_width_max = height_width_max else: (width, height) = get_image_width_height(source) if height > height_width_max or width > height_width_max: out_height_width_max = height_width_max args = [_SIPS_TOOL, '-s', 'format', out_format] if out_height_width_max: args.extend(['--resampleHeightWidthMax', '%d' % (out_height_width_max)]) # TODO(tilmansp): This has problems with non-ASCII output folders. args.extend([source, '--out', output]) result = su.fsdec(su.execandcombine(args)) if result.find('Error') != -1 or result.find('Warning') != -1: return result return None
def resize_image(source, output, height_width_max, out_format='jpeg', enlarge=False): """Converts an image to a new format and resizes it. Args: source: path to inputimage file. output: path to output image file. height_width_max: resize image so height and width aren't greater than this value. out_format: output file format (like "jpeg") enlarge: if set, enlarge images that are smaller than height_width_max. Returns: Output from running "sips" command if it failed, None on success. """ # To use ImageMagick: #result = su.execandcombine( # [imageutils.CONVERT_TOOL, source, '-delete', '1--1', '-quality', '90%', # '-resize', "%dx%d^" % (height_width_max, height_width_max),output]) out_height_width_max = 0 if enlarge: out_height_width_max = height_width_max else: (width, height) = get_image_width_height(source) if height > height_width_max or width > height_width_max: out_height_width_max = height_width_max args = [_SIPS_TOOL, '-s', 'format', out_format] if out_height_width_max: args.extend( ['--resampleHeightWidthMax', '%d' % (out_height_width_max)]) # TODO(tilmansp): This has problems with non-ASCII output folders. args.extend([source, '--out', output]) result = su.fsdec(su.execandcombine(args)) if result.find('Error') != -1 or result.find( 'Warning') != -1 or result.find('Trace') != -1: return result return None
def resolve_alias(path): """Resolves a path to point to the real file if it is a file system alias. """ fs, _, _ = FSResolveAliasFile(path, 1) return su.fsdec(fs.as_pathname())
command.append(u'-RegionType=Face') elif new_persons != None: command.append('-RegionName=') if new_rectangles: for rectangle in new_rectangles: command.append('-RegionAreaX=%s' % (str(rectangle[0]))) command.append('-RegionAreaY=%s' % (str(rectangle[1]))) command.append('-RegionAreaW=%s' % (str(rectangle[2]))) command.append('-RegionAreaH=%s' % (str(rectangle[3]))) command.append('-RegionAreaUnit=normalized') elif new_rectangles != None: command.append('-RegionAreaX=') command.append("-iptc:CodedCharacterSet=ESC % G") command.append(filepath) result = su.fsdec(su.execandcombine(command)) if tmp: os.remove(tmp) if result.find("1 image files updated") != -1: if result != "1 image files updated": su.pout(result) # wipe out the back file created by exiftool backup_file = filepath + "_original" if os.path.exists(backup_file): os.remove(backup_file) return True else: su.perr("Failed to update IPTC data in image %s: %s" % (filepath, result)) return False
def update_iptcdata(filepath, new_caption, new_keywords, new_datetime, new_rating, new_gps, new_rectangles, new_persons): """Updates the caption and keywords of an image file.""" # Some cameras write into ImageDescription, so we wipe it out to not cause # conflicts with Caption-Abstract. We also wipe out the XMP Subject and # Description tags (we use Keywords and Caption-Abstract). command = [EXIFTOOL, '-F', '-m', '-P', '-ImageDescription=', '-Subject=', '-Description='] tmp = None if not new_caption is None: if not new_caption: command.append('-Caption-Abstract=') else: tmpfd, tmp = tempfile.mkstemp(dir="/var/tmp") os.close(tmpfd) file1 = open(tmp, "w") print >> file1, new_caption.encode("utf-8") file1.close() command.append('-Caption-Abstract<=%s' % (tmp)) if new_datetime: command.append('-DateTimeOriginal="%s"' % ( new_datetime.strftime("%Y:%m:%d %H:%M:%S"))) if new_keywords: for keyword in new_keywords: command.append(u'-keywords=%s' % (keyword)) elif new_keywords != None: command.append('-keywords=') if new_rating >= 0: command.append('-Rating=%d' % (new_rating)) if new_gps: command.append('-c') command.append('%.6f') command.append('-GPSLatitude="%f"' % (abs(new_gps.latitude))) command.append('-GPSLatitudeRef=' + new_gps.latitude_ref()) command.append('-GPSLongitude="%f"' % (abs(new_gps.longitude))) command.append('-GPSLongitudeRef=' + new_gps.longitude_ref()) if new_persons: for person in new_persons: command.append(u'-RegionPersonDisplayName=%s' % (person)) elif new_persons != None: command.append('-RegionPersonDisplayName=') if new_rectangles: for rectangle in new_rectangles: command.append('-RegionRectangle=%s' % ( ','.join(str(c) for c in rectangle))) elif new_rectangles != None: command.append('-RegionRectangle=') command.append("-iptc:CodedCharacterSet=ESC % G") command.append(filepath) result = su.fsdec(su.execandcombine(command)) if tmp: os.remove(tmp) if result.find("1 image files updated") != -1: if result != "1 image files updated": su.pout(result) # wipe out the back file created by exiftool backup_file = filepath + "_original" if os.path.exists(backup_file): os.remove(backup_file) return True else: su.perr("Failed to update IPTC data in image %s: %s" % ( filepath, result)) return False
def update_iptcdata(filepath, new_caption, new_keywords, new_datetime, new_rating, new_gps, new_rectangles, new_persons): """Updates the caption and keywords of an image file.""" # Some cameras write into ImageDescription, so we wipe it out to not cause # conflicts with Caption-Abstract. We also wipe out the XMP Subject and # Description tags (we use Keywords and Caption-Abstract). command = [ EXIFTOOL, '-F', '-m', '-P', '-ImageDescription=', '-Subject=', '-Description=' ] tmp = None if not new_caption is None: if not new_caption: command.append('-Caption-Abstract=') else: tmpfd, tmp = tempfile.mkstemp(dir="/var/tmp") os.close(tmpfd) file1 = open(tmp, "w") print >> file1, new_caption.encode("utf-8") file1.close() command.append('-Caption-Abstract<=%s' % (tmp)) if new_datetime: command.append('-DateTimeOriginal="%s"' % (new_datetime.strftime("%Y:%m:%d %H:%M:%S"))) if new_keywords: for keyword in new_keywords: command.append(u'-keywords=%s' % (keyword)) elif new_keywords != None: command.append('-keywords=') if new_rating >= 0: command.append('-Rating=%d' % (new_rating)) if new_gps: command.append('-c') command.append('%.6f') command.append('-GPSLatitude="%f"' % (abs(new_gps.latitude))) command.append('-GPSLatitudeRef=' + new_gps.latitude_ref()) command.append('-GPSLongitude="%f"' % (abs(new_gps.longitude))) command.append('-GPSLongitudeRef=' + new_gps.longitude_ref()) if new_persons: for person in new_persons: command.append(u'-RegionPersonDisplayName=%s' % (person)) elif new_persons != None: command.append('-RegionPersonDisplayName=') if new_rectangles: for rectangle in new_rectangles: command.append('-RegionRectangle=%s' % (','.join(str(c) for c in rectangle))) elif new_rectangles != None: command.append('-RegionRectangle=') command.append("-iptc:CodedCharacterSet=ESC % G") command.append(filepath) result = su.fsdec(su.execandcombine(command)) if tmp: os.remove(tmp) if result.find("1 image files updated") != -1: if result != "1 image files updated": su.pout(result) # wipe out the back file created by exiftool backup_file = filepath + "_original" if os.path.exists(backup_file): os.remove(backup_file) return True else: su.perr("Failed to update IPTC data in image %s: %s" % (filepath, result)) return False
command.append(u'-RegionType=Face') elif new_persons != None: command.append('-RegionName=') if new_rectangles: for rectangle in new_rectangles: command.append('-RegionAreaX=%s' % (str(rectangle[0]))) command.append('-RegionAreaY=%s' % (str(rectangle[1]))) command.append('-RegionAreaW=%s' % (str(rectangle[2]))) command.append('-RegionAreaH=%s' % (str(rectangle[3]))) command.append('-RegionAreaUnit=normalized') elif new_rectangles != None: command.append('-RegionAreaX=') command.append("-iptc:CodedCharacterSet=ESC % G") command.append(filepath) result = su.fsdec(su.execandcombine(command)) if tmp: os.remove(tmp) if result.find("1 image files updated") != -1: if result != "1 image files updated": su.pout(result) # wipe out the back file created by exiftool backup_file = filepath + "_original" if os.path.exists(backup_file): os.remove(backup_file) return True else: su.perr("Failed to update IPTC data in image %s: %s" % ( filepath, result)) return False