def setFilename(self, filename, append=True):
        """
        Use a file to store all messages. The
        UTF-8 encoding will be used. Write an informative
        message if the file can't be created.

        @param filename: C{L{string}}
        """

        # Look if file already exists or not
        filename = os.path.expanduser(filename)
        filename = os.path.realpath(filename)
        append = os.access(filename, os.F_OK)

        # Create log file (or open it in append mode, if it already exists)
        try:
            import codecs
            if append:
                self.__file = codecs.open(filename, "a", "utf-8")
            else:
                self.__file = codecs.open(filename, "w", "utf-8")
            self._writeIntoFile(_("Starting Hachoir"))
        except IOError, err:
            if err.errno == 2:
                self.__file = None
                self.info(
                    _("[Log] setFilename(%s) fails: no such file") % filename)
            else:
                raise
    def useHeader(self, header):
        self.width = header["width"].value
        self.height = header["height"].value

        # Read number of colors and pixel format
        if "/palette/size" in header:
            nb_colors = header["/palette/size"].value // 3
        else:
            nb_colors = None
        if not header["has_palette"].value:
            if header["has_alpha"].value:
                self.pixel_format = _("RGBA")
            else:
                self.pixel_format = _("RGB")
        elif "/transparency" in header:
            self.pixel_format = _("Color index with transparency")
            if nb_colors:
                nb_colors -= 1
        else:
            self.pixel_format = _("Color index")
        self.bits_per_pixel = pngBitsPerPixel(header)
        if nb_colors:
            self.nb_colors = nb_colors

        # Read compression, timestamp, etc.
        self.compression = header["compression"].display
Esempio n. 3
0
def getHachoirOptions(parser):
    """
    Create an option group (type optparse.OptionGroup) of Hachoir
    library options.
    """
    def setLogFilename(*args):
        log.setFilename(args[2])

    common = OptionGroup(parser, _("Hachoir library"), \
        "Configure Hachoir library")
    common.add_option("--verbose",
                      help=_("Verbose mode"),
                      default=False,
                      action="store_true")
    common.add_option("--log",
                      help=_("Write log in a file"),
                      type="string",
                      action="callback",
                      callback=setLogFilename)
    common.add_option("--quiet",
                      help=_("Quiet mode (don't display warning)"),
                      default=False,
                      action="store_true")
    common.add_option("--debug",
                      help=_("Debug mode"),
                      default=False,
                      action="store_true")
    return common
Esempio n. 4
0
    def useHeader(self, header):
        self.width = header["width"].value
        self.height = header["height"].value

        # Read number of colors and pixel format
        if "/palette/size" in header:
            nb_colors = header["/palette/size"].value // 3
        else:
            nb_colors = None
        if not header["has_palette"].value:
            if header["has_alpha"].value:
                self.pixel_format = _("RGBA")
            else:
                self.pixel_format = _("RGB")
        elif "/transparency" in header:
            self.pixel_format = _("Color index with transparency")
            if nb_colors:
                nb_colors -= 1
        else:
            self.pixel_format = _("Color index")
        self.bits_per_pixel = pngBitsPerPixel(header)
        if nb_colors:
            self.nb_colors = nb_colors

        # Read compression, timestamp, etc.
        self.compression = header["compression"].display
Esempio n. 5
0
    def setFilename(self, filename, append=True):
        """
        Use a file to store all messages. The
        UTF-8 encoding will be used. Write an informative
        message if the file can't be created.

        @param filename: C{L{string}}
        """

        # Look if file already exists or not
        filename = os.path.expanduser(filename)
        filename = os.path.realpath(filename)
        append = os.access(filename, os.F_OK)

        # Create log file (or open it in append mode, if it already exists)
        try:
            import codecs
            if append:
                self.__file = codecs.open(filename, "a", "utf-8")
            else:
                self.__file = codecs.open(filename, "w", "utf-8")
            self._writeIntoFile(_("Starting Hachoir"))
        except IOError, err:
            if err.errno == 2:
                self.__file = None
                self.info(_("[Log] setFilename(%s) fails: no such file") % filename)
            else:
                raise
Esempio n. 6
0
 def __init__(self, size, address, got=None):
     self.size = size
     self.address = address
     self.got = got
     if self.got is not None:
         msg = _("Can't read %u bits at address %u (got %u bits)") % (self.size, self.address, self.got)
     else:
         msg = _("Can't read %u bits at address %u") % (self.size, self.address)
     InputStreamError.__init__(self, msg)
Esempio n. 7
0
 def __init__(self, size, address, got=None):
     self.size = size
     self.address = address
     self.got = got
     if self.got is not None:
         msg = _("Can't read %u bits at address %u (got %u bits)") % (
             self.size, self.address, self.got)
     else:
         msg = _("Can't read %u bits at address %u") % (self.size,
                                                        self.address)
     InputStreamError.__init__(self, msg)
 def extract(self, gif):
     self.useScreen(gif["/screen"])
     if self.has("bits_per_pixel"):
         self.nb_colors = (1 << self.get('bits_per_pixel'))
     self.compression = _("LZW")
     self.format_version =  "GIF version %s" % gif["version"].value
     for comments in gif.array("comments"):
         for comment in gif.array(comments.name + "/comment"):
             self.comment = comment.value
     if "graphic_ctl/has_transp" in gif and gif["graphic_ctl/has_transp"].value:
         self.pixel_format = _("Color index with transparency")
     else:
         self.pixel_format = _("Color index")
Esempio n. 9
0
 def extract(self, tar):
     max_nb = maxNbFile(self)
     for index, field in enumerate(tar.array("file")):
         if max_nb is not None and max_nb <= index:
             self.warning("TAR archive contains many files, but only first %s files are processed" % max_nb)
             break
         meta = Metadata(self)
         self.extractFile(field, meta)
         if meta.has("filename"):
             title = _('File "%s"') % meta.getText('filename')
         else:
             title = _("File")
         self.addGroup(field.name, meta, title)
Esempio n. 10
0
 def extract(self, gif):
     self.useScreen(gif["/screen"])
     if self.has("bits_per_pixel"):
         self.nb_colors = 1 << self.get("bits_per_pixel")
     self.compression = _("LZW")
     self.format_version = "GIF version %s" % gif["version"].value
     for comments in gif.array("comments"):
         for comment in gif.array(comments.name + "/comment"):
             self.comment = comment.value
     if "graphic_ctl/has_transp" in gif and gif["graphic_ctl/has_transp"].value:
         self.pixel_format = _("Color index with transparency")
     else:
         self.pixel_format = _("Color index")
Esempio n. 11
0
 def extract(self, tar):
     max_nb = maxNbFile(self)
     for index, field in enumerate(tar.array("file")):
         if max_nb is not None and max_nb <= index:
             self.warning("TAR archive contains many files, but only first %s files are processed" % max_nb)
             break
         meta = Metadata(self)
         self.extractFile(field, meta)
         if meta.has("filename"):
             title = _('File "%s"') % meta.getText('filename')
         else:
             title = _("File")
         self.addGroup(field.name, meta, title)
Esempio n. 12
0
 def useFile(self, field):
     meta = Metadata(self)
     meta.filename = field["filename"].value
     meta.file_size = field["filesize"].value
     meta.creation_date = field["timestamp"].value
     attr = field["attributes"].value
     if attr != "(none)":
         meta.file_attr = attr
     if meta.has("filename"):
         title = _("File \"%s\"") % meta.getText('filename')
     else:
         title = _("File")
     self.addGroup(field.name, meta, title)
Esempio n. 13
0
 def useFile(self, field):
     meta = Metadata(self)
     meta.filename = field["filename"].value
     meta.file_size = field["filesize"].value
     meta.creation_date = field["timestamp"].value
     attr = field["attributes"].value
     if attr != "(none)":
         meta.file_attr = attr
     if meta.has("filename"):
         title = _("File \"%s\"") % meta.getText('filename')
     else:
         title = _("File")
     self.addGroup(field.name, meta, title)
Esempio n. 14
0
 def __init__(self, stream, **args):
     validate = args.pop("validate", False)
     self._mime_type = None
     while validate:
         nbits = self.getParserTags()["min_size"]
         if stream.sizeGe(nbits):
             res = self.validate()
             if res is True:
                 break
             res = makeUnicode(res)
         else:
             res = _("stream is smaller than %s.%s bytes" % divmod(nbits, 8))
         raise ValidateError(res or _("no reason given"))
     self._autofix = True
    def startOfFrame(self, sof):
        # Set compression method
        key = sof["../type"].value
        self.compression = "JPEG (%s)" % JpegChunk.START_OF_FRAME[key]

        # Read image size and bits/pixel
        self.width = sof["width"].value
        self.height = sof["height"].value
        nb_components = sof["nr_components"].value
        self.bits_per_pixel = 8 * nb_components
        if nb_components == 3:
            self.pixel_format = _("YCbCr")
        elif nb_components == 1:
            self.pixel_format = _("Grayscale")
            self.nb_colors = 256
Esempio n. 16
0
 def __init__(self, stream, **args):
     validate = args.pop("validate", False)
     self._mime_type = None
     while validate:
         nbits = self.getParserTags()["min_size"]
         if stream.sizeGe(nbits):
             res = self.validate()
             if res is True:
                 break
             res = makeUnicode(res)
         else:
             res = _("stream is smaller than %s.%s bytes" %
                     divmod(nbits, 8))
         raise ValidateError(res or _("no reason given"))
     self._autofix = True
Esempio n. 17
0
    def extractAVI(self, headers):
        audio_index = 1
        for stream in headers.array("stream"):
            if "stream_hdr/stream_type" not in stream:
                continue
            stream_type = stream["stream_hdr/stream_type"].value
            if stream_type == "vids":
                if "stream_hdr" in stream:
                    meta = Metadata(self)
                    self.extractAVIVideo(stream["stream_hdr"], meta)
                    self.addGroup("video", meta, "Video stream")
            elif stream_type == "auds":
                if "stream_fmt" in stream:
                    meta = Metadata(self)
                    self.extractAVIAudio(stream["stream_fmt"], meta)
                    self.addGroup("audio[%u]" % audio_index, meta,
                                  "Audio stream")
                    audio_index += 1
        if "avi_hdr" in headers:
            self.useAviHeader(headers["avi_hdr"])

        # Compute global bit rate
        if self.has("duration") and "/movie/size" in headers:
            self.bit_rate = float(
                headers["/movie/size"].value) * 8 / timedelta2seconds(
                    self.get('duration'))

        # Video has index?
        if "/index" in headers:
            self.comment = _("Has audio/video index (%s)") \
                % humanFilesize(headers["/index"].size/8)
Esempio n. 18
0
 def computeBitrate(self, frame):
     bit_rate = frame.getBitRate()  # may returns None on error
     if not bit_rate:
         return
     self.bit_rate = (bit_rate, _("%s (constant)") % humanBitRate(bit_rate))
     self.duration = timedelta(seconds=float(frame["/frames"].size) /
                               bit_rate)
    def extract(self, icon):
        for index, header in enumerate(icon.array("icon_header")):
            image = Metadata(self)

            # Read size and colors from header
            image.width = header["width"].value
            image.height = header["height"].value
            bpp = header["bpp"].value
            nb_colors = header["nb_color"].value
            if nb_colors != 0:
                image.nb_colors = nb_colors
                if bpp == 0 and nb_colors in self.color_to_bpp:
                    bpp = self.color_to_bpp[nb_colors]
            elif bpp == 0:
                bpp = 8
            image.bits_per_pixel = bpp
            image.setHeader(_("Icon #%u (%sx%s)")
                % (1+index, image.get("width", "?"), image.get("height", "?")))

            # Read compression from data (if available)
            key = "icon_data[%u]/header/codec" % index
            if key in icon:
                image.compression = icon[key].display
            key = "icon_data[%u]/pixels" % index
            if key in icon:
                computeComprRate(image, icon[key].size)

            # Store new image
            self.addGroup("image[%u]" % index, image)
    def __delitem__(self, index):
        """
        Delete item at position index. May raise IndexError.

        >>> d=Dict( ((6, 'six'), (9, 'neuf'), (4, 'quatre')) )
        >>> del d[1]
        >>> d
        {6: 'six', 4: 'quatre'}
        """
        if index < 0:
            index += len(self._value_list)
        if not (0 <= index < len(self._value_list)):
            raise IndexError(_("list assignment index out of range (%s/%s)")
                % (index, len(self._value_list)))
        del self._value_list[index]
        del self._key_list[index]

        # First loop which may alter self._index
        for key, item_index in self._index.iteritems():
            if item_index == index:
                del self._index[key]
                break

        # Second loop update indexes
        for key, item_index in self._index.iteritems():
            if index < item_index:
                self._index[key] -= 1
Esempio n. 21
0
    def extract(self, icon):
        for index, header in enumerate(icon.array("icon_header")):
            image = Metadata(self)

            # Read size and colors from header
            image.width = header["width"].value
            image.height = header["height"].value
            bpp = header["bpp"].value
            nb_colors = header["nb_color"].value
            if nb_colors != 0:
                image.nb_colors = nb_colors
                if bpp == 0 and nb_colors in self.color_to_bpp:
                    bpp = self.color_to_bpp[nb_colors]
            elif bpp == 0:
                bpp = 8
            image.bits_per_pixel = bpp
            image.setHeader(_("Icon #%u (%sx%s)") % (1 + index, image.get("width", "?"), image.get("height", "?")))

            # Read compression from data (if available)
            key = "icon_data[%u]/header/codec" % index
            if key in icon:
                image.compression = icon[key].display
            key = "icon_data[%u]/pixels" % index
            if key in icon:
                computeComprRate(image, icon[key].size)

            # Store new image
            self.addGroup("image[%u]" % index, image)
Esempio n. 22
0
    def extractAVI(self, headers):
        audio_index = 1
        for stream in headers.array("stream"):
            if "stream_hdr/stream_type" not in stream:
                continue
            stream_type = stream["stream_hdr/stream_type"].value
            if stream_type == "vids":
                if "stream_hdr" in stream:
                    meta = Metadata(self)
                    self.extractAVIVideo(stream["stream_hdr"], meta)
                    self.addGroup("video", meta, "Video stream")
            elif stream_type == "auds":
                if "stream_fmt" in stream:
                    meta = Metadata(self)
                    self.extractAVIAudio(stream["stream_fmt"], meta)
                    self.addGroup("audio[%u]" % audio_index, meta, "Audio stream")
                    audio_index += 1
        if "avi_hdr" in headers:
            self.useAviHeader(headers["avi_hdr"])

        # Compute global bit rate
        if self.has("duration") and "/movie/size" in headers:
            self.bit_rate = float(headers["/movie/size"].value) * 8 / timedelta2seconds(self.get("duration"))

        # Video has index?
        if "/index" in headers:
            self.comment = _("Has audio/video index (%s)") % humanFilesize(headers["/index"].size / 8)
Esempio n. 23
0
 def computeVariableBitrate(self, mp3):
     if self.quality <= QUALITY_FAST:
         return
     count = 0
     if QUALITY_BEST <= self.quality:
         self.warning(
             "Process all MPEG audio frames to compute exact duration")
         max_count = None
     else:
         max_count = 500 * self.quality
     total_bit_rate = 0.0
     for index, frame in enumerate(mp3.array("frames/frame")):
         if index < 3:
             continue
         bit_rate = frame.getBitRate()
         if bit_rate:
             total_bit_rate += float(bit_rate)
             count += 1
             if max_count and max_count <= count:
                 break
     if not count:
         return
     bit_rate = total_bit_rate / count
     self.bit_rate = (bit_rate,
                      _("%s (Variable bit rate)") % humanBitRate(bit_rate))
     duration = timedelta(seconds=float(mp3["frames"].size) / bit_rate)
     self.duration = duration
Esempio n. 24
0
    def displayStat(self, stat):
        """
        Display statistics to stdout:
        - best time (minimum)
        - average time (arithmetic average)
        - worst time (maximum)
        - total time (sum)

        Use arithmetic avertage instead of geometric average because
        geometric fails if any value is zero (returns zero) and also
        because floating point multiplication lose precision with many
        values.
        """
        average = stat.getSum() / len(stat)
        values = (stat.getMin(), average, stat.getMax(), stat.getSum())
        values = tuple(self.formatTime(value) for value in values)
        print _("Benchmark: best=%s  average=%s  worst=%s  total=%s") \
            % values
Esempio n. 25
0
    def displayStat(self, stat):
        """
        Display statistics to stdout:
        - best time (minimum)
        - average time (arithmetic average)
        - worst time (maximum)
        - total time (sum)

        Use arithmetic avertage instead of geometric average because
        geometric fails if any value is zero (returns zero) and also
        because floating point multiplication lose precision with many
        values.
        """
        average = stat.getSum() / len(stat)
        values = (stat.getMin(), average, stat.getMax(), stat.getSum())
        values = tuple(self.formatTime(value) for value in values)
        print _("Benchmark: best=%s  average=%s  worst=%s  total=%s") \
            % values
 def append(self, key, value):
     """
     Append new value
     """
     if key in self._index:
         raise UniqKeyError(_("Key '%s' already exists") % key)
     self._index[key] = len(self._value_list)
     self._key_list.append(key)
     self._value_list.append(value)
Esempio n. 27
0
def getHachoirOptions(parser):
    """
    Create an option group (type optparse.OptionGroup) of Hachoir
    library options.
    """
    def setLogFilename(*args):
        log.setFilename(args[2])

    common = OptionGroup(parser, _("Hachoir library"), \
        "Configure Hachoir library")
    common.add_option("--verbose", help=_("Verbose mode"),
        default=False, action="store_true")
    common.add_option("--log", help=_("Write log in a file"),
        type="string", action="callback", callback=setLogFilename)
    common.add_option("--quiet", help=_("Quiet mode (don't display warning)"),
        default=False, action="store_true")
    common.add_option("--debug", help=_("Debug mode"),
        default=False, action="store_true")
    return common
Esempio n. 28
0
    def __setattr__(self, key, value):
        """
        Add a new value to data with name 'key'. Skip duplicates.
        """
        # Invalid key?
        if key not in self.__data:
            raise KeyError(_("%s has no metadata '%s'") % (self.__class__.__name__, key))

        # Skip duplicates
        self.__data[key].add(value)
    def __setattr__(self, key, value):
        """
        Add a new value to data with name 'key'. Skip duplicates.
        """
        # Invalid key?
        if key not in self.__data:
            raise KeyError(
                _("%s has no metadata '%s'") % (self.__class__.__name__, key))

        # Skip duplicates
        self.__data[key].add(value)
 def extract(self, pcx):
     self.width = 1 + pcx["xmax"].value
     self.height = 1 + pcx["ymax"].value
     self.width_dpi = pcx["horiz_dpi"].value
     self.height_dpi = pcx["vert_dpi"].value
     self.bits_per_pixel = pcx["bpp"].value
     if 1 <= pcx["bpp"].value <= 8:
         self.nb_colors = 2 ** pcx["bpp"].value
     self.compression = _("Run-length encoding (RLE)")
     self.format_version = "PCX: %s" % pcx["version"].display
     if "image_data" in pcx:
         computeComprRate(self, pcx["image_data"].size)
Esempio n. 31
0
 def extract(self, pcx):
     self.width = 1 + pcx["xmax"].value
     self.height = 1 + pcx["ymax"].value
     self.width_dpi = pcx["horiz_dpi"].value
     self.height_dpi = pcx["vert_dpi"].value
     self.bits_per_pixel = pcx["bpp"].value
     if 1 <= pcx["bpp"].value <= 8:
         self.nb_colors = 2 ** pcx["bpp"].value
     self.compression = _("Run-length encoding (RLE)")
     self.format_version = "PCX: %s" % pcx["version"].display
     if "image_data" in pcx:
         computeComprRate(self, pcx["image_data"].size)
    def insert(self, index, key, value):
        """
        Insert an item at specified position index.

        >>> d=Dict( ((6, 'six'), (9, 'neuf'), (4, 'quatre')) )
        >>> d.insert(1, '40', 'quarante')
        >>> d
        {6: 'six', '40': 'quarante', 9: 'neuf', 4: 'quatre'}
        """
        if key in self:
            raise UniqKeyError(_("Insert error: key '%s' ready exists") % key)
        _index = index
        if index < 0:
            index += len(self._value_list)
        if not(0 <= index <= len(self._value_list)):
            raise IndexError(_("Insert error: index '%s' is invalid") % _index)
        for item_key, item_index in self._index.iteritems():
            if item_index >= index:
                self._index[item_key] += 1
        self._index[key] = index
        self._key_list.insert(index, key)
        self._value_list.insert(index, value)
Esempio n. 33
0
def humanFilesize(size):
    """
    Convert a file size in byte to human natural representation.
    It uses the values: 1 KB is 1024 bytes, 1 MB is 1024 KB, etc.
    The result is an unicode string.

    >>> humanFilesize(1)
    u'1 byte'
    >>> humanFilesize(790)
    u'790 bytes'
    >>> humanFilesize(256960)
    u'250.9 KB'
    """
    if size < 10000:
        return ngettext("%u byte", "%u bytes", size) % size
    units = [_("KB"), _("MB"), _("GB"), _("TB")]
    size = float(size)
    divisor = 1024
    for unit in units:
        size = size / divisor
        if size < divisor:
            return "%.1f %s" % (size, unit)
    return "%u %s" % (size, unit)
Esempio n. 34
0
def humanFilesize(size):
    """
    Convert a file size in byte to human natural representation.
    It uses the values: 1 KB is 1024 bytes, 1 MB is 1024 KB, etc.
    The result is an unicode string.

    >>> humanFilesize(1)
    u'1 byte'
    >>> humanFilesize(790)
    u'790 bytes'
    >>> humanFilesize(256960)
    u'250.9 KB'
    """
    if size < 10000:
        return ngettext("%u byte", "%u bytes", size) % size
    units = [_("KB"), _("MB"), _("GB"), _("TB")]
    size = float(size)
    divisor = 1024
    for unit in units:
        size = size / divisor
        if size < divisor:
            return "%.1f %s" % (size, unit)
    return "%u %s" % (size, unit)
Esempio n. 35
0
def timestampMac32(value):
    """
    Convert an Mac (32-bit) timestamp to string. The format is the number
    of seconds since the 1st January 1904 (to 2040). Returns unicode string.

    >>> timestampMac32(0)
    datetime.datetime(1904, 1, 1, 0, 0)
    >>> timestampMac32(2843043290)
    datetime.datetime(1994, 2, 2, 14, 14, 50)
    """
    if not isinstance(value, (float, int, long)):
        raise TypeError("an integer or float is required")
    if not(0 <= value <= 4294967295):
        return _("invalid Mac timestamp (%s)") % value
    return MAC_TIMESTAMP_T0 + timedelta(seconds=value)
Esempio n. 36
0
def timestampMac32(value):
    """
    Convert an Mac (32-bit) timestamp to string. The format is the number
    of seconds since the 1st January 1904 (to 2040). Returns unicode string.

    >>> timestampMac32(0)
    datetime.datetime(1904, 1, 1, 0, 0)
    >>> timestampMac32(2843043290)
    datetime.datetime(1994, 2, 2, 14, 14, 50)
    """
    if not isinstance(value, (float, int, long)):
        raise TypeError("an integer or float is required")
    if not (0 <= value <= 4294967295):
        return _("invalid Mac timestamp (%s)") % value
    return MAC_TIMESTAMP_T0 + timedelta(seconds=value)
Esempio n. 37
0
def timestampWin64(value):
    """
    Convert Windows 64-bit timestamp to string. The timestamp format is
    a 64-bit number which represents number of 100ns since the
    1st January 1601 at 00:00. Result is an unicode string.
    See also durationWin64(). Maximum date is 28 may 60056.

    >>> timestampWin64(0)
    datetime.datetime(1601, 1, 1, 0, 0)
    >>> timestampWin64(127840491566710000)
    datetime.datetime(2006, 2, 10, 12, 45, 56, 671000)
    """
    try:
        return WIN64_TIMESTAMP_T0 + durationWin64(value)
    except OverflowError:
        raise ValueError(_("date newer than year %s (value=%s)") % (MAXYEAR, value))
Esempio n. 38
0
def timestampWin64(value):
    """
    Convert Windows 64-bit timestamp to string. The timestamp format is
    a 64-bit number which represents number of 100ns since the
    1st January 1601 at 00:00. Result is an unicode string.
    See also durationWin64(). Maximum date is 28 may 60056.

    >>> timestampWin64(0)
    datetime.datetime(1601, 1, 1, 0, 0)
    >>> timestampWin64(127840491566710000)
    datetime.datetime(2006, 2, 10, 12, 45, 56, 671000)
    """
    try:
        return WIN64_TIMESTAMP_T0 + durationWin64(value)
    except OverflowError:
        raise ValueError(
            _("date newer than year %s (value=%s)") % (MAXYEAR, value))
Esempio n. 39
0
def FileInputStream(filename, real_filename=None, **args):
    """
    Create an input stream of a file. filename must be unicode.

    real_filename is an optional argument used to specify the real filename,
    its type can be 'str' or 'unicode'. Use real_filename when you are
    not able to convert filename to real unicode string (ie. you have to
    use unicode(name, 'replace') or unicode(name, 'ignore')).
    """
    assert isinstance(filename, unicode)
    if not real_filename:
        real_filename = filename
    try:
        inputio = open(real_filename, "rb")
    except IOError, err:
        charset = getTerminalCharset()
        errmsg = unicode(str(err), charset)
        raise InputStreamError(_("Unable to open file %s: %s") % (filename, errmsg))
Esempio n. 40
0
 def _get(self, index):
     if index >= len(self.buffers):
         return ''
     buf = self.buffers[index]
     if buf is None:
         raise InputStreamError(_("Error: Buffers too small. Can't seek backward."))
     if self.last != index:
         next = buf[1]
         prev = buf[2]
         self.buffers[next][2] = prev
         self.buffers[prev][1] = next
         first = self.buffers[self.last][1]
         buf[1] = first
         buf[2] = self.last
         self.buffers[first][2] = index
         self.buffers[self.last][1] = index
         self.last = index
     return buf[0]
def FileInputStream(filename, real_filename=None, **args):
    """
    Create an input stream of a file. filename must be unicode.

    real_filename is an optional argument used to specify the real filename,
    its type can be 'str' or 'unicode'. Use real_filename when you are
    not able to convert filename to real unicode string (ie. you have to
    use unicode(name, 'replace') or unicode(name, 'ignore')).
    """
    assert isinstance(filename, unicode)
    if not real_filename:
        real_filename = filename
    try:
        inputio = open(real_filename, 'rb')
    except IOError, err:
        charset = getTerminalCharset()
        errmsg = unicode(str(err), charset)
        raise InputStreamError(_("Unable to open file %s: %s") % (filename, errmsg))
Esempio n. 42
0
 def __init__(self, input, size=None, **args):
     if not hasattr(input, "seek"):
         if size is None:
             input = InputPipe(input, self._setSize)
         else:
             input = InputPipe(input)
     elif size is None:
         try:
             input.seek(0, 2)
             size = input.tell() * 8
         except IOError, err:
             if err.errno == ESPIPE:
                 input = InputPipe(input, self._setSize)
             else:
                 charset = getTerminalCharset()
                 errmsg = unicode(str(err), charset)
                 source = args.get("source", "<inputio:%r>" % input)
                 raise InputStreamError(_("Unable to get size of %s: %s") % (source, errmsg))
Esempio n. 43
0
    def computeQuality(self, jpeg):
        # This function is an adaption to Python of ImageMagick code
        # to compute JPEG quality using quantization tables

        # Read quantization tables
        qtlist = []
        for dqt in jpeg.array("quantization"):
            for qt in dqt.array("content/qt"):
                # TODO: Take care of qt["index"].value?
                qtlist.append(qt)
        if not qtlist:
            return

        # Compute sum of all coefficients
        sumcoeff = 0
        for qt in qtlist:
            coeff = qt.array("coeff")
            for index in xrange(64):
                sumcoeff += coeff[index].value

        # Choose the right quality table and compute hash value
        try:
            hashval = qtlist[0]["coeff[2]"].value + qtlist[0]["coeff[53]"].value
            if 2 <= len(qtlist):
                hashval += qtlist[1]["coeff[0]"].value + qtlist[1][
                    "coeff[63]"].value
                hashtable = QUALITY_HASH_COLOR
                sumtable = QUALITY_SUM_COLOR
            else:
                hashtable = QUALITY_HASH_GRAY
                sumtable = QUALITY_SUM_GRAY
        except (MissingField, IndexError):
            # A coefficient is missing, so don't compute JPEG quality
            return

        # Find the JPEG quality
        for index in xrange(100):
            if (hashval >= hashtable[index]) or (sumcoeff >= sumtable[index]):
                quality = "%s%%" % (index + 1)
                if (hashval > hashtable[index]) or (sumcoeff >
                                                    sumtable[index]):
                    quality += " " + _("(approximate)")
                self.comment = "JPEG quality: %s" % quality
                return
Esempio n. 44
0
 def createDisplay(self, human=True):
     if not human:
         if self._raw_value is None:
             self._raw_value = GenericString.createValue(self, False)
         value = makePrintable(self._raw_value, "ASCII", to_unicode=True)
     elif self._charset:
         value = makePrintable(self.value, "ISO-8859-1", to_unicode=True)
     else:
         value = self.value
     if config.max_string_length < len(value):
         # Truncate string if needed
         value = "%s(...)" % value[:config.max_string_length]
     if not self._charset or not human:
         return makePrintable(value, "ASCII", quote='"', to_unicode=True)
     else:
         if value:
             return '"%s"' % value.replace('"', '\\"')
         else:
             return _("(empty)")
Esempio n. 45
0
def timestampUUID60(value):
    """
    Convert UUID 60-bit timestamp to string. The timestamp format is
    a 60-bit number which represents number of 100ns since the
    the 15 October 1582 at 00:00. Result is an unicode string.

    >>> timestampUUID60(0)
    datetime.datetime(1582, 10, 15, 0, 0)
    >>> timestampUUID60(130435676263032368)
    datetime.datetime(1996, 2, 14, 5, 13, 46, 303236)
    """
    if not isinstance(value, (float, int, long)):
        raise TypeError("an integer or float is required")
    if value < 0:
        raise ValueError("value have to be a positive or nul integer")
    try:
        return UUID60_TIMESTAMP_T0 + timedelta(microseconds=value/10)
    except OverflowError:
        raise ValueError(_("timestampUUID60() overflow (value=%s)") % value)
Esempio n. 46
0
 def __init__(self, input, size=None, **args):
     if not hasattr(input, "seek"):
         if size is None:
             input = InputPipe(input, self._setSize)
         else:
             input = InputPipe(input)
     elif size is None:
         try:
             input.seek(0, 2)
             size = input.tell() * 8
         except IOError, err:
             if err.errno == ESPIPE:
                 input = InputPipe(input, self._setSize)
             else:
                 charset = getTerminalCharset()
                 errmsg = unicode(str(err), charset)
                 source = args.get("source", "<inputio:%r>" % input)
                 raise InputStreamError(
                     _("Unable to get size of %s: %s") % (source, errmsg))
Esempio n. 47
0
 def _get(self, index):
     if index >= len(self.buffers):
         return ''
     buf = self.buffers[index]
     if buf is None:
         raise InputStreamError(
             _("Error: Buffers too small. Can't seek backward."))
     if self.last != index:
         next = buf[1]
         prev = buf[2]
         self.buffers[next][2] = prev
         self.buffers[prev][1] = next
         first = self.buffers[self.last][1]
         buf[1] = first
         buf[2] = self.last
         self.buffers[first][2] = index
         self.buffers[self.last][1] = index
         self.last = index
     return buf[0]
Esempio n. 48
0
def timestampUUID60(value):
    """
    Convert UUID 60-bit timestamp to string. The timestamp format is
    a 60-bit number which represents number of 100ns since the
    the 15 October 1582 at 00:00. Result is an unicode string.

    >>> timestampUUID60(0)
    datetime.datetime(1582, 10, 15, 0, 0)
    >>> timestampUUID60(130435676263032368)
    datetime.datetime(1996, 2, 14, 5, 13, 46, 303236)
    """
    if not isinstance(value, (float, int, long)):
        raise TypeError("an integer or float is required")
    if value < 0:
        raise ValueError("value have to be a positive or nul integer")
    try:
        return UUID60_TIMESTAMP_T0 + timedelta(microseconds=value / 10)
    except OverflowError:
        raise ValueError(_("timestampUUID60() overflow (value=%s)") % value)
Esempio n. 49
0
 def createDisplay(self, human=True):
     if not human:
         if self._raw_value is None:
             self._raw_value = GenericString.createValue(self, False)
         value = makePrintable(self._raw_value, "ASCII", to_unicode=True)
     elif self._charset:
         value = makePrintable(self.value, "ISO-8859-1", to_unicode=True)
     else:
         value = self.value
     if config.max_string_length < len(value):
         # Truncate string if needed
         value = "%s(...)" % value[:config.max_string_length]
     if not self._charset or not human:
         return makePrintable(value, "ASCII", quote='"', to_unicode=True)
     else:
         if value:
             return '"%s"' % value.replace('"', '\\"')
         else:
             return _("(empty)")
Esempio n. 50
0
    def computeQuality(self, jpeg):
        # This function is an adaption to Python of ImageMagick code
        # to compute JPEG quality using quantization tables

        # Read quantization tables
        qtlist = []
        for dqt in jpeg.array("quantization"):
            for qt in dqt.array("content/qt"):
                # TODO: Take care of qt["index"].value?
                qtlist.append(qt)
        if not qtlist:
            return

        # Compute sum of all coefficients
        sumcoeff = 0
        for qt in qtlist:
           coeff = qt.array("coeff")
           for index in xrange(64):
                sumcoeff += coeff[index].value

        # Choose the right quality table and compute hash value
        try:
            hashval= qtlist[0]["coeff[2]"].value +  qtlist[0]["coeff[53]"].value
            if 2 <= len(qtlist):
                hashval += qtlist[1]["coeff[0]"].value + qtlist[1]["coeff[63]"].value
                hashtable = QUALITY_HASH_COLOR
                sumtable = QUALITY_SUM_COLOR
            else:
                hashtable = QUALITY_HASH_GRAY
                sumtable = QUALITY_SUM_GRAY
        except (MissingField, IndexError):
            # A coefficient is missing, so don't compute JPEG quality
            return

        # Find the JPEG quality
        for index in xrange(100):
            if (hashval >= hashtable[index]) or (sumcoeff >= sumtable[index]):
                quality = "%s%%" % (index + 1)
                if (hashval > hashtable[index]) or (sumcoeff > sumtable[index]):
                    quality += " " + _("(approximate)")
                self.comment = "JPEG quality: %s" % quality
                return
Esempio n. 51
0
 def _getValue(self):
     try:
         value = self.createValue()
     except HACHOIR_ERRORS, err:
         self.error(_("Unable to create value: %s") % unicode(err))
         value = None
class JpegMetadata(RootMetadata):
    EXIF_KEY = {
        # Exif metadatas
        ExifEntry.TAG_CAMERA_MANUFACTURER: "camera_manufacturer",
        ExifEntry.TAG_CAMERA_MODEL: "camera_model",
        ExifEntry.TAG_ORIENTATION: "image_orientation",
        ExifEntry.TAG_EXPOSURE: "camera_exposure",
        ExifEntry.TAG_FOCAL: "camera_focal",
        ExifEntry.TAG_BRIGHTNESS: "camera_brightness",
        ExifEntry.TAG_APERTURE: "camera_aperture",

        # Generic metadatas
        ExifEntry.TAG_IMG_TITLE: "title",
        ExifEntry.TAG_SOFTWARE: "producer",
        ExifEntry.TAG_FILE_TIMESTAMP: "creation_date",
        ExifEntry.TAG_WIDTH: "width",
        ExifEntry.TAG_HEIGHT: "height",
        ExifEntry.TAG_USER_COMMENT: "comment",
    }

    IPTC_KEY = {
         80: "author",
         90: "city",
        101: "country",
        116: "copyright",
        120: "title",
        231: "comment",
    }

    orientation_name = {
        1: _('Horizontal (normal)'),
        2: _('Mirrored horizontal'),
        3: _('Rotated 180'),
        4: _('Mirrored vertical'),
        5: _('Mirrored horizontal then rotated 90 counter-clock-wise'),
        6: _('Rotated 90 clock-wise'),
        7: _('Mirrored horizontal then rotated 90 clock-wise'),
        8: _('Rotated 90 counter clock-wise'),
    }

    def extract(self, jpeg):
        if "start_frame/content" in jpeg:
            self.startOfFrame(jpeg["start_frame/content"])
        elif "start_scan/content/nr_components" in jpeg:
            self.bits_per_pixel = 8 * jpeg["start_scan/content/nr_components"].value
        if "app0/content" in jpeg:
            self.extractAPP0(jpeg["app0/content"])

        if "exif/content" in jpeg:
            for ifd in jpeg.array("exif/content/ifd"):
                for entry in ifd.array("entry"):
                    self.processIfdEntry(ifd, entry)
                self.readGPS(ifd)
        if "photoshop/content" in jpeg:
            psd = jpeg["photoshop/content"]
            if "version/content/reader_name" in psd:
                self.producer = psd["version/content/reader_name"].value
            if "iptc/content" in psd:
                self.parseIPTC(psd["iptc/content"])
        for field in jpeg.array("comment"):
            if "content/comment" in field:
                self.comment = field["content/comment"].value
        self.computeQuality(jpeg)
        if "data" in jpeg:
            computeComprRate(self, jpeg["data"].size)
        if not self.has("producer") and "photoshop" in jpeg:
            self.producer = u"Adobe Photoshop"
        if self.has("compression"):
            self.compression = "JPEG"

    @fault_tolerant
    def startOfFrame(self, sof):
        # Set compression method
        key = sof["../type"].value
        self.compression = "JPEG (%s)" % JpegChunk.START_OF_FRAME[key]

        # Read image size and bits/pixel
        self.width = sof["width"].value
        self.height = sof["height"].value
        nb_components = sof["nr_components"].value
        self.bits_per_pixel = 8 * nb_components
        if nb_components == 3:
            self.pixel_format = _("YCbCr")
        elif nb_components == 1:
            self.pixel_format = _("Grayscale")
            self.nb_colors = 256

    @fault_tolerant
    def computeQuality(self, jpeg):
        # This function is an adaption to Python of ImageMagick code
        # to compute JPEG quality using quantization tables

        # Read quantization tables
        qtlist = []
        for dqt in jpeg.array("quantization"):
            for qt in dqt.array("content/qt"):
                # TODO: Take care of qt["index"].value?
                qtlist.append(qt)
        if not qtlist:
            return

        # Compute sum of all coefficients
        sumcoeff = 0
        for qt in qtlist:
           coeff = qt.array("coeff")
           for index in xrange(64):
                sumcoeff += coeff[index].value

        # Choose the right quality table and compute hash value
        try:
            hashval= qtlist[0]["coeff[2]"].value +  qtlist[0]["coeff[53]"].value
            if 2 <= len(qtlist):
                hashval += qtlist[1]["coeff[0]"].value + qtlist[1]["coeff[63]"].value
                hashtable = QUALITY_HASH_COLOR
                sumtable = QUALITY_SUM_COLOR
            else:
                hashtable = QUALITY_HASH_GRAY
                sumtable = QUALITY_SUM_GRAY
        except (MissingField, IndexError):
            # A coefficient is missing, so don't compute JPEG quality
            return

        # Find the JPEG quality
        for index in xrange(100):
            if (hashval >= hashtable[index]) or (sumcoeff >= sumtable[index]):
                quality = "%s%%" % (index + 1)
                if (hashval > hashtable[index]) or (sumcoeff > sumtable[index]):
                    quality += " " + _("(approximate)")
                self.comment = "JPEG quality: %s" % quality
                return

    @fault_tolerant
    def extractAPP0(self, app0):
        self.format_version = u"JFIF %u.%02u" \
            % (app0["ver_maj"].value, app0["ver_min"].value)
        if "y_density" in app0:
            self.width_dpi = app0["x_density"].value
            self.height_dpi = app0["y_density"].value

    @fault_tolerant
    def processIfdEntry(self, ifd, entry):
        # Skip unknown tags
        tag = entry["tag"].value
        if tag not in self.EXIF_KEY:
            return
        key = self.EXIF_KEY[tag]
        if key in ("width", "height") and self.has(key):
            # EXIF "valid size" are sometimes not updated when the image is scaled
            # so we just ignore it
            return

        # Read value
        if "value" in entry:
            value = entry["value"].value
        else:
            value = ifd["value_%s" % entry.name].value

        # Convert value to string
        if tag == ExifEntry.TAG_ORIENTATION:
            value = self.orientation_name.get(value, value)
        elif tag == ExifEntry.TAG_EXPOSURE:
            if not value:
                return
            if isinstance(value, float):
                value = (value, u"1/%g" % (1/value))
        elif entry["type"].value in (ExifEntry.TYPE_RATIONAL, ExifEntry.TYPE_SIGNED_RATIONAL):
            value = (value, u"%.3g" % value)

        # Store information
        setattr(self, key, value)

    @fault_tolerant
    def readGPS(self, ifd):
        # Read latitude and longitude
        latitude_ref = None
        longitude_ref = None
        latitude = None
        longitude = None
        altitude_ref = 1
        altitude = None
        timestamp = None
        datestamp = None
        for entry in ifd.array("entry"):
            tag = entry["tag"].value
            if tag == ExifEntry.TAG_GPS_LATITUDE_REF:
                if entry["value"].value == "N":
                    latitude_ref = 1
                else:
                    latitude_ref = -1
            elif tag == ExifEntry.TAG_GPS_LONGITUDE_REF:
                if entry["value"].value == "E":
                    longitude_ref = 1
                else:
                    longitude_ref = -1
            elif tag == ExifEntry.TAG_GPS_ALTITUDE_REF:
                if entry["value"].value == 1:
                    altitude_ref = -1
                else:
                    altitude_ref = 1
            elif tag == ExifEntry.TAG_GPS_LATITUDE:
                latitude = [ifd["value_%s[%u]" % (entry.name, index)].value for index in xrange(3)]
            elif tag == ExifEntry.TAG_GPS_LONGITUDE:
                longitude = [ifd["value_%s[%u]" % (entry.name, index)].value for index in xrange(3)]
            elif tag == ExifEntry.TAG_GPS_ALTITUDE:
                altitude = ifd["value_%s" % entry.name].value
            elif tag == ExifEntry.TAG_GPS_DATESTAMP:
                datestamp = ifd["value_%s" % entry.name].value
            elif tag == ExifEntry.TAG_GPS_TIMESTAMP:
                items = [ifd["value_%s[%u]" % (entry.name, index)].value for index in xrange(3)]
                items = map(int, items)
                items = map(str, items)
                timestamp = ":".join(items)
        if latitude_ref and latitude:
            value = deg2float(*latitude)
            if latitude_ref < 0:
                value = -value
            self.latitude = value
        if longitude and longitude_ref:
            value = deg2float(*longitude)
            if longitude_ref < 0:
                value = -value
            self.longitude = value
        if altitude:
            value = altitude
            if altitude_ref < 0:
                value = -value
            self.altitude = value
        if datestamp:
            if timestamp:
                datestamp += " " + timestamp
            self.creation_date = datestamp

    def parseIPTC(self, iptc):
        datestr = hourstr = None
        for field in iptc:
            # Skip incomplete field
            if "tag" not in field or "content" not in field:
                continue

            # Get value
            value = field["content"].value
            if isinstance(value, (str, unicode)):
                value = value.replace("\r", " ")
                value = value.replace("\n", " ")

            # Skip unknown tag
            tag = field["tag"].value
            if tag == 55:
                datestr = value
                continue
            if tag == 60:
                hourstr = value
                continue
            if tag not in self.IPTC_KEY:
                if tag != 0:
                    self.warning("Skip IPTC key %s: %s" % (
                        field["tag"].display, makeUnicode(value)))
                continue
            setattr(self, self.IPTC_KEY[tag], value)
        if datestr and hourstr:
            try:
                year = int(datestr[0:4])
                month = int(datestr[4:6])
                day = int(datestr[6:8])
                hour = int(hourstr[0:2])
                min = int(hourstr[2:4])
                sec = int(hourstr[4:6])
                self.creation_date = datetime(year, month, day, hour, min, sec)
            except ValueError:
                pass
Esempio n. 53
0
                    for key, value in self.parser_args.iteritems():
                        setattr(parser_obj, key, value)
                return parser_obj
            except ValidateError, err:
                res = unicode(err)
                if fallback and self.fallback:
                    fb = parser
            except HACHOIR_ERRORS, err:
                res = unicode(err)
            if warn:
                if parser == self.other:
                    warn = info
                warn(_("Skip parser '%s': %s") % (parser.__name__, res))
            fallback = False
        if self.use_fallback and fb:
            warning(_("Force use of parser '%s'") % fb.__name__)
            return fb(stream)


def guessParser(stream):
    return QueryParser(stream.tags).parse(stream)


def createParser(filename, real_filename=None, tags=None):
    """
    Create a parser from a file or returns None on error.

    Options:
    - filename (unicode): Input file name ;
    - real_filename (str|unicode): Real file name.
    """
Esempio n. 54
0
from lib.hachoir_core.i18n import _, ngettext

NB_CHANNEL_NAME = {1: _("mono"), 2: _("stereo")}

def humanAudioChannel(value):
    return NB_CHANNEL_NAME.get(value, unicode(value))

def humanFrameRate(value):
    if isinstance(value, (int, long, float)):
        return _("%.1f fps") % value
    else:
        return value

def humanComprRate(rate):
    return u"%.1fx" % rate

def humanAltitude(value):
    return ngettext("%.1f meter", "%.1f meters", value) % value

def humanPixelSize(value):
    return ngettext("%s pixel", "%s pixels", value) % value

def humanDPI(value):
    return u"%s DPI" % value

Esempio n. 55
0
def humanFrameRate(value):
    if isinstance(value, (int, long, float)):
        return _("%.1f fps") % value
    else:
        return value
Esempio n. 56
0
 def processMovieHeader(self, hdr):
     self.creation_date = hdr["creation_date"].value
     self.last_modification = hdr["lastmod_date"].value
     self.duration = timedelta(seconds=float(hdr["duration"].value) / hdr["time_scale"].value)
     self.comment = _("Play speed: %.1f%%") % (hdr["play_speed"].value*100)
     self.comment = _("User volume: %.1f%%") % (float(hdr["volume"].value)*100//255)