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
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
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)
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 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)
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 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")
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)
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
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
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
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 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
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 extractAVI(self, headers, **kwargs): 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? scan_index = (True, kwargs['scan_index'])['scan_index' in kwargs] if scan_index and "/index" in headers: self.comment = _("Has audio/video index (%s)") \ % humanFilesize(headers["/index"].size // 8)
def _getValue(self): try: value = self.createValue() except Exception as err: self.error(_("Unable to create value: %s") % unicode(err)) value = None self._getValue = lambda: value return value
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)
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)
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)
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)
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)
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))
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))
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)")
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)
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))
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))
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 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
def doparse(self, stream, fallback=True): fb = None warn = warning for parser in self.parsers: try: parser_obj = parser(stream, validate=self.validate) if self.parser_args: for key, value in self.parser_args.iteritems(): setattr(parser_obj, key, value) return parser_obj except ValidateError as err: if fallback and self.fallback: fb = parser if parser == self.other: warn = info warn("Skip parser '%s': %s" % (parser.__name__, err)) except Exception as err: if parser == self.other: warn = info warn("Skip parser '%s': %s" % (parser.__name__, err)) fallback = False if self.use_fallback and fb: warning(_("Force use of parser '%s'") % fb.__name__) return fb(stream)
from 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
def registerAllItems(meta): meta.register(Data("title", 100, _("Title"), type=unicode)) meta.register(Data("artist", 101, _("Artist"), type=unicode)) meta.register(Data("author", 102, _("Author"), type=unicode)) meta.register(Data("music_composer", 103, _("Music composer"), type=unicode)) meta.register(Data("album", 200, _("Album"), type=unicode)) meta.register(Data("duration", 201, _("Duration"), # integer in milliseconde type=timedelta, text_handler=humanDuration, filter=DURATION_FILTER)) meta.register(Data("nb_page", 202, _("Nb page"), filter=NumberFilter(1, MAX_NB_PAGE))) meta.register(Data("music_genre", 203, _("Music genre"), type=unicode)) meta.register(Data("language", 204, _("Language"), conversion=setLanguage, type=Language)) meta.register(Data("track_number", 205, _("Track number"), conversion=setTrackNumber, filter=NumberFilter(1, MAX_TRACK), type=(int, long))) meta.register(Data("track_total", 206, _("Track total"), conversion=setTrackTotal, filter=NumberFilter(1, MAX_TRACK), type=(int, long))) meta.register(Data("organization", 210, _("Organization"), type=unicode)) meta.register(Data("version", 220, _("Version"))) meta.register(Data("width", 301, _("Image width"), filter=NumberFilter(1, MAX_WIDTH), type=(int, long), text_handler=humanPixelSize)) meta.register(Data("height", 302, _("Image height"), filter=NumberFilter(1, MAX_HEIGHT), type=(int, long), text_handler=humanPixelSize)) meta.register(Data("nb_channel", 303, _("Channel"), text_handler=humanAudioChannel, filter=NumberFilter(1, MAX_NB_CHANNEL), type=(int, long))) meta.register(Data("sample_rate", 304, _("Sample rate"), text_handler=humanFrequency, filter=NumberFilter(MIN_SAMPLE_RATE, MAX_SAMPLE_RATE), type=(int, long, float))) meta.register(Data("bits_per_sample", 305, _("Bits/sample"), text_handler=humanBitSize, filter=NumberFilter(1, 64), type=(int, long))) meta.register(Data("image_orientation", 306, _("Image orientation"))) meta.register(Data("nb_colors", 307, _("Number of colors"), filter=NumberFilter(1, MAX_NB_COLOR), type=(int, long))) meta.register(Data("bits_per_pixel", 308, _("Bits/pixel"), filter=NumberFilter(1, MAX_BITS_PER_PIXEL), type=(int, long))) meta.register(Data("filename", 309, _("File name"), type=unicode)) meta.register(Data("file_size", 310, _("File size"), text_handler=humanFilesize, type=(int, long))) meta.register(Data("pixel_format", 311, _("Pixel format"))) meta.register(Data("compr_size", 312, _("Compressed file size"), text_handler=humanFilesize, type=(int, long))) meta.register(Data("compr_rate", 313, _("Compression rate"), text_handler=humanComprRate, filter=NumberFilter(MIN_COMPR_RATE, MAX_COMPR_RATE), type=(int, long, float))) meta.register(Data("width_dpi", 320, _("Image DPI width"), filter=NumberFilter(1, MAX_DPI_WIDTH), type=(int, long), text_handler=humanDPI)) meta.register(Data("height_dpi", 321, _("Image DPI height"), filter=NumberFilter(1, MAX_DPI_HEIGHT), type=(int, long), text_handler=humanDPI)) meta.register(Data("file_attr", 400, _("File attributes"))) meta.register(Data("file_type", 401, _("File type"))) meta.register(Data("subtitle_author", 402, _("Subtitle author"), type=unicode)) meta.register(Data("creation_date", 500, _("Creation date"), text_handler=humanDatetime, filter=DATETIME_FILTER, type=(datetime, date), conversion=setDatetime)) meta.register(Data("last_modification", 501, _("Last modification"), text_handler=humanDatetime, filter=DATETIME_FILTER, type=(datetime, date), conversion=setDatetime)) meta.register(Data("latitude", 510, _("Latitude"), type=float)) meta.register(Data("longitude", 511, _("Longitude"), type=float)) meta.register(Data("altitude", 512, _("Altitude"), type=float, text_handler=humanAltitude)) meta.register(Data("location", 530, _("Location"), type=unicode)) meta.register(Data("city", 531, _("City"), type=unicode)) meta.register(Data("country", 532, _("Country"), type=unicode)) meta.register(Data("charset", 540, _("Charset"), type=unicode)) meta.register(Data("font_weight", 550, _("Font weight"))) meta.register(Data("camera_aperture", 520, _("Camera aperture"))) meta.register(Data("camera_focal", 521, _("Camera focal"))) meta.register(Data("camera_exposure", 522, _("Camera exposure"))) meta.register(Data("camera_brightness", 530, _("Camera brightness"))) meta.register(Data("camera_model", 531, _("Camera model"), type=unicode)) meta.register(Data("camera_manufacturer", 532, _("Camera manufacturer"), type=unicode)) meta.register(Data("compression", 600, _("Compression"))) meta.register(Data("copyright", 601, _("Copyright"), type=unicode)) meta.register(Data("url", 602, _("URL"), type=unicode)) meta.register(Data("frame_rate", 603, _("Frame rate"), text_handler=humanFrameRate, filter=NumberFilter(1, MAX_FRAME_RATE), type=(int, long, float))) meta.register(Data("bit_rate", 604, _("Bit rate"), text_handler=humanBitRate, filter=NumberFilter(1, MAX_BIT_RATE), type=(int, long, float))) meta.register(Data("aspect_ratio", 604, _("Aspect ratio"), type=(int, long, float))) meta.register(Data("thumbnail_size", 604, _("Thumbnail size"), text_handler=humanFilesize, type=(int, long, float))) meta.register(Data("iso_speed_ratings", 800, _("ISO speed rating"))) meta.register(Data("exif_version", 801, _("EXIF version"))) meta.register(Data("date_time_original", 802, _("Date-time original"), text_handler=humanDatetime, filter=DATETIME_FILTER, type=(datetime, date), conversion=setDatetime)) meta.register(Data("date_time_digitized", 803, _("Date-time digitized"), text_handler=humanDatetime, filter=DATETIME_FILTER, type=(datetime, date), conversion=setDatetime)) meta.register(Data("compressed_bits_per_pixel", 804, _("Compressed bits per pixel"), type=(int, long, float))) meta.register(Data("shutter_speed_value", 805, _("Shutter speed"), type=(int, long, float))) meta.register(Data("aperture_value", 806, _("Aperture"))) meta.register(Data("exposure_bias_value", 807, _("Exposure bias"))) meta.register(Data("focal_length", 808, _("Focal length"))) meta.register(Data("flashpix_version", 809, _("Flashpix version"))) meta.register(Data("focal_plane_x_resolution", 810, _("Focal plane width"))) meta.register(Data("focal_plane_y_resolution", 811, _("Focal plane height"), type=float)) meta.register(Data("focal_length_in_35mm_film", 812, _("Focal length in 35mm film"))) meta.register(Data("os", 900, _("OS"), type=unicode)) meta.register(Data("producer", 901, _("Producer"), type=unicode)) meta.register(Data("comment", 902, _("Comment"), type=unicode)) meta.register(Data("format_version", 950, _("Format version"), type=unicode)) meta.register(Data("mime_type", 951, _("MIME type"), type=unicode)) meta.register(Data("endian", 952, _("Endianness"), type=unicode))
def humanFrameRate(value): if isinstance(value, (int, long, float)): return _("%.1f fps") % value else: return value
def _run(self, func, args, kw): """ Call func(*args, **kw) as many times as needed to get good statistics. Algorithm: - call the function once - compute needed number of calls - and then call function N times To compute number of calls, parameters are: - time of first function call - minimum number of calls (min_count attribute) - maximum test time (max_time attribute) Notice: The function will approximate number of calls. """ # First call of the benchmark stat = BenchmarkStat() diff = self._runOnce(func, args, kw) best = diff stat.append(diff) total_time = diff # Compute needed number of calls count = int(floor(self.max_time / diff)) count = max(count, self.min_count) if self.max_count: count = min(count, self.max_count) # Not other call? Just exit if count == 1: return stat estimate = diff * count if self.verbose: print _("Run benchmark: %s calls (estimate: %s)") \ % (count, self.formatTime(estimate)) display_progress = self.verbose and (1.0 <= estimate) total_count = 1 while total_count < count: # Run benchmark and display each result if display_progress: print _("Result %s/%s: %s (best: %s)") % \ (total_count, count, self.formatTime(diff), self.formatTime(best)) part = count - total_count # Will takes more than one second? average = total_time / total_count if self.progress_time < part * average: part = max(int(self.progress_time / average), 1) for index in xrange(part): diff = self._runOnce(func, args, kw) stat.append(diff) total_time += diff best = min(diff, best) total_count += part if display_progress: print _("Result %s/%s: %s (best: %s)") % \ (count, count, self.formatTime(diff), self.formatTime(best)) return stat