def dimensions_and_resize(max_dim: int, vault: Vault, sub_path: str, image_to_write: Bean) -> Optional[str]: """ Get dimensions from given image, return a string with the error in case of issue. It is assumed that the image is valid, i.e. did not throw an exception in above validate() """ im = PIL_Image.open(vault.path_to(sub_path)) image_to_write.width = im.size[0] image_to_write.height = im.size[1] # Generate a thumbnail if image is too large if (im.size[0] > max_dim) or (im.size[1] > max_dim): if im.mode == 'P' or im.mode[0] == 'I': # (8-bit pixels, mapped to any other mode using a color palette) # from https://pillow.readthedocs.io/en/latest/handbook/concepts.html#modes # Tested using a PNG with palette im = im.convert("RGB") im.thumbnail((max_dim, max_dim)) thumb_relative_path, thumb_full_path = vault.thumbnail_paths(image_to_write.imgid) im.save(thumb_full_path) image_to_write.thumb_file_name = thumb_relative_path image_to_write.thumb_width = im.size[0] image_to_write.thumb_height = im.size[1] else: # Close the PIL image, when resized it was done during im.save # Otherwise there is a FD exhaustion on PyPy im.close() # Need empty fields for bulk insert image_to_write.thumb_file_name = None image_to_write.thumb_width = None image_to_write.thumb_height = None return None
def dimensions_and_resize(max_dim: int, vault: Vault, sub_path: str, image_to_write: Bean) -> Optional[str]: try: im = PIL_Image.open(vault.path_to(sub_path)) except DecompressionBombError: return "Image too large: %s" % sub_path image_to_write.width = im.size[0] image_to_write.height = im.size[1] # Generate a thumbnail if image is too large if (im.size[0] > max_dim) or (im.size[1] > max_dim): im.thumbnail((max_dim, max_dim)) if im.mode == 'P': # (8-bit pixels, mapped to any other mode using a color palette) # from https://pillow.readthedocs.io/en/latest/handbook/concepts.html#modes # Tested using a PNG with palette im = im.convert("RGB") thumb_relative_path, thumb_full_path = vault.thumbnail_paths( image_to_write.imgid) im.save(thumb_full_path) image_to_write.thumb_file_name = thumb_relative_path image_to_write.thumb_width = im.size[0] image_to_write.thumb_height = im.size[1] else: # Close the PIL image, when resized it was done during im.save # Otherwise there is a FD exhaustion on PyPy im.close() # Need empty fields for bulk insert image_to_write.thumb_file_name = None image_to_write.thumb_width = None image_to_write.thumb_height = None return None
def deal_with_images(self, where: ImportWhere, how: ImportHow, image_to_write: Bean, instead_image: Path = None): """ Generate image, eventually the vignette, create DB line(s) and copy image file into vault. :param where: :param how: :param image_to_write: :param instead_image: Store this image instead of the one in Image record. :return: """ if instead_image: # Source file is a replacement img_file_path = instead_image else: # Files are in a subdirectory for UVP6, same directory for non-UVP6 # TODO: Unsure if it works on Windows, as there is a "/" for UVP6 img_file_path = self.path_for_image(image_to_write.orig_file_name) sub_path = where.vault.store_image(img_file_path, image_to_write.imgid) image_to_write.file_name = sub_path present_ranks = how.image_ranks_per_obj.setdefault( image_to_write.objid, set()) if image_to_write.get("imgrank") is None: self.compute_rank(image_to_write, present_ranks) else: # The TSV format is float image_to_write.imgrank = int(image_to_write.imgrank) if image_to_write.imgrank in present_ranks: tsv_rank = image_to_write.imgrank self.compute_rank(image_to_write, present_ranks) logger.info( 'For %s, cannot use rank from TSV %d, using %d instead', image_to_write.file_name, tsv_rank, image_to_write.imgrank) present_ranks.add(image_to_write.imgrank) err = ImageBO.dimensions_and_resize(how.max_dim, where.vault, sub_path, image_to_write) if err: logger.error(err + ", not copied")
def add_db_entities(self, object_head_to_write: Bean, object_fields_to_write: Bean, image_to_write: Optional[Bean], new_records: int): # Bulk mode or Core do not create links (using ORM relationship), so we have to do manually if new_records > 1: # There is a new image and more #assert object_head_to_write.projid is not None assert object_head_to_write.orig_id is not None # Default value from sequences object_head_to_write.objid = self.obj_seq_cache.next() object_fields_to_write.objfid = object_head_to_write.objid if new_records >= 1 and image_to_write: # There is (potentially just) a new image image_to_write.imgid = self.img_seq_cache.next() image_to_write.objid = object_head_to_write.objid if new_records > 1: # There is a new image and more self.obj_fields_bulks.append(object_fields_to_write) self.obj_bulks.append(object_head_to_write) if new_records >= 1 and image_to_write: # There is (potentially just) a new image self.img_bulks.append(image_to_write)
def do_sun_position_field(object_head_to_write: Bean): """ Initial compute or update of sun position field. """ # Default value, so there is something to write into the DB in case of problem object_head_to_write.sunpos = "?" # Is there enough data for computation? nb_fields = object_head_to_write.nb_fields_from(USED_FIELDS_FOR_SUNPOS) if nb_fields < len(USED_FIELDS_FOR_SUNPOS): if nb_fields > 0: # Warn if only a few fields, but not if 0 logger.warning("Not enough fields for computing sun position") return # All fields are in, so give it a try try: object_head_to_write.sunpos = compute_sun_position( object_head_to_write) except Exception as e: # See astral.py for cases # Astral error : Sun never reaches 12.0 degrees below the horizon, at this location. # for {'objtime': datetime.time(12, 29), 'latitude': -64.2, 'objdate': datetime.date(2011, 1, 9), # 'longitude': -52.59 } logger.error("Astral error : %s for %s", e, object_head_to_write)
def add_cnn_features(self, object_head_to_write, cnn_features: Bean): cnn_features.objcnnid = object_head_to_write.objid self.obj_cnn_bulks.append(cnn_features)