class imageFile(object):
    """get name of file out of it's path and provide function \
        to save with new copyright info"""
    def __init__(self, path, cr_text):
        self.path = path
        self.split_image_path = path.split('/')
        self.image_name= self.split_image_path[-1]
        self.split_image_name = self.image_name.split('.')
        self.orig_name = self.split_image_name[0]
        self.folder = (string.join(self.split_image_path[0:-1], "/") + "/")
        self.info= IPTCInfo(str(path), force= True)
        self.copyright = self.info.data['copyright notice']
        self.info.data['copyright notice']= (year + " " + cr_text)

    def save_new(self):
        file_copy = (str(self.orig_name) + '_cr' + '.' + str(self.split_image_name[-1]))
        if os.path.exists(self.folder + '/' + file_copy):
            print "Sorry! The file " + file_copy + " already exists!"
            return
        else:
            try:
                self.info.saveAs(self.folder + file_copy)
                #os.remove(self.path)
                shutil.move(self.path, "/Users/" + user + "/.Trash")    
            except:
                print "Unexpected error:", sys.exc_info()[0]
                raise
    
    def save_over(self):
        self.info.save()
示例#2
0
def process_files(srcdir):
  global dryrun

  from iptcinfo import IPTCInfo

  files = os.listdir(srcdir) 
  
  for name in files:
    if not os.path.splitext(name)[1] in fileTypesAllowed:
      logger.info('Ignoring %s' % name)
      continue
    else:
      filepath = os.path.join(srcdir,  name)
      logger.info('Processing %s' % name)
      
      try:
        info = IPTCInfo(filepath, force=True)
      
        caption = info.data['caption/abstract']
        if not caption:
          logger.info('Caption not found.')
          info.data['caption/abstract'] = os.path.splitext(name)[0]
          logger.info('New caption -> %s' % info.data['caption/abstract'])
          if not dryrun:
            logger.info('Overwriting %s' % name)
            info.save()
        else:
          logger.info('Found existing caption. Nothing to do')
      except:
        continue
示例#3
0
 def write_info(self):
     """Write picasa album names and star rating to photo's IPTC keywords."""
     for photo, info in self.photos.items():
         photo = IPTCInfo(photo, force=True)
         if "albums" in info:
             photo.keywords = list(set(photo.keywords + info["albums"]))
         print "Write: {}".format(photo.keywords)
         photo.save()
示例#4
0
 def test_only_write_tags_once(self):
     labeler = FileLabeler()
     info = IPTCInfo(self.jpg_file, force=True)
     info.keywords = ('cat', 'mammal')
     info.save()
     os.remove('%s~' % self.jpg_file)
     labeler.label(self.jpg_file, (u'cat', u'mammal'))
     info = IPTCInfo(self.jpg_file)
     self.assertEqual(info.keywords, ['cat', 'mammal'])
示例#5
0
 def test_preserve_existing_labels(self):
     labeler = FileLabeler()
     info = IPTCInfo(self.jpg_file, force=True)
     info.keywords = ('cat', 'mammal')
     info.save()
     os.remove('%s~' % self.jpg_file)
     labeler.label(self.jpg_file, (u'dog', u'mammal'))
     info = IPTCInfo(self.jpg_file)
     self.assertEqual(info.keywords, ['cat', 'mammal', 'dog'])
 def write_info(self):
     """Write picasa album names and star rating to photo's IPTC keywords."""
     for filename, info in self.photos.items():
         photo = IPTCInfo(filename, force=True)
         if "albums" in info:
             photo.keywords = list(set(photo.keywords + info["albums"]))
         print "Writing {}: {}".format(filename, photo.keywords)
         try:
             photo.save()
         except:
             self.errors[filename] = sys.exc_info()[0]
示例#7
0
 def write_list_to_jpg(self, filename, items):
     """
     Writes a list of data to the IPTC special_instructions field of a .JPG file
     :param filename: .jpg filename
     :param items: list of items to be written (specified using Python list syntax)
     :return: none
     """
     info = IPTCInfo(filename)
     if len(info.data) < 4: raise Exception(info.error)
     info.data['caption/abstract']='Contains Special Instructions'
     info.data['special instructions']=str(items)
     info.save()
示例#8
0
 def test_skip_already_tagged_files(self):
     file_walker = FileWalker(FileLabeler(), LabelServiceExecutor(TestServiceConnector()))
     os.makedirs('_testdir/2016/10')
     self._create_testfile('_testdir/2016/10/test1.jpg')
     os.makedirs('_testdir/2016/11')
     self._create_testfile('_testdir/2016/11/test2.jpg')
     info = IPTCInfo('_testdir/2016/11/test2.jpg', force=True)
     info.keywords = ('already', 'tagged')
     info.data[TAGGED_PHOTO_KEY] = TAGGED_PHOTO_LABEL
     info.save()
     file_walker.walk_and_tag('_testdir/2016')
     self.assertEqual(IPTCInfo('_testdir/2016/10/test1.jpg').keywords,
                      ['cat', 'mammal', 'vertebrate', 'whiskers', 'animal'])
     self.assertEqual(IPTCInfo('_testdir/2016/11/test2.jpg').keywords, ['already', 'tagged'])
示例#9
0
 def write_encrypted_list_to_jpg(self, filename, password, items):
     """
     Writes an encrypted list of data to the IPTC special_instructions field of a .JPG file
     :param filename: .jpg filename
     :param password: the password used for encryption
     :param items: list of items to be written (specified using Python list syntax)
     :return: none
     """
     info = IPTCInfo(filename)
     if len(info.data) < 4: raise Exception(info.error)
     token = self._fernet_encrypt(str(items),password)
     info.data['caption/abstract']='Contains Special Instructions'
     info.data['special instructions']=token
     info.save()
示例#10
0
def updateIPTC(obj, event):
    """ On edit store the updated image metadata inside the image file itself in 
        IPTC format """

    if WATERMARK:
        state = getToolByName(obj,'portal_workflow').getInfoFor(obj,'review_state')
    else:
        state = None

    if WATERMARK and state in ['published', 'featured']:
        img = ImageExtender(obj).fields[0].get(obj)
    else:
        img = obj.getImage()

    fd, filename = tempfile.mkstemp('_'+obj.getId())
    os.close(fd)
    fout = open(filename, 'wb')
    fout.write(img.data)
    fout.close()

    info = IPTCInfo(filename, force=True)
    info.data['object name'] = obj.Title()
    info.data['caption/abstract'] = obj.Description()
    info.data['by-line'] = obj.Creator()
    info.data['copyright notice'] = obj.Rights()
    info.data['keywords'] = [i for i in obj.Subject()]
    info.keyword = info.data['keywords']
    info.data['sub-location'] = obj.getLocation().strip()
    info.data['city'] = obj.getLocation().strip()
    info.data['province/state'] = obj.getLocation().strip()
    info.data['country/primary location name'] = obj.getLocation().strip()
    info.data['country/primary location code'] = obj.getLocation().strip()
    info.save()

    if WATERMARK:
    # Set the original image field to have the updated IPTC
        fin = open(filename)
        ImageExtender(obj).fields[0].set(obj, fin.read())
        fin.close()

        if state in ['published', 'featured']:
            applyWatermark(obj)
        else:
            obj.setImage(ImageExtender(obj).fields[0].get(obj))
    else:
        fin = open(filename)
        obj.setImage(fin.read())
        fin.close()
示例#11
0
文件: picman.py 项目: michrony/picman
def iptcCaptionSet(fn, caption):
  logging.disable(logging.CRITICAL)
  if (caption==""): caption = " "
  now = datetime.now()
  now = now.strftime("%Y%m%d")
  info = None
  try:
     n = 1
     info = IPTCInfo(fn, force=True)
     n = 2
     info.data['caption/abstract'] = caption
     info.data['date created']     = now
     info.data['writer/editor']    = "picman"
     info.data['copyright notice'] = ""
     #info.data['keywords']  = ""
     n = 3
     info.save()
     os.remove(fn + "~")
  except Exception, e:
    info  = None
    print "[%s]" % (caption)
    print "iptcCaptionSet() failed to process %s - %d %s" % (fn, n, str(e))
class Image(object):
    """
    Models an image filename with tags.
    """
    def __init__(self, filename):
        logging.info('Creating new Image from “{}”.'.format(filename))

        self.basename = ""
        self.date = ""
        self.dirname = ""
        self.event = ""
        self.number = ""
        self.origname = ""
        self.prefix = ""
        self.suffix = ""
        self.iptc = None

        self.tags = set()

        self.origname = filename
        self.dirname = os.path.dirname(filename)
        self.basename = os.path.basename(filename)

        self._parse_folder_name()
        self._parse_filename()

        self._load_iptc()

    def add_tag(self, tag):
        """
        Adds the given tag.

        :param tag: Tag to add.
        :type tag: Tag
        :raise TypeError: Raised if not a :py:class:`Tag` given.
        """
        if not isinstance(tag, Tag):
            raise TypeError("Image::add_tag(hashtags.Tag)")

        self.tags.add(tag)

    def remove_tag(self, tag):
        """
        Removes the tag, if it is there.

        If the given tag is not in the set, no error is printed.

        :param tag: Tag to remove.
        :type tag: Tag
        """
        if not isinstance(tag, Tag):
            raise TypeError("Image::remove_tag(hashtags.Tag)")

        self.tags.discard(tag)

    def __repr__(self):
        return "Image('{}')".format(self.current_path())

    def rename(self):
        """
        Performs the actual renaming.

        If the file exists, it will try to increase the picture number. If the
        attribute :py:attr:`tempname` is set, this name will be used instead of
        :py:attr:`origname`.
        """
        newname = self.current_path()
        if os.path.isfile(newname):
            print 'File “{}” already exists.'.format(newname)
            answer = raw_input('Do you want to increase the number? [Y/n] ')

            if answer != "n":
                while os.path.isfile(newname):
                    self.number = str(int(self.number) +1)
                    newname = self.current_path()

            print 'Now using “{}”.'.format(newname)

        assert not os.path.isfile(newname)

        oldname = self.origname
        try:
            oldname = self.tempname
        except AttributeError:
            pass

        logging.info('Renaming “{}” to “{}”.'.format(self.origname, newname))
        os.rename(oldname, newname)

    def _tagstring(self):
        tagstring = ""
        if len(self.tags) > 0:
            tagstring = "#" + "#".join(sorted([tag.escape() for tag in self.tags]))

        return tagstring

    def current_path(self):
        """
        Gives the current path of this image.
        
        :raises FilenameTooLongError: Raised if generated filename is longer than the filesystem probably supports.
        :return: Current path.
        :rtype: str
        """
        filename = "{}-{}-{}{}.{}".format(
            self.date, self.event, self.number, self._tagstring(), self.suffix
        )

        pathname = os.path.join(self.dirname, filename)

        if len(pathname) > 256:
            raise FilenameTooLongError("Filename “{}” is longer than 256 chars.".format(pathname))

        return pathname

    def _parse_filename(self):
        """
        Parses the filename to find the hashtags.

        :raises FilenameParseError: Raised if name could not be parsed.
        """
        m = re.match(r"([^#]+)(#.*)*\.(\w+)", self.basename)

        if m is None:
            raise FilenameParseError('Could not parse “{}”.'.format(self.basename))

        if not m.group(2) is None:
            taglist = m.group(2).split("#")

            for tag in taglist:
                if len(tag) > 0:
                    self.add_tag(Tag.from_escaped(tag))

        self.prefix = m.group(1)
        self.suffix = m.group(3)

        self._parse_prefix()

    def _parse_prefix(self):
        """
        Parses the first part of the filename.

        If date or event are already set from the folder name, they are not
        overwritten.
        """
        prefixparts = self.prefix.split('-')

        if len(prefixparts) >= 3:
            if self.date == "":
                self.date = prefixparts[0]
            if self.event == "":
                self.event = '-'.join(prefixparts[1:-1])

            self.number = prefixparts[-1]

        # The number could not be parsed yet, try to find a number. At this
        # point, any number is fine.
        if self.number == "":
            numbers = re.findall(r"\d+", self.prefix)
            if len(numbers) > 0:
                self.number = numbers[-1]

        if self.number == "":
            global next_id
            self.number = str(next_id)
            next_id += 1

        # In case anything is missing, this could not be parsed.
        if self.date == "":
            raise DateParseError('Could not parse “{}”.'.format(self.prefix))
        if self.event == "":
            raise EventParseError('Could not parse “{}”.'.format(self.prefix))
        if self.number == "":
            raise NumberParseError('Could not parse “{}”.'.format(self.prefix))

    def _parse_folder_name(self):
        """
        Parses date and event name from a folder name.

        Sets :py:attr:`date` and :py:attr:`event`.
        """
        if len(self.dirname) == 0:
            return

        pattern = re.compile(r"([012]\d{3}[01]\d[0123]\d)-([^/]+)/?")
        album_dir = os.path.basename(self.dirname)
        m = pattern.match(album_dir)
        if m is None:
            raise FolderParseError('Could not parse “{}”.'.format(album_dir))

        self.date = m.group(1)
        self.event = m.group(2)

    def get_tags(self):
        """
        Gives the list with all tags.

        :return: A list with all tags.
        :rtype: list
        """
        return list(self.tags)

    def _load_iptc(self):
        """
        Loads the IPTC data from the original file and saves them with
        :py:meth:`add_tag`.
        """
        try:
            self.iptc = IPTCInfo(self.origname, force=True)
        except IOError as e:
            pass
        else:
            logging.info('Found Tags “{}” in “{}”.'.format(
                ', '.join(sorted(self.iptc.keywords)), self.origname))
            for keyword in self.iptc.keywords:
                self.add_tag(Tag(keyword))

    def write_iptc(self):
        """
        Writes the IPTC data.
        """
        self.iptc.data['keywords'] = list(sorted(self.get_tags()))
        logging.info('Saving IPTC keywords to “{}”.'.format(self.origname))
        self.iptc.save()

    def name_changed(self):
        """
        Checks whether the name that :py:meth:`current_path` gives is the same
        than :py:attr:`origname`.

        :return: Whether the filename was changed.
        :rtype: bool
        """
        return self.origname != self.current_path()

    def iptc_changed(self):
        """
        Check whether the tags match the IPTC tags.

        :return: Whether the IPTC tags need to be rewritten.
        :rtype: bool
        """
        return sorted(map(Tag, self.iptc.keywords)) != sorted(self.get_tags())

    def save(self):
        """
        Renames the file and updates the IPTC fields.
        """
        if self.iptc_changed():
            self.write_iptc()

        if self.name_changed():
            self.rename()

    def rename_to_temp(self):
        """
        Renames the image to a temporary name.

        It generates a random UUID 4 and renames the picture to it. The
        temporary name is stored in the :py:attr:`tempname` attribute.
        """
        self.tempname = str(uuid.uuid4())
        os.rename(self.origname, self.tempname)
示例#13
0
#!/usr/bin/env python
# :mode=python:encoding=utf-8
# -*- coding: utf-8 -*-

import sys
sys.path.insert(0, '.')
from iptcinfo import IPTCInfo, LOG, LOGDBG

if __name__ == '__main__':
    import logging
    logging.basicConfig(level=logging.DEBUG)
    LOGDBG.setLevel(logging.DEBUG)
    if len(sys.argv) > 1:
        info = IPTCInfo(sys.argv[1], True)
        info.keywords = ['test']
        info.supplementalCategories = []
        info.contacts = []
        print("info = %s\n%s" % (info, "=" * 30), file=sys.stderr)
        info.save()
示例#14
0
 def test_write_keywords(self):
     info = IPTCInfo(self.jpg_file, force=True)
     info.keywords = ('A', 'B')
     info.save()
     info = IPTCInfo(self.jpg_file)
     self.assertEqual(info.keywords, ['A', 'B'])
示例#15
0
class Image:
    def __init__(self, filename):
      self.filename = filename
      self.info = None
      self.exif = None

      try:
        self.info = IPTCInfo(self.filename, force=True)
      except:
        print "cannot initialize IPTCInfo!"
        pass

      try:
        self.exif = MinimalExifReader(self.filename)
      except:
        print "cannot initialize exif reader"
        pass

      # if we can't create either reader, give up
      if self.exif == None and self.info == None:
        print "cannot read file metadata"
        raise

      # at a minimum, we set a datestamp if one doesn't exist
      # set to current date & time
      exifDateStamp = None
      if self.exif != None:
        exifDateStamp = self.exif.dateTimeOriginal("%Y%m%d-%H%M%S")
        if exifDateStamp == "":
          exifDateStamp = None
      iptcDate = self.getData("dateCreated")
      iptcTime = self.getData("timeCreated")
  
      if exifDateStamp != None and \
        iptcDate == None and \
        iptcTime == None:
        datestamp = exifDateStamp.split('-')
        self.info.data[iptcMap['dateCreated']] = datestamp[0]
        self.info.data[iptcMap['timeCreated']] = datestamp[1]
      elif exifDateStamp == None and \
        iptcDate == None and \
        iptcTime == None:
        date, time = nowStamp()
        self.info.data[iptcMap['dateCreated']] = date
        self.info.data[iptcMap['timeCreated']] = time

    def availableFields(self):
      return iptcMap.keys()

    def setData(self, field, data):
      if field in iptcMap:
        self.info.data[iptcMap[field]] = data

    def getData(self, field):
      if self.info != None:
        if field in iptcMap:
          return self.info.data[iptcMap[field]]

      return None
 
    def writeFile(self):
      self.info.save()

    def dump(self):
      for f in self.availableFields():
        print f + " : " + str(self.getData(f))
示例#16
0
# Check if file had IPTC data
# if len(info.data) < 4: raise Exception(info.error)

# Get list of keywords, supplemental categories, or contacts
keywords = info.keywords
suppCats = info.supplementalCategories
contacts = info.contacts

# Get specific attributes...
caption = info.data['caption/abstract']

# Create object for file that may or may not have IPTC data.
info = IPTCInfo(fn, force=True)

# Add/change an attribute
info.data['caption/abstract'] = 'árvíztűrő tükörfúrógép'
info.data['supplemental category'] = ['portrait']
info.data[123] = '123'
info.data['nonstandard_123'] = 'n123'

print info.data

# Save new info to file
##### See disclaimer in 'SAVING FILES' section #####
info.save()
info.saveAs(fn2)

#re-read IPTC info
print IPTCInfo(fn2)