Skip to content

Commit

Permalink
Add readme
Browse files Browse the repository at this point in the history
  • Loading branch information
ggouzi committed Sep 5, 2022
1 parent 6a2b4d1 commit f341af1
Show file tree
Hide file tree
Showing 17 changed files with 126 additions and 17 deletions.
33 changes: 18 additions & 15 deletions ImageMerger.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def __get_image_from_url(self):
img = Image.open(u)
return img
except Exception as e:
# TODO raise exception
print(str(e))
print(traceback.format_exc())
return None
Expand All @@ -34,14 +35,6 @@ def __post_init__(self):
else:
self.content = Image.open(self.path)

def resize(self, basewidth=800):
if self.content is None:
return None
wpercent = (basewidth / float(self.content.size[0]))
hsize = int((float(self.content.size[1]) * float(wpercent)))
img = self.content.resize((basewidth, hsize), Image.Resampling.LANCZOS)
self.content = img


@dataclass
class Merger:
Expand All @@ -55,11 +48,12 @@ class Merger:
preserve_aspect_ratio: bool = False

def __nearest_square(self, limit):
# TODO: rework
sq = int((limit ** 0.5))
return sq

def __post_init__(self):
# self.list_images = [im.content for im in list_images]
self.list_images = [im.content for im in self.list_images]
warning_str = (f"Warning: limit_horizontal({self.limit_horizontal})*limit_vertical({self.limit_vertical}) is smaller than image set size({len(self.list_images)}). Output will not contain all images")

if self.shuffle:
Expand All @@ -69,9 +63,9 @@ def __post_init__(self):
self.limit_horizontal = len(self.list_images) / self.limit_vertical

elif self.limit_vertical and self.limit_horizontal:
print(warning_str)
m = self.limit_vertical * self.limit_horizontal
if m < len(self.list_images):
print(warning_str)
self.list_images = self.list_images[0:m]
self.limit_horizontal = self.limit_horizontal

Expand All @@ -89,12 +83,12 @@ def generate_merge_list(self):

elif self.merge_strategy == MERGE_GRID:
merge, h = [], []
limit_h = self.limit_horizontal
if self.limit_horizontal is None:
limit_h = self.__nearest_square(len(self.list_images))
self.limit_horizontal = self.__nearest_square(len(self.list_images))
limit_h = self.limit_horizontal

for idx, im in enumerate(self.list_images):
if idx < limit_h or idx > len(self.list_images) - self.limit_horizontal / 2:
if idx < limit_h or (idx > round(len(self.list_images) - self.limit_horizontal / 2) and len(merge) > 1):
h.append(im)
else:
merge.append(h)
Expand All @@ -106,7 +100,6 @@ def generate_merge_list(self):
def __generate_merged_image(self):

t = self.generate_merge_list()
print(t)
if self.merge_strategy in (MERGE_HORIZONTALLY, MERGE_VERTICALLY):
_im = merge_images(list_images_tmp=t, direction=self.merge_strategy, preserve_aspect_ratio=self.preserve_aspect_ratio)
else:
Expand Down Expand Up @@ -134,6 +127,7 @@ def generate_filename(suffix, extension):


def concat_two_images(im1, im2, direction):
# TODO: Factorize
if im1 is None:
return im2
if direction == MERGE_HORIZONTALLY:
Expand All @@ -147,10 +141,19 @@ def concat_two_images(im1, im2, direction):
return dst


def resize(im, basewidth=800):
if im is None:
return None
wpercent = (basewidth / float(im.size[0]))
hsize = int((float(im.size[1]) * float(wpercent)))
img = im.resize((basewidth, hsize), Image.Resampling.LANCZOS)
return img


def merge_images(list_images_tmp: List[ImageToMerge], direction: int, preserve_aspect_ratio: bool):
_im = None
for im in list_images_tmp:
if not preserve_aspect_ratio:
im = im.resize()
im = resize(im)
_im = concat_two_images(im1=_im, im2=im, direction=direction)
return _im
109 changes: 107 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,109 @@
# WIP

# image-merger
A small Python library to merge images
A small Python library to merge images easily

# Installation
```
pip install image-merger
```

# Usage

## Simple use case
```
from ImageMerger import Merger, ImageToMerge, MERGE_GRID
# Initialize list of images
list_images = [
ImageToMerge(path='images/samples/1.png'),
ImageToMerge(path='images/samples/2.png'),
ImageToMerge(path='images/samples/3.png'),
ImageToMerge(path='images/samples/4.png')
]
# Load merger with different settings
m = Merger(list_images=list_images)
# Save merged image
m.save_image(filename="images/results/output_4_grid.png")
```
![output_4_grid.png](https://raw.githubusercontent.com/ggouzi/image-merger/main/images/results/output_4_grid.png)

## Parameters

- `limit_horizontal: int`: Optional int to define the maximum number of images to append horizontally
- `limit_vertical: int`: Optional int to define the maximum number of images to append vertically
- `suffle: bool`: Optional boolean to decide if `list_images` must be shuffled prior to process. Default `False`
- `merge_strategy: int`: Optional int to set the merging strategy. Either `MERGE_HORIZONTALLY`, - `MERGE_VERTICALLY` or `MERGE_GRID`(default)
- `preserve_aspect_ratio: bool`: Optional boolean that defines if proportion of each image should be kept or if image can be squeezed/extended to fit. Default `False`
- Setting it to `True` can lead to images being distored to fit layout but there will be no gaps.
- Setting it to `False` will kept each image aspect ratio but can lead to black gaps in output image.

## Configuration examples
- `ImageToMerge.path` can either be a path(local or relative) or HTTP(S) URL
- `limit_horizontal` and `limit_vertical` are optional and can also be used at the same time
- If `limit_horizontal` and `limit_vertical` are not set, and `merge_strategy` is set to `MERGE_GRID` The process will try to fit as best as possible all images in a square grid.
- List of images can be shuffled randomly using `shuffle=True` parameter


## More examples
```
from ImageMerger import Merger, ImageToMerge
# Initialize list of images
list_images = [
ImageToMerge(path='images/samples/1.png'),
ImageToMerge(path='images/samples/2.png'),
ImageToMerge(path='https://raw.githubusercontent.com/ggouzi/image-merger/main/images/samples/3.png'),
ImageToMerge(path='https://raw.githubusercontent.com/ggouzi/image-merger/main/images/samples/4.png'),
ImageToMerge(path='https://raw.githubusercontent.com/ggouzi/image-merger/main/images/samples/5.png')
]
# Load merger with different settings
m = Merger(
list_images=list_images,
preserve_aspect_ratio=True,
limit_vertical=2
)
# Save merged image
m.save_image(filename="images/results/output_5_grid_keep_aspect_ratio.png")
```
![output_5_grid_keep_aspect_ratio.png](https://raw.githubusercontent.com/ggouzi/image-merger/main/images/results/output_5_grid_keep_aspect_ratio.png)

```
from ImageMerger import Merger, ImageToMerge
# Initialize list of images
list_images = [ImageToMerge(path=f"images/samples/{i}.png") for i in range(1, 11)]
# Load merger with different settings
m = Merger(
list_images=list_images,
limit_horizontal=2
)
# Save merged image
m.save_image(filename="images/results/output_10_2rows.png")
```
![output_10_2rows.png](https://raw.githubusercontent.com/ggouzi/image-merger/main/images/results/output_10_2rows.png)

```
from ImageMerger import Merger, ImageToMerge
# Initialize list of images
list_images = [ImageToMerge(path=f"images/samples/{i}.png") for i in range(1, 11)]
# Load merger with different settings
m = Merger(
list_images=list_images,
shuffle=True
)
# Save merged image
m.save_image(filename="images/results/output_10_grid_shuffled.png")
```
![output_10_grid_shuffled.png](https://raw.githubusercontent.com/ggouzi/image-merger/main/images/results/output_10_grid_shuffled.png)

# References
- [Pillow](https://github.com/python-pillow/Pillow/)
Binary file added images/results/output_10_2rows.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/results/output_10_grid_shuffled.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/results/output_4_grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pillow==9.2.0

0 comments on commit f341af1

Please sign in to comment.