def convert(value): if value['data'] and not value['image']: buf = QtCore.QBuffer() buf.setData(value['data']) reader = QtGui.QImageReader(buf) reader.setAutoTransform(False) value['fmt'] = reader.format().data().decode().upper() value['image'] = reader.read() if value['image'].isNull(): logger.error('thumbnail: %s', reader.errorString()) value['image'] = None # don't keep reference to what might be an entire image file value['data'] = None if value['image'] and not value['data']: buf = QtCore.QBuffer() buf.open(buf.WriteOnly) value['fmt'] = 'JPEG' value['image'].save(buf, value['fmt']) value['data'] = buf.data().data() if value['image']: value['w'] = value['image'].width() value['h'] = value['image'].height() else: value['w'] = 0 value['h'] = 0 return value
def to_xmp(self): fmt, data = self['fmt'], self['data'] if fmt != 'JPEG': data = None if self['image'] and not data: buf = QtCore.QBuffer() buf.open(buf.WriteOnly) fmt = 'JPEG' self['image'].save(buf, self['fmt'], 95) data = buf.data().data() data = codecs.encode(data, 'base64_codec').decode('ascii') return (str(self['w']), str(self['h']), fmt, data)
def make_thumb_Qt(self, qt_im): w, h = 160, 120 if qt_im.width() < qt_im.height(): w, h = h, w # scale Qt image - not as good quality as PIL qt_im = qt_im.scaled(w, h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) # save image to memory buf = QtCore.QBuffer() buf.open(QtCore.QIODevice.WriteOnly) fmt = 'JPEG' qt_im.save(buf, fmt) return buf.data().data(), fmt, qt_im.width(), qt_im.height()
def to_exif(self): fmt, data = self['fmt'], self['data'] if self['image'] and not data: buf = QtCore.QBuffer() buf.open(buf.WriteOnly) fmt = 'JPEG' quality = 95 while quality > 10: self['image'].save(buf, fmt, quality) data = buf.data().data() if len(data) < 60000: break data = None quality -= 5 return (str(self['w']), str(self['h']), fmt, data)
def make_thumb_PIL(self, qt_im): w, h = 160, 120 if qt_im.width() < qt_im.height(): w, h = h, w # convert Qt image to PIL image buf = QtCore.QBuffer() buf.open(QtCore.QIODevice.WriteOnly) qt_im.save(buf, 'PPM') data = BytesIO(buf.data().data()) pil_im = PIL.open(data) # scale PIL image pil_im.thumbnail((w, h), PIL.ANTIALIAS) # save image to memory data = BytesIO() fmt = 'JPEG' pil_im.save(data, fmt) return (data.getvalue(), fmt) + pil_im.size
def write(self, handler, tag): if handler.is_xmp_tag(tag): data = self.data if self.fmt != 'JPEG': pixmap = QtGui.QPixmap() pixmap.loadFromData(data) buf = QtCore.QBuffer() buf.open(QtCore.QIODevice.WriteOnly) pixmap.save(buf, 'JPEG') data = buf.data().data() w = pixmap.width() h = pixmap.height() else: w, h = self.size() data = codecs.encode(data, 'base64_codec') if not six.PY2: data = data.decode('ascii') handler.set_string(tag, (data, 'JPEG', str(w), str(h))) elif handler.is_exif_tag(tag): handler.set_exif_thumbnail_from_buffer(self.data)
def make_thumb_PIL(self, qt_im): w, h = 160, 120 if qt_im.width() < qt_im.height(): w, h = h, w # convert Qt image to PIL image buf = QtCore.QBuffer() buf.open(buf.WriteOnly) qt_im.save(buf, 'PPM') data = io.BytesIO(buf.data().data()) try: pil_im = PIL.open(data) except Exception as ex: logger.error(ex) return None # scale PIL image pil_im.thumbnail((w, h), PIL.ANTIALIAS) # save image to memory data = io.BytesIO() pil_im.save(data, 'JPEG') return data.getvalue()
def convert(value): if value['data'] and not value['image']: buf = QtCore.QBuffer() buf.setData(value['data']) reader = QtGui.QImageReader(buf) reader.setAutoTransform(False) value['fmt'] = reader.format().data().decode().upper() value['image'] = reader.read() if value['image'].isNull(): logger.error('thumbnail: %s', reader.errorString()) value['image'] = None if value['image']: value['w'] = value['image'].width() value['h'] = value['image'].height() if value['data'] and len(value['data']) >= 60000: # don't keep unusably large amount of data value['data'] = None else: value['w'] = 0 value['h'] = 0 value['data'] = None return value
def regenerate_thumbnail(self): with Busy(): # get Qt image first qt_im = QtGui.QImage(self.path) if self.file_type.startswith('video') and qt_im.isNull(): # use OpenCV to read first frame qt_im = self.get_video_frame() if not qt_im or qt_im.isNull(): logger.error('Cannot read %s image data from %s', self.file_type, self.path) return # reorient if required if self.file_type in ('image/x-canon-cr2', 'image/x-nikon-nef'): qt_im = self.transform(qt_im, self.metadata.orientation, inverse=True) w = qt_im.width() h = qt_im.height() # use Qt's scaling (not high quality) to pre-shrink very # large images, to avoid PIL "DecompressionBombWarning" if max(w, h) >= 6000: qt_im = qt_im.scaled(6000, 6000, Qt.KeepAspectRatio, Qt.SmoothTransformation) w = qt_im.width() h = qt_im.height() # DCF spec says thumbnail must be 160 x 120 so pad picture # to 4:3 aspect ratio if w >= h: new_h = int(0.5 + (float(w * 3) / 4.0)) new_w = int(0.5 + (float(h * 4) / 3.0)) if new_h > h: pad = (new_h - h) // 2 qt_im = qt_im.copy(0, -pad, w, new_h) elif new_w > w: pad = (new_w - w) // 2 qt_im = qt_im.copy(-pad, 0, new_w, h) w, h = 160, 120 else: new_h = int(0.5 + (float(w * 4) / 3.0)) new_w = int(0.5 + (float(h * 3) / 4.0)) if new_w > w: pad = (new_w - w) // 2 qt_im = qt_im.copy(-pad, 0, new_w, h) elif new_h > h: pad = (new_h - h) // 2 qt_im = qt_im.copy(0, -pad, w, new_h) w, h = 120, 160 fmt = 'JPEG' if PIL: # convert Qt image to PIL image buf = QtCore.QBuffer() buf.open(QtCore.QIODevice.WriteOnly) qt_im.save(buf, 'PPM') data = BytesIO(buf.data().data()) pil_im = PIL.open(data) # scale PIL image pil_im = pil_im.resize((w, h), PIL.ANTIALIAS) # save image to memory data = BytesIO() pil_im.save(data, fmt) data = data.getvalue() else: # scale Qt image - not as good quality as PIL qt_im = qt_im.scaled(w, h, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) # save image to memory buf = QtCore.QBuffer() buf.open(QtCore.QIODevice.WriteOnly) qt_im.save(buf, fmt) data = buf.data().data() # set thumbnail self.metadata.thumbnail = data, fmt, w, h # reload thumbnail self.load_thumbnail()