Skip to content

Commit 00194f3

Browse files
committed
Add 'merge-convert jpeg' command
1 parent 7660b19 commit 00194f3

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed

docs/90_development/50_testing.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Testing
2+
3+
PyGerber uses pytest for testing purposes. All tests are contained in `tests/`
4+
directory. Tests are grouped in 3 categories:
5+
6+
- `unit`: tests for individual functionalities, testing those in separation from rest of
7+
the project
8+
- `e2e`: end-to-end tests, testing full flows from user provided data to user consumable
9+
output
10+
- `examples`: automatically validated code exampled used in documentation
11+
12+
Assets used as input data for tests are stored in `tests/assets/` directory. Assets used
13+
as output reference data are stored in separate repository:
14+
[pygerber_reference_assets](https://github.com/PyGerber/pygerber_reference_assets).
15+
16+
Example of test making use of reference data can be found in
17+
`test/unit/test_console/test_gerber.py` - `test_gerber_convert_png`. Reference asset
18+
must be generated by special execution mode of the test, guarded by
19+
`is_regeneration_enabled` fixture. To regenerate test asset (or generate it for the
20+
first time) you have to run that test **alone** with `--regenerate` flag. To commit
21+
regenerated assets, use `--auto-commit-regenerated` flag.
22+
23+
```bash
24+
pytest -k test_gerber_convert_png --regenerate --auto-commit-regenerated
25+
```

src/pygerber/console/gerber.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,40 @@ def merge_convert_png(
540540
raise NotImplementedError(msg)
541541

542542

543+
@merge_convert.command("jpeg")
544+
@click.argument("sources", nargs=-1)
545+
@_get_output_file_option()
546+
@_get_dpmm_option()
547+
@_get_file_type_option()
548+
@_get_raster_implementation_option("pillow")
549+
def merge_convert_jpeg(
550+
sources: str,
551+
output: str,
552+
file_type: str,
553+
dpmm: int,
554+
implementation: str,
555+
) -> None:
556+
"""Convert multiple Gerber images to JPEG image and merge them into one image.
557+
558+
Images are merged from first to last, thus fist layer is bottom most, last layer
559+
is topmost, unobstructed.
560+
561+
SOURCES - paths to files which are supposed to be rendered and merged.
562+
"""
563+
view = CompositeView(
564+
GerberFile.from_file(source, file_type=FileTypeEnum(file_type.upper()))
565+
for source in sources
566+
)
567+
568+
if implementation.lower() == "pillow":
569+
result = view.render_with_pillow(dpmm)
570+
result.save_jpeg(output)
571+
572+
else:
573+
msg = f"Implementation {implementation!r} is not supported."
574+
raise NotImplementedError(msg)
575+
576+
543577
@gerber.command("lint")
544578
@click.argument("files", nargs=-1)
545579
@click.option(

test/assets/reference/pygerber/console/gerber.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,8 @@
4848
REFERENCE_REPOSITORY.file("reference/pygerber/console/merge_convert_png.png"),
4949
ImageFormat.PNG,
5050
)
51+
52+
MERGE_CONVERT_JPEG_REFERENCE_IMAGE = ImageAsset[GitFile].new(
53+
REFERENCE_REPOSITORY.file("reference/pygerber/console/merge_convert_jpeg.jpeg"),
54+
ImageFormat.JPEG,
55+
)

test/unit/test_console/test_gerber.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
bmp,
1111
format_cmd,
1212
jpeg,
13+
merge_convert_jpeg,
1314
merge_convert_png,
1415
png,
1516
tiff,
@@ -27,6 +28,7 @@
2728
CONVERT_WEBP_LOSSLESS_REFERENCE_IMAGE,
2829
CONVERT_WEBP_LOSSY_REFERENCE_IMAGE,
2930
FORMAT_CMD_REFERENCE_CONTENT,
31+
MERGE_CONVERT_JPEG_REFERENCE_IMAGE,
3032
MERGE_CONVERT_PNG_REFERENCE_IMAGE,
3133
)
3234
from test.conftest import cd_to_tempdir
@@ -359,3 +361,40 @@ def test_gerber_merge_convert_png(*, is_regeneration_enabled: bool) -> None:
359361
.assert_channel_count(4)
360362
.assert_greater_or_equal_values(0.99)
361363
)
364+
365+
366+
MIN_MERGE_JPEG_SSIM = 0.99
367+
368+
369+
@tag(Tag.PILLOW, Tag.OPENCV, Tag.SKIMAGE)
370+
def test_gerber_merge_convert_jpeg(*, is_regeneration_enabled: bool) -> None:
371+
runner = CliRunner()
372+
with cd_to_tempdir() as temp_path:
373+
result = runner.invoke(
374+
merge_convert_jpeg,
375+
[
376+
get_example_path(ExamplesEnum.carte_test_B_Cu).as_posix(),
377+
get_example_path(ExamplesEnum.carte_test_B_Mask).as_posix(),
378+
get_example_path(ExamplesEnum.carte_test_B_Silkscreen).as_posix(),
379+
"-o",
380+
"output.jpeg",
381+
"-d",
382+
"20",
383+
],
384+
)
385+
logging.debug(result.output)
386+
assert result.exit_code == 0
387+
assert (temp_path / "output.jpeg").exists()
388+
389+
image = Image.open(temp_path / "output.jpeg")
390+
if is_regeneration_enabled:
391+
MERGE_CONVERT_JPEG_REFERENCE_IMAGE.update(image) # pragma: no cover
392+
else:
393+
ia = ImageAnalyzer(MERGE_CONVERT_JPEG_REFERENCE_IMAGE.load())
394+
assert ia.structural_similarity(image) > MIN_MERGE_JPEG_SSIM
395+
ia.assert_same_size(image)
396+
(
397+
ia.histogram_compare_color(image)
398+
.assert_channel_count(4)
399+
.assert_greater_or_equal_values(0.99)
400+
)

0 commit comments

Comments
 (0)