diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aa405f9..30a2cc5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,7 +26,7 @@ build: - job: gitversion artifacts: true script: - - sed -i "s/0.0.1/${GitVersion_MajorMinorPatch}/" src/optima35/__init__.py + - sed -i "s/1.0.0/${GitVersion_MajorMinorPatch}/" src/optima35/__init__.py - cat src/optima35/__init__.py - python3 -m pip install build - python3 -m build diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b241c9..7761952 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.0.0-rc: +### Refactoring +- Added function descriptions for better clarity and maintainability. +- Introduced guidelines for each function, defining objectives and expected behavior. + ## 0.12.x ### 0.12.2: Bug fixes - Fixed missing lens in meta data diff --git a/src/optima35/__init__.py b/src/optima35/__init__.py index f102a9c..5becc17 100644 --- a/src/optima35/__init__.py +++ b/src/optima35/__init__.py @@ -1 +1 @@ -__version__ = "0.0.1" +__version__ = "1.0.0" diff --git a/src/optima35/core.py b/src/optima35/core.py index 9ff8a53..664d51b 100644 --- a/src/optima35/core.py +++ b/src/optima35/core.py @@ -22,96 +22,184 @@ class OptimaManager: data_for_exif["date_time_original"] = new_time.strftime("%Y:%m:%d %H:%M:%S") return data_for_exif - def process_image(self, # TODO: split into two classes, one for modification for one saving.. - image_input_file, - image_output_file, - file_type = "jpg", - quality = 90, - compressing = 6, - optimize = False, - resize = None, - watermark = None, - font_size = 2, - grayscale = False, - brightness = None, - contrast = None, - dict_for_exif = None, - gps = None, - copy_exif = False, - save = True): - # Partly optimized by ChatGPT - # Open the image file - with self.image_processor.open_image(image_input_file) as img: - processed_img = img - image_name = os.path.basename(image_output_file) # for date adjustment - # Resize - if resize is not None: - processed_img = self.image_processor.resize_image( - image=processed_img, percent = resize + def _process_image( + self, + image_input_file: str, + resize: int = None, + watermark: str = None, + font_size: int = 2, + grayscale: bool = False, + brightness: float = None, + contrast: float = None + ): + # Restructured by ChatGPT, but had to fix bugs + img = self.image_processor.open_image(image_input_file) + # Apply transformations + if resize is not None: + print("Resize") + img = self.image_processor.resize_image(img, percent=resize) + if watermark is not None: + print("Watermark") + img = self.image_processor.add_watermark(img, watermark, font_size) + if grayscale: + print("Grayscale") + img = self.image_processor.grayscale(img) + if brightness is not None: + print("Brightness") + img = self.image_processor.change_brightness(img, brightness) + if contrast is not None: + print("Contrast") + img = self.image_processor.change_contrast(img, contrast) + return img + + def _handle_exif( + self, + image, + file_name, + dict_for_exif: dict = None, + gps: tuple[float, float] = None, + copy_exif: bool = False + ): + # Restructured by ChatGPT, but had to fix bugs + # Build or copy EXIF data + if dict_for_exif: + if "date_time_original" in dict_for_exif: + dict_for_exif = self.modify_timestamp_in_exif(dict_for_exif, file_name) + exif_data = self.exif_handler.build_exif_bytes( + dict_for_exif, self.image_processor.get_image_size(image) + ) + if gps: + exif_data = self.exif_handler.add_geolocation_to_exif( + exif_data, gps[0], gps[1] ) + elif copy_exif: + exif_data = self.exif_handler.get_exif_info(image) + else: + exif_data = None + return exif_data - # Watermark - if watermark is not None: - processed_img = self.image_processor.add_watermark( - processed_img, watermark, int(font_size) - ) + def process_and_save_image( + self, + image_input_file: str, + image_output_file: str, + file_type: str = "jpg", + quality: int = 90, + compressing: int = 6, + optimize: bool = False, + resize: int = None, + watermark: str = None, + font_size: int = 2, + grayscale: bool = False, + brightness: float = None, + contrast: float = None, + dict_for_exif: dict = None, + gps: tuple[float, float] = None, + copy_exif: bool = False + ) -> None: + """ + Processes an image with the given parameters and saves the output to a file. - # Grayscale - if grayscale: - processed_img = self.image_processor.grayscale(processed_img) + Args: + image_input_file (str): Path to the input image file. + image_output_file (str): Path to save the processed image. + file_type (str): Output image format ('jpg', 'png'). Defaults to 'jpg'. + quality (int): JPEG quality (1-100). Defaults to 90. + compressing (int): PNG compression level (0-9). Defaults to 6. + optimize (bool): Optimize image for smaller file size. Defaults to False. + resize (int, optional): Resize percentage. Defaults to None. + watermark (str, optional): Watermark text to add. Defaults to None. + font_size (int): Font size for the watermark. Defaults to 2. + grayscale (bool): Convert image to grayscale. Defaults to False. + brightness (float, optional): Adjust brightness (e.g., 1.2 for 20% brighter). Defaults to None. + contrast (float, optional): Adjust contrast (e.g., 1.5 for 50% higher contrast). Defaults to None. + dict_for_exif (dict, optional): EXIF metadata to insert. Defaults to None. + gps (tuple[float, float], optional): GPS coordinates (latitude, longitude). Defaults to None. + copy_exif (bool): Copy EXIF metadata from the input image. Defaults to False. - # Brightness - if brightness is not None: - processed_img = self.image_processor.change_brightness( - processed_img, brightness - ) + Returns: + None + """ + # Restructured by ChatGPT + processed_img = self._process_image( + image_input_file, + resize, + watermark, + font_size, + grayscale, + brightness, + contrast, + ) - # Contrast - if contrast is not None: - processed_img = self.image_processor.change_contrast( - processed_img, contrast - ) + # Handle EXIF metadata + exif_piexif_format = self._handle_exif( + image = processed_img, + file_name = image_output_file, + dict_for_exif = dict_for_exif, + gps = gps, + copy_exif = copy_exif + ) - # EXIF data handling - exif_piexif_format = None - if dict_for_exif: # todo: maybe move to ui and only accept complete exif dicts.. - selected_exif = dict_for_exif - if "date_time_original" in dict_for_exif: - selected_exif = self.modify_timestamp_in_exif(selected_exif, image_name) - exif_piexif_format = self.exif_handler.build_exif_bytes( - selected_exif, self.image_processor.get_image_size(processed_img) - ) + # Save the image + self.image_processor.save_image( + image = processed_img, + path = image_output_file, + piexif_exif_data = exif_piexif_format, + file_type = file_type, + jpg_quality = quality, + png_compressing = compressing, + optimize = optimize, + ) - # GPS data - if gps is not None: - latitude = float(gps[0]) - longitude = float(gps[1]) - exif_piexif_format = self.exif_handler.add_geolocation_to_exif(exif_piexif_format, latitude, longitude) + def process_image_object( + self, + image_input_file: str, + resize: int = None, + watermark: str = None, + font_size: int = 2, + grayscale: bool = False, + brightness: float = None, + contrast: float = None + ): + """ + Processes an image with the given parameters and returns the modified image object. - # Copy EXIF data if selected, and ensure size is correct in exif data - elif copy_exif: - try: - og_exif = self.exif_handler.get_exif_info(img) - og_exif["Exif"][40962], og_exif["Exif"][40963] = self.image_processor.get_image_size(processed_img) - exif_piexif_format = og_exif - except Exception: - print("Copying EXIF data selected, but no EXIF data is available in the original image file.") + Args: + image_input_file (str): Path to the input image file. + resize (int, optional): Resize percentage. Defaults to None. + watermark (str, optional): Watermark text to add. Defaults to None. + font_size (int): Font size for the watermark. Defaults to 2. + grayscale (bool): Convert image to grayscale. Defaults to False. + brightness (float, optional): Adjust brightness. Defaults to None. + contrast (float, optional): Adjust contrast. Defaults to None. - if save: - # Save the processed image - self.image_processor.save_image( - image = processed_img, - path = image_output_file, - piexif_exif_data = exif_piexif_format, - file_type = file_type, - jpg_quality = quality, - png_compressing = compressing, - optimize = optimize - ) - else: - return self.image_processor.convert_pil_to_qtimage(processed_img) + Returns: + Image: The processed image object. + """ + # Restructured by ChatGPT + processed_img = self._process_image( + image_input_file, + resize, + watermark, + font_size, + grayscale, + brightness, + contrast, + ) + return self.image_processor.convert_pil_to_qtimage(processed_img) - def insert_dict_to_image(self, exif_dict, image_path, gps = None): + def insert_exif_to_image(self, exif_dict: dict, image_path: str, gps: tuple[float, float] = None) -> None: + """ + Inserts EXIF metadata into an image. + + Args: + exif_data (dict): A dictionary containing EXIF metadata as key-value pairs (e.g., strings, integers). + image_path (str): Absolute path to the target image file. + gps (tuple[float, float], optional): GPS coordinates as a tuple (latitude, longitude). Defaults to None. + + Returns: + None: The function modifies the image file in place. + """ + # Restructured by ChatGPT image_name, ending = os.path.splitext(os.path.basename(image_path)) img = self.image_processor.open_image(image_path) selected_exif = exif_dict