diff --git a/neuralstyle/imagemagick.py b/neuralstyle/imagemagick.py index e250973..c90690f 100644 --- a/neuralstyle/imagemagick.py +++ b/neuralstyle/imagemagick.py @@ -1,28 +1,19 @@ # Convenience functions to perform Image Magicks from subprocess import run, PIPE from glob import glob -from tempfile import TemporaryDirectory from neuralstyle.utils import filename def convert(origin, dest): - """Transforms the format of an image in a file, by creating a new file with the new format - - If the input file has several layers, they are flattened. - """ - command = "convert " + origin + " -flatten " + dest - run(command, shell=True) + """Transforms the format of an image in a file, by creating a new file with the new format""" + if ismultilayer(origin): + raise ValueError("Cannot operate with multilayer images") + run("convert %s %s" % (origin, dest), shell=True) def shape(imfile): - """Returns the shape of an image file - - If the input file has several layers, it is flattened before computing the shape. - """ - tmpdir = TemporaryDirectory() - tmpname = tmpdir.name + "/" + "image.png" - convert(imfile, tmpname) - result = run("convert " + tmpname + ' -format "%w %h" info:', shell=True, check=True, stdout=PIPE) + """Returns the shape of an image file""" + result = run("convert " + imfile + ' -format "%w %h" info:', shell=True, check=True, stdout=PIPE) return [int(x) for x in result.stdout.decode("utf-8").split(" ")] @@ -90,6 +81,8 @@ def composite(imfiles, outname): def extractalpha(imfile, rgbfile, alphafile): """Decomposes an image file into the RGB channels and the alpha channel, saving both as separate image files""" + if ismultilayer(imfile): + raise ValueError("Cannot operate with multilayer images") # Alpha channel extraction command = "convert -alpha extract %s %s" % (imfile, alphafile) run(command, shell=True, check=True) @@ -119,3 +112,8 @@ def equalimages(imfile1, imfile2): if result.returncode == 2: raise IOError("Error while calling imagemagick compare method") return result.returncode == 0 + + +def ismultilayer(imfile): + """Returns whether an image file contains multiple layers""" + return len(shape(imfile)) > 2 diff --git a/tests/algorithms_tests.py b/tests/algorithms_tests.py index c3249c5..9ccb91f 100644 --- a/tests/algorithms_tests.py +++ b/tests/algorithms_tests.py @@ -11,6 +11,18 @@ STYLES = "/app/entrypoint/tests/styles/" +def assertalldifferent(pattern, expected=None): + """Asserts that all images that follow a given glob pattern have different contents + + An expected number of images can also be provided to be checked. + """ + files = glob(pattern) + if expected is not None: + assert len(files) == expected + for f1, f2 in zip(files, files[1:]): + assert not equalimages(f1, f2) + + def test_styletransfer_gatys(): """Style transfer works without error for the Gatys algorithm""" tmpdir = TemporaryDirectory() @@ -79,11 +91,7 @@ def test_styletransfer_ss(): tmpdir = TemporaryDirectory() styletransfer([CONTENTS + img], [STYLES + "cubism.jpg"], tmpdir.name, alg=alg, size=100, stylescales=stylescales) - files = glob(tmpdir.name + "/" + filename(img) + "*cubism*") - # Check correct number of generated images, and that they are different - assert len(files) == len(stylescales) - for f1, f2 in zip(files, files[1:]): - assert not equalimages(f1, f2) + assertalldifferent(tmpdir.name + "/" + filename(img) + "*cubism*", len(stylescales)) def test_styletransfer_sw(): @@ -94,11 +102,7 @@ def test_styletransfer_sw(): tmpdir = TemporaryDirectory() styletransfer([CONTENTS + img], [STYLES + "cubism.jpg"], tmpdir.name, alg=alg, size=100, weights=styleweights) - files = glob(tmpdir.name + "/" + filename(img) + "*cubism*") - # Check correct number of generated images, and that they are different - assert len(files) == len(styleweights) - for f1, f2 in zip(files, files[1:]): - assert not equalimages(f1, f2) + assertalldifferent(tmpdir.name + "/" + filename(img) + "*cubism*", len(styleweights)) def test_neuraltile(): @@ -124,3 +128,31 @@ def test_formatpsd(): tmpdir = TemporaryDirectory() styletransfer(contents, [STYLES + "cubism.jpg"], tmpdir.name, alg="chen-schmidt-inverse") assert len(glob(tmpdir.name + "/*cubism*")) == 1 + + +def test_alpha(): + """Transformation of images with an alpha channel preserve transparency""" + tmpdir = TemporaryDirectory() + # Transform image with alpha + styletransfer([CONTENTS + "dockersmallalpha.png"], [STYLES + "cubism.jpg"], tmpdir.name, alg="chen-schmidt-inverse") + assert len(glob(tmpdir.name + "/*dockersmallalpha_cubism*")) == 1 + # Transform image without alpha + styletransfer([CONTENTS + "dockersmall.png"], [STYLES + "cubism.jpg"], tmpdir.name, alg="chen-schmidt-inverse") + assert len(glob(tmpdir.name + "/*dockersmall_cubism*")) == 1 + # Check correct that generated image are different + assertalldifferent(tmpdir.name + "/*cubism*") + + +def test_alpha_tiling(): + """Transformation of images with an alpha channel preserve transparency, even when a tiling strategy is used""" + tmpdir = TemporaryDirectory() + # Transform image with alpha + styletransfer([CONTENTS + "dockersmallalpha.png"], [STYLES + "cubism.jpg"], tmpdir.name, alg="chen-schmidt-inverse", + maxtilesize=150) + assert len(glob(tmpdir.name + "/*dockersmallalpha_cubism*")) == 1 + # Transform image without alpha + styletransfer([CONTENTS + "dockersmall.png"], [STYLES + "cubism.jpg"], tmpdir.name, alg="chen-schmidt-inverse", + maxtilesize=150) + assert len(glob(tmpdir.name + "/*dockersmall_cubism*")) == 1 + # Check correct that generated image are different + assertalldifferent(tmpdir.name + "/*cubism*") diff --git a/tests/contents/dockersmallalpha.png b/tests/contents/dockersmallalpha.png new file mode 100644 index 0000000..30eaeb4 Binary files /dev/null and b/tests/contents/dockersmallalpha.png differ diff --git a/tests/contents/marbles.tga b/tests/contents/marbles.tga new file mode 100644 index 0000000..0bb8708 Binary files /dev/null and b/tests/contents/marbles.tga differ diff --git a/tests/contents/oldtelephone.psd b/tests/contents/oldtelephone.psd new file mode 100644 index 0000000..a0a8465 Binary files /dev/null and b/tests/contents/oldtelephone.psd differ diff --git a/tests/contents/tgasample.tga b/tests/contents/tgasample.tga new file mode 100644 index 0000000..2fcf2e0 Binary files /dev/null and b/tests/contents/tgasample.tga differ diff --git a/tests/imagemagick_tests.py b/tests/imagemagick_tests.py index 4eb7076..0f71d7b 100644 --- a/tests/imagemagick_tests.py +++ b/tests/imagemagick_tests.py @@ -47,17 +47,6 @@ def test_convert_nolayers(): assert shape(outname) == shape(content) -def test_convert_layers(): - """Convert a single image with layers works as expected""" - for content in [CONTENTS + f for f in ["oldtelephone.psd"]]: - for ext in [".png", ".jpg", ".psd", ".tga"]: - tmpdir = TemporaryDirectory() - outname = tmpdir.name + "/" + "output" + ext - convert(content, outname) - assert len(glob(tmpdir.name + "/" + filename(outname) + ext)) == 1 - assert shape(outname) == shape(content) - - def test_resize_keepproportions(): """Resizing an image without changing proportions works correctly""" tmpdir = TemporaryDirectory()