def qimage2numpy(qimage: QImage): """Convert QImage to numpy.ndarray. The dtype defaults to uint8 for QImage.Format_Indexed8 or `bgra_dtype` (i.e. a record array) for 32bit color images. You can pass a different dtype to use, or 'array' to get a 3D uint8 array for color images.""" result_shape = (qimage.height(), qimage.width()) temp_shape = (qimage.height(), int(qimage.bytesPerLine() * 8 / qimage.depth())) if qimage.format() in (QImage.Format_ARGB32_Premultiplied, QImage.Format_ARGB32, QImage.Format_RGB32): dtype = np.uint8 result_shape += (4,) temp_shape += (4,) elif qimage.format() == QtGui.QImage.Format_Indexed8: dtype = np.uint8 else: raise ValueError("qimage2numpy only supports 32bit and 8bit images") # FIXME: raise error if alignment does not match buf = qimage.bits().asstring(qimage.byteCount()) result = np.frombuffer(buf, dtype).reshape(temp_shape) if result_shape != temp_shape: result = result[:, :result_shape[1]] if qimage.format() == QImage.Format_RGB32 and dtype == np.uint8: result = result[..., :3] return result
def save_thumbnail(self, full_file_name: str, size: int, modification_time: Union[float, int], generation_failed: bool, thumbnail: QImage, camera_model: str = None, free_desktop_org: bool = True) -> str: """ Save a thumbnail in the thumbnail cache. :param full_file_name: full path of the file (including file name). If the path contains symbolic links, two thumbnails will be saved: the canonical path (without symlinks), and the path as passed. :param size: size of the file in bytes :param modification_time: file modification time, to be turned into a float if it's not already :param generation_failed: True if the thumbnail is meant to signify the application failed to generate the thumbnail. If so, it will be saved as an empty PNG in the application subdirectory in the fail cache directory. :param thumbnail: the thumbnail to be saved. Will not be resized. Will be ignored if generation_failed is True. :param camera_model: optional camera model. If the thumbnail is not from a camera, then should be None. :param free_desktop_org: if True, then image will be convereted to 8bit mode if necessary :return the md5_name of the saved file, else None if operation failed """ if not self.valid: return None # Save to both the real path and the path passed, which may include # symbolic links full_file_name_real_path = os.path.realpath(full_file_name) if full_file_name_real_path != full_file_name: self.save_thumbnail(full_file_name_real_path, size, modification_time, generation_failed, thumbnail, camera_model, free_desktop_org) md5_name, uri = self.md5.md5_hash_name(full_file_name, camera_model) if generation_failed: thumbnail = QImage(QSize(1, 1), QImage.Format_Indexed8) save_dir = self.failure_dir else: save_dir = self.cache_dir path = os.path.join(save_dir, md5_name) thumbnail.setText('Thumb::URI', uri) thumbnail.setText('Thumb::MTime', str(float(modification_time))) thumbnail.setText('Thumb::Size', str(size)) if free_desktop_org and not generation_failed: if thumbnail.depth() != 8: thumbnail = thumbnail.convertToFormat(QImage.Format_Indexed8) temp_path = os.path.join(save_dir, self.random_filename.name(extension='png')) if thumbnail.save(temp_path): os.rename(temp_path, path) os.chmod(path, 0o600) if generation_failed: logging.debug("Wrote {}x{} thumbnail {} for {}".format( thumbnail.width(), thumbnail.height(), path, uri)) return md5_name else: return None
def qimage_to_numpy(image: gui.QImage): ptr = image.bits() w, h, d = image.width(), image.height(), image.depth() ptr.setsize(w * h * 4) return np.array(ptr).reshape(h, w, 4)