From b0d3c8aa9b57eeabe11b3140c85fe254fa079157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Porte=C5=A1?= Date: Tue, 4 Apr 2023 16:54:34 +0200 Subject: [PATCH 1/2] Add the `fill_area` parameter --- pictureshow/core.py | 21 +++++++++++++-------- tests/unit_test.py | 31 +++++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/pictureshow/core.py b/pictureshow/core.py index 99cfa63..8884369 100644 --- a/pictureshow/core.py +++ b/pictureshow/core.py @@ -30,7 +30,8 @@ def __init__(self, *pic_files): self.errors = [] def save_pdf(self, output_file, page_size='A4', landscape=False, margin=72, - layout=(1, 1), stretch_small=False, force_overwrite=False): + layout=(1, 1), stretch_small=False, fill_area=False, + force_overwrite=False): """Save pictures stored in `self.pic_files` to a PDF document. Return a named tuple of three values: @@ -43,10 +44,11 @@ def save_pdf(self, output_file, page_size='A4', landscape=False, margin=72, layout = self._validate_layout(layout) return self._save_pdf( - output_file, page_size, margin, layout, stretch_small + output_file, page_size, margin, layout, stretch_small, fill_area ) - def _save_pdf(self, output_file, page_size, margin, layout, stretch_small): + def _save_pdf(self, output_file, page_size, margin, layout, stretch_small, + fill_area): pdf_canvas = Canvas(output_file, pagesize=page_size) valid_pics = self._valid_pictures() num_ok = 0 @@ -66,7 +68,8 @@ def _save_pdf(self, output_file, page_size, margin, layout, stretch_small): x, y, pic_width, pic_height = self._position_and_size( picture.getSize(), area[2:], # short for (area.width, area.height) - stretch_small + stretch_small, + fill_area ) pdf_canvas.drawImage( picture, area.x + x, area.y + y, pic_width, pic_height, @@ -138,11 +141,13 @@ def _valid_pictures(self): yield picture @staticmethod - def _position_and_size(pic_size, area_size, stretch_small): + def _position_and_size(pic_size, area_size, stretch_small, fill_area): """Calculate position and size of the picture in the area.""" - pic_width, pic_height = pic_size area_width, area_height = area_size + if fill_area: + return 0, 0, area_width, area_height + pic_width, pic_height = pic_size pic_is_big = pic_width > area_width or pic_height > area_height pic_is_wide = pic_width / pic_height > area_width / area_height @@ -183,7 +188,7 @@ def _areas(layout, page_size, margin): def pictures_to_pdf(*pic_files, output_file, page_size='A4', landscape=False, - margin=72, layout=(1, 1), stretch_small=False, + margin=72, layout=(1, 1), stretch_small=False, fill_area=False, force_overwrite=False): """Save one or more pictures to a PDF document. @@ -195,6 +200,6 @@ def pictures_to_pdf(*pic_files, output_file, page_size='A4', landscape=False, pic_show = PictureShow(*pic_files) return pic_show.save_pdf( - output_file, page_size, landscape, margin, layout, stretch_small, + output_file, page_size, landscape, margin, layout, stretch_small, fill_area, force_overwrite ) diff --git a/tests/unit_test.py b/tests/unit_test.py index c36ddc1..2dd5fcf 100644 --- a/tests/unit_test.py +++ b/tests/unit_test.py @@ -12,7 +12,9 @@ A4 = A4_WIDTH, A4_LENGTH A4_LANDSCAPE = A4_LENGTH, A4_WIDTH -DEFAULTS = dict(page_size=A4, margin=72, layout=(1, 1), stretch_small=False) +DEFAULTS = dict( + page_size=A4, margin=72, layout=(1, 1), stretch_small=False, fill_area=False +) def picture(): @@ -377,7 +379,7 @@ class TestPositionAndSize: def test_big_wide_picture_fills_area_x(self, pic_size, area_size): original_aspect = pic_size[0] / pic_size[1] x, y, new_width, new_height = PictureShow()._position_and_size( - pic_size, area_size, stretch_small=False + pic_size, area_size, False, False ) assert x == 0 assert new_width == area_size[0] @@ -393,7 +395,7 @@ def test_big_wide_picture_fills_area_x(self, pic_size, area_size): def test_big_tall_picture_fills_area_y(self, pic_size, area_size): original_aspect = pic_size[0] / pic_size[1] x, y, new_width, new_height = PictureShow()._position_and_size( - pic_size, area_size, stretch_small=False + pic_size, area_size, False, False ) assert y == 0 assert new_height == area_size[1] @@ -402,7 +404,7 @@ def test_big_tall_picture_fills_area_y(self, pic_size, area_size): def test_small_picture_not_resized(self): pic_size = (320, 200) x, y, new_width, new_height = PictureShow()._position_and_size( - pic_size, A4_PORTRAIT_MARGIN_72, stretch_small=False + pic_size, A4_PORTRAIT_MARGIN_72, False, False ) assert (new_width, new_height) == pic_size @@ -416,7 +418,7 @@ def test_small_picture_not_resized(self): def test_small_wide_picture_stretch_small(self, pic_size, area_size): original_aspect = pic_size[0] / pic_size[1] x, y, new_width, new_height = PictureShow()._position_and_size( - pic_size, area_size, stretch_small=True + pic_size, area_size, stretch_small=True, fill_area=False ) assert x == 0 assert new_width == area_size[0] @@ -432,12 +434,29 @@ def test_small_wide_picture_stretch_small(self, pic_size, area_size): def test_small_tall_picture_stretch_small(self, pic_size, area_size): original_aspect = pic_size[0] / pic_size[1] x, y, new_width, new_height = PictureShow()._position_and_size( - pic_size, area_size, stretch_small=True + pic_size, area_size, stretch_small=True, fill_area=False ) assert y == 0 assert new_height == area_size[1] assert new_width / new_height == pytest.approx(original_aspect) + @pytest.mark.parametrize( + 'pic_size, area_size', + ( + pytest.param((800, 387), A4_PORTRAIT_MARGIN_72, id='big wide picture'), + pytest.param((400, 3260), A4_PORTRAIT_MARGIN_72, id='big tall picture'), + pytest.param((320, 200), A4_PORTRAIT_MARGIN_72, id='small picture'), + ) + ) + def test_fill_area(self, pic_size, area_size): + x, y, new_width, new_height = PictureShow()._position_and_size( + pic_size, area_size, stretch_small=False, fill_area=True + ) + assert x == 0 + assert y == 0 + assert new_width == area_size[0] + assert new_height == area_size[1] + class TestAreas: """Test core.PictureShow._areas""" From 4bc614592e81ce6ccb06a1d0fcd56e18aeab1238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Porte=C5=A1?= Date: Tue, 4 Apr 2023 16:55:03 +0200 Subject: [PATCH 2/2] Add the `--fill-area` CLI option, update README Close #8 --- README.rst | 9 ++++----- pictureshow/cli.py | 4 ++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 09482fd..d232e73 100644 --- a/README.rst +++ b/README.rst @@ -16,11 +16,6 @@ Installation pip install pictureshow -Third-party dependencies: - -- `Pillow `__ -- `reportlab `__ - Usage ===== @@ -38,6 +33,8 @@ As a command line tool options: -h, --help show this help message and exit + -a, --fill-area fill drawing area with picture, ignoring the picture's + aspect ratio -f, --force-overwrite save to output filename even if file exists -L, --landscape set landscape orientation of page; default is portrait @@ -119,6 +116,7 @@ correspond to the above shown command line options: margin=72, layout=(1, 1), stretch_small=False, + fill_area=False, force_overwrite=False ) @@ -151,6 +149,7 @@ default values correspond to the above shown command line options: margin=72, layout=(1, 1), stretch_small=False, + fill_area=False, force_overwrite=False ) diff --git a/pictureshow/cli.py b/pictureshow/cli.py index 2da2155..8d46443 100644 --- a/pictureshow/cli.py +++ b/pictureshow/cli.py @@ -9,6 +9,9 @@ def get_args(parser): parser.add_argument('pictures', nargs='+', metavar='PICTURE', help='one or more picture paths or URLs') + parser.add_argument('-a', '--fill-area', action='store_true', + help="fill drawing area with picture, ignoring the picture's" + " aspect ratio") parser.add_argument('-f', '--force-overwrite', action='store_true', help='save to output filename even if file exists') parser.add_argument('-L', '--landscape', action='store_true', @@ -92,6 +95,7 @@ def main(): margin=args.margin, layout=args.layout, stretch_small=args.stretch_small, + fill_area=args.fill_area, force_overwrite=args.force_overwrite ) except Exception as err: