Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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())
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
            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
Ejemplo n.º 12
0
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())
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
            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