Beispiel #1
0
def test_merge_layer_from_file():
    with TempFile('.xcf') as dst, TempFile('.xcf') as src:
        layer_bg = np.array([
            [[255, 255, 255], [0, 0, 0], [255, 255, 255]],
            [[255, 255, 255], [255, 255, 255], [255, 255, 255]],
        ],
                            dtype=np.uint8)

        src_file = GimpFile(src)
        src_file.create('Background', np.zeros(shape=(2, 3, 3),
                                               dtype=np.uint8))
        src_file.add_layer_from_numpy(
            'Yellow',
            np.array([
                [[240, 255, 0], [240, 255, 0], [240, 255, 0]],
                [[240, 255, 0], [240, 255, 0], [240, 255, 0]],
            ],
                     dtype=np.uint8))

        dst_file = GimpFile(dst)
        dst_file.create('Yellow', layer_bg)
        dst_file.merge_layer_from_file(src_file, 'Yellow')

        new_layer_contents = dst_file.layer_to_numpy('Yellow')

        assert np.all([240, 255, 0] == new_layer_contents)
Beispiel #2
0
def test_create_from_template():
    with TempFile('.xcf') as original, TempFile('.xcf') as created:
        original_file = GimpFile(original).create(
            'Background', np.zeros(shape=(3, 2), dtype=np.uint8))
        created_file = GimpFile(created).create_from_template(original_file)
        assert [] == created_file.layer_names()
        assert (2, 3) == created_file.dimensions()
Beispiel #3
0
def test_execute_script_and_return_json_with_script_that_takes_multiple_files_using_for_each():
    with TempFile('.xcf') as with_white, TempFile('.xcf') as without_white:
        GimpFile(with_white) \
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8)) \
            .add_layer_from_numpy('White', np.ones(shape=(1, 1), dtype=np.uint8) * 255)

        GimpFile(without_white) \
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8)) \
            .add_layer_from_numpy('Black', np.zeros(shape=(1, 1), dtype=np.uint8))

        collection = GimpFileCollection([with_white, without_white])

        script = textwrap.dedent(
            """
            from pgimp.gimp.file import for_each_file
            from pgimp.gimp.parameter import return_json, get_json

            matches = []

            def layer_matches(image, file):
                for layer in image.layers:
                    if layer.name == '{0:s}':
                        matches.append(file)

            for_each_file(layer_matches)
            return_json(matches)
            """
        )

        files = collection.execute_script_and_return_json(script.format(escape_single_quotes('White')),
                                                          timeout_in_seconds=3)
        assert len(files) == 1
        assert with_white == files[0]
Beispiel #4
0
def test_execute_script_and_return_json_with_script_that_takes_single_file():
    with TempFile('.xcf') as with_white, TempFile('.xcf') as without_white:
        GimpFile(with_white)\
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8))\
            .add_layer_from_numpy('White', np.ones(shape=(1, 1), dtype=np.uint8)*255)

        GimpFile(without_white) \
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8)) \
            .add_layer_from_numpy('Black', np.zeros(shape=(1, 1), dtype=np.uint8))

        collection = GimpFileCollection([with_white, without_white])

        script = textwrap.dedent(
            """
            from pgimp.gimp.file import open_xcf
            from pgimp.gimp.parameter import return_json
            image = open_xcf('__file__')
            for layer in image.layers:
                if layer.name == '{0:s}':
                    return_json(True)
            return_json(False)
            """
        )

        files = collection.execute_script_and_return_json(script.format(escape_single_quotes('White')), timeout_in_seconds=3)
        assert {
            with_white: True,
            without_white: False,
        } == files
Beispiel #5
0
def test_find_files_by_script_with_script_that_takes_multiple_files():
    with TempFile('.xcf') as with_white, TempFile('.xcf') as without_white:
        GimpFile(with_white)\
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8))\
            .add_layer_from_numpy('White', np.ones(shape=(1, 1), dtype=np.uint8)*255)

        GimpFile(without_white) \
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8)) \
            .add_layer_from_numpy('Black', np.zeros(shape=(1, 1), dtype=np.uint8))

        collection = GimpFileCollection([with_white, without_white])

        script = textwrap.dedent(
            """
            import gimp
            from pgimp.gimp.file import XcfFile
            from pgimp.gimp.parameter import return_json, get_json
            files = get_json('__files__')
            matches = []
            for file in files:
                with XcfFile(file) as image:
                    for layer in image.layers:
                        if layer.name == '{0:s}':
                            matches.append(file)
            return_json(matches)
            """
        )

        files = collection.find_files_by_script(script.format(escape_single_quotes('White')), timeout_in_seconds=3)
        assert len(files) == 1
        assert with_white == files[0]

        files = collection.find_files_by_script(script.format(escape_single_quotes('Not existing')), timeout_in_seconds=3)
        assert len(files) == 0
Beispiel #6
0
def test_add_layer_from_file():
    with TempFile('.xcf') as dst, TempFile('.xcf') as src:
        layer_bg = np.array([
            [[255, 255, 255], [0, 0, 0], [255, 255, 255]],
            [[255, 255, 255], [255, 255, 255], [255, 255, 255]],
        ],
                            dtype=np.uint8)
        position = 1

        src_file = GimpFile(src)
        src_file.create('Background', np.zeros(shape=(2, 3, 3),
                                               dtype=np.uint8))
        src_file.add_layer_from_numpy(
            'Yellow',
            np.array([
                [[240, 255, 0], [240, 255, 0], [240, 255, 0]],
                [[240, 255, 0], [240, 255, 0], [240, 255, 0]],
            ],
                     dtype=np.uint8))

        dst_file = GimpFile(dst)
        dst_file.create('Background', layer_bg)
        dst_file.add_layer_from_file(src_file,
                                     'Yellow',
                                     new_name='Yellow (copied)',
                                     new_position=position)

        assert 'Yellow (copied)' == dst_file.layers()[position].name
        assert np.all(
            [240, 255, 0] == dst_file.layer_to_numpy('Yellow (copied)'))
Beispiel #7
0
def test_copy():
    with TempFile('.xcf') as original, TempFile('.xcf') as copy:
        original_file = GimpFile(original).create(
            'Background', np.zeros(shape=(2, 2), dtype=np.uint8))
        copied_file = original_file.copy(copy)
        original_file.add_layer_from_numpy(
            'New', np.zeros(shape=(2, 2), dtype=np.uint8))
        assert ['Background'] == copied_file.layer_names()
        assert ['New', 'Background'] == original_file.layer_names()
Beispiel #8
0
def test_export():
    with TempFile('.xcf') as xcf, TempFile('.png') as png, TempFile(
            '.jpg') as jpg, TempFile('.xcf') as from_png:
        gimp_file = GimpFile(xcf) \
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8)) \
            .add_layer_from_numpy('Foreground', np.ones(shape=(1, 1), dtype=np.uint8) * 255, opacity=50.) \

        gimp_file.export(
            png
        )  # saved as grayscale with alpha (identify -format '%[channels]' FILE)
        gimp_file.export(jpg)

        assert np.all([127, 255] == GimpFile(from_png).create_from_file(
            png, layer_name='Image').layer_to_numpy('Image'))
        assert np.all([127] == GimpFile(from_png).create_from_file(
            jpg, layer_name='Image').layer_to_numpy('Image'))
Beispiel #9
0
def test_find_files_containing_layer_by_name():
    with TempFile('.xcf') as with_white, TempFile('.xcf') as without_white:
        GimpFile(with_white)\
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8))\
            .add_layer_from_numpy('White', np.ones(shape=(1, 1), dtype=np.uint8)*255)

        GimpFile(without_white) \
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8)) \
            .add_layer_from_numpy('Black', np.zeros(shape=(1, 1), dtype=np.uint8))

        collection = GimpFileCollection([with_white, without_white])

        files = collection.find_files_containing_layer_by_name('White', timeout_in_seconds=10)
        assert len(files) == 1
        assert with_white == files[0]

        files = collection.find_files_containing_layer_by_name('Not existing', timeout_in_seconds=10)
        assert len(files) == 0
Beispiel #10
0
def test_add_layer_from_numpy_with_position_layer_name():
    data = np.array([[[255, 255, 255]]], dtype=np.uint8)
    with TempFile('.xcf') as tmp_file:
        gimp_file = GimpFile(tmp_file)
        gimp_file.create('Background', data)
        gimp_file.add_layer_from_numpy('Layer 1', data, position='Background')
        gimp_file.add_layer_from_numpy('Layer 2', data, position='Background')

        assert gimp_file.layer_names() == ['Layer 1', 'Layer 2', 'Background']
Beispiel #11
0
    def layers_to_numpy(
        self,
        layer_names: List[str],
        use_temp_file=True,
        timeout: Optional[int] = None,
    ) -> np.ndarray:
        """
        Convert gimp layers to a numpy array of unsigned 8 bit integers.

        Example:

        >>> from pgimp.GimpFile import GimpFile
        >>> from pgimp.util.TempFile import TempFile
        >>> import numpy as np
        >>> with TempFile('.xcf') as f:
        ...     gimp_file = GimpFile(f) \\
        ...         .create('Red', np.zeros(shape=(1, 2, 1), dtype=np.uint8)) \\
        ...         .add_layer_from_numpy('Green', np.ones(shape=(1, 2, 1), dtype=np.uint8)*127) \\
        ...         .add_layer_from_numpy('Blue', np.ones(shape=(1, 2, 1), dtype=np.uint8)*255)
        ...     gimp_file.layers_to_numpy(['Red', 'Green', 'Blue']).shape
        (1, 2, 3)

        :param layer_names: Names of the layers to convert.
        :param use_temp_file: Use a tempfile for data transmition instead of stdout. This is more robust in
                              a multiprocessing setting.
        :param timeout: Execution timeout in seconds.
        :return: Numpy array of unsigned 8 bit integers.
        """
        with TempFile('.npy') as tmpfile:
            bytes = self._gsr.execute_binary(
                textwrap.dedent(
                    """
                    import numpy as np
                    import sys
                    from pgimp.gimp.file import open_xcf
                    from pgimp.gimp.parameter import get_json, get_string
                    from pgimp.gimp.layer import convert_layers_to_numpy
    
                    np_buffer = convert_layers_to_numpy(open_xcf('{0:s}'), get_json('layer_names', '[]'))
                    temp_file = get_string('temp_file')
                    if temp_file:
                        np.save(temp_file, np_buffer)
                    else:
                        np.save(sys.stdout, np_buffer)
                    """, ).format(escape_single_quotes(self._file)),
                parameters={
                    'layer_names': layer_names,
                    'temp_file': tmpfile if use_temp_file else ''
                },
                timeout_in_seconds=self.long_running_timeout_in_seconds
                if timeout is None else timeout)
            if use_temp_file:
                return np.load(tmpfile)

        return np.load(io.BytesIO(bytes))
Beispiel #12
0
def test_tempfile_is_removed_on_exception():
    try:
        with TempFile() as f:
            assert 'tmp' in f
            open(f, 'w').close()
            assert os.path.exists(f)
            raise ValueError
    except ValueError:
        pass

    assert not os.path.exists(f)
Beispiel #13
0
def test_add_layers_from_numpy():
    with TempFile('.xcf') as f:
        gimp_file = GimpFile(f).create('Background',
                                       np.zeros(shape=(1, 2), dtype=np.uint8))
        gimp_file.add_layers_from_numpy(
            ['Layer 1', 'Layer 2'],
            np.ones(shape=(2, 1, 2), dtype=np.uint8) * 255,
            opacity=55.,
            visible=False,
            position='Background')
        assert gimp_file.layer_names() == ['Layer 1', 'Layer 2', 'Background']
Beispiel #14
0
def test_memory_gets_freed_in_shm():
    if use_shmem():
        with TempFile() as f:
            fh = open(f, 'w')
            fh.write('x' * (100 * 1000000))  # write 100M
            fh.close()
            statvfs = os.statvfs(shmem_dir())
            free_before = statvfs.f_frsize * statvfs.f_bavail / 1000000  # disk free in M
        statvfs = os.statvfs(shmem_dir())
        free_after = statvfs.f_frsize * statvfs.f_bavail / 1000000  # disk free in M
        assert free_after > free_before + 100 * 0.8  # at least 80 M more space than before
Beispiel #15
0
def test_add_layers_from_numpy_with_list_config():
    with TempFile('.xcf') as f:
        gimp_file = GimpFile(f).create('Background',
                                       np.zeros(shape=(1, 2), dtype=np.uint8))
        gimp_file.add_layers_from_numpy(
            ['Layer 1', 'Layer 2'],
            np.ones(shape=(2, 1, 2), dtype=np.uint8) * 255,
            opacity=[100., 55.],
            visible=[False, True],
            position='Background',
            blend_mode=gimpenums.NORMAL_MODE)
        assert gimp_file.layer_names() == ['Layer 1', 'Layer 2', 'Background']
Beispiel #16
0
def test_clear_selection():
    file_with_selection_original = file.relative_to(__file__, 'test-resources/selection.xcf')
    with TempFile('.xcf') as file_with_selection:
        shutil.copyfile(file_with_selection_original, file_with_selection)
        collection = GimpFileCollection([file_with_selection])

        selections_before = _has_selections(collection)
        assert selections_before[file_with_selection]

        collection.clear_selection(timeout_in_seconds=10)

        selections_after = _has_selections(collection)
        assert not selections_after[file_with_selection]
Beispiel #17
0
def test_find_files_containing_layer_by_predictate():
    with TempFile('.xcf') as with_white, TempFile('.xcf') as without_white:
        GimpFile(with_white)\
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8))\
            .add_layer_from_numpy('White', np.ones(shape=(1, 1), dtype=np.uint8)*255)

        GimpFile(without_white) \
            .create('Background', np.zeros(shape=(1, 1), dtype=np.uint8)) \
            .add_layer_from_numpy('Black', np.zeros(shape=(1, 1), dtype=np.uint8))

        collection = GimpFileCollection([with_white, without_white])

        files = collection.find_files_containing_layer_by_predictate(
            lambda layers: 'White' in map(lambda layer: layer.name, layers)
        )
        assert len(files) == 1
        assert with_white == files[0]

        files = collection.find_files_containing_layer_by_predictate(
            lambda layers: 'Not existing' in map(lambda layer: layer.name, layers)
        )
        assert len(files) == 0
Beispiel #18
0
def test_layers_to_numpy():
    use_temp_file_values = [True, False]
    for use_temp_file in use_temp_file_values:
        with TempFile('.xcf') as f:
            gimp_file = GimpFile(f) \
                .create('Red', np.zeros(shape=(1, 2, 3), dtype=np.uint8)) \
                .add_layer_from_numpy('Green', np.ones(shape=(1, 2, 3), dtype=np.uint8) * 127) \
                .add_layer_from_numpy('Blue', np.ones(shape=(1, 2, 3), dtype=np.uint8) * 255)
            np_array = gimp_file.layers_to_numpy(['Red', 'Green', 'Blue'],
                                                 use_temp_file=use_temp_file)

        assert (1, 2, 9) == np_array.shape
        assert np.all(
            np.array([
                [[0, 0, 0, 127, 127, 127, 255, 255, 255],
                 [0, 0, 0, 127, 127, 127, 255, 255, 255]],
            ],
                     dtype=np.uint8) == np_array)
Beispiel #19
0
def test_merge_layer_from_file_with_cleared_selection():
    src = file.relative_to(__file__, 'test-resources/selection.xcf')
    with TempFile('.xcf') as dst:
        src_file = GimpFile(src)
        dst_file = GimpFile(dst)
        dst_file.create('Background', np.zeros(shape=(3, 3, 3),
                                               dtype=np.uint8))
        dst_file.merge_layer_from_file(src_file, 'Background')

        new_layer_contents = dst_file.layer_to_numpy('Background')

        assert np.all(
            np.array([
                [[255, 255, 255], [255, 255, 255], [255, 255, 255]],
                [[255, 0, 0], [255, 0, 0], [255, 255, 255]],
                [[255, 255, 255], [255, 255, 255], [255, 255, 255]],
            ],
                     dtype=np.uint8) == new_layer_contents)
Beispiel #20
0
    def _send_to_gimp(
            self,
            code: str,
            timeout_in_seconds: float = None,
            binary=False,
            parameters: dict = None,
    ) -> Union[str, bytes, None]:

        if not is_gimp_present():
            raise GimpNotInstalledException('A working gimp installation with gimp on the PATH is necessary.')

        command = []
        if is_xvfb_present():
            command.append(path_to_xvfb_run())
            command.append(FLAG_AUTO_SERVERNUM)  # workaround for defunct xvfb-run processes on ubuntu 16.04
        command.append(path_to_gimp_executable())
        command.extend([
            FLAG_NO_INTERFACE,
            FLAG_NO_DATA,
            FLAG_NO_FONTS,
            FLAG_PYTHON_INTERPRETER,
            FLAG_NON_INTERACTIVE,
            FLAG_FROM_STDIN
        ])

        gimp_environment = {'__working_directory__': self._working_directory}
        gimp_environment.update(os.environ.copy())
        if 'PYTHONPATH' not in gimp_environment:
            gimp_environment['__PYTHONPATH__'] = python2_pythonpath()
        else:
            gimp_environment['__PYTHONPATH__'] = python2_pythonpath() + ':' + gimp_environment['PYTHONPATH']
        gimp_environment.update({k: v for k, v in self._environment.items() if self._environment[k] is not None})

        parameters = parameters or {}
        parameters_parsed = {}
        for parameter, value in parameters.items():
            if isinstance(value, str):
                parameters_parsed[parameter] = value
            elif isinstance(value, (bool, int, float, bytes)):
                parameters_parsed[parameter] = repr(value)
            elif isinstance(value, (list, tuple, dict)):
                parameters_parsed[parameter] = json.dumps(value)
            else:
                raise GimpScriptException('Cannot interpret parameter type {:s}'.format(type(value).__name__))

        gimp_environment.update({k: v for k, v in parameters_parsed.items() if parameters_parsed[k] is not None})

        with TempFile('.stdout', 'pgimp') as stdout_file, TempFile('.stderr', 'pgimp') as stderr_file:
            gimp_environment['__stdout__'] = stdout_file
            gimp_environment['__stderr__'] = stderr_file
            gimp_environment['__binary__'] = str(binary)

            self._gimp_process = subprocess.Popen(
                command,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                env=gimp_environment,
            )

            initializer = file.get_content(file.relative_to(__file__, 'gimp/initializer.py')) + '\n'
            extend_path = "sys.path.append('{:s}')\n".format(os.path.dirname(os.path.dirname(__file__)))
            quit_gimp = '\npdb.gimp_quit(0)'

            code = initializer + extend_path + code + quit_gimp

            if pgimp.execute_scripts_with_process_check:
                import psutil

                if is_xvfb_present():
                    expected_processes = {'xvfb', 'gimp', 'script-fu', 'python'}
                else:
                    expected_processes = {'script-fu', 'python'}

                process = psutil.Process(self._gimp_process.pid)
                process_children = self._wait_for_child_processes_to_start(process, expected_processes)

            try:
                self._gimp_process.communicate(code.encode(), timeout=timeout_in_seconds)
            except subprocess.TimeoutExpired as exception:
                self._gimp_process.kill()
                raise GimpScriptExecutionTimeoutException(str(exception) + '\nCode that was executed:\n' + code)
            finally:
                if pgimp.execute_scripts_with_process_check:
                    self._kill_non_terminated_processes(process_children)

            stdout_content = read(stdout_file, 'r' if not binary else 'rb')
            stderr_content = read(stderr_file, 'r')

        if stderr_content:
            error_lines = stderr_content.strip().split('\n')
            if error_lines[-1].startswith('__GIMP_SCRIPT_ERROR__'):
                error_string = stderr_content.rsplit('\n', 1)[0] + '\n'
                if self._file_to_execute:
                    error_string = error_string.replace('File "<string>"', 'File "{:s}"'.format(self._file_to_execute), 1)
                raise GimpScriptException(error_string)
            raise GimpScriptException('\n'.join(error_lines))

        return stdout_content
Beispiel #21
0
def test_read():
    content = 'abc' * 1000000
    with TempFile() as tmp:
        fh = open(tmp, 'w')
        fh.write(content)
        assert read(tmp) == content
Beispiel #22
0
def test_create_empty():
    with TempFile('.xcf') as f:
        gimp_file = GimpFile(f).create_empty(3, 2, GimpFileType.RGB)
        assert (3, 2) == gimp_file.dimensions()
        assert [] == gimp_file.layer_names()
Beispiel #23
0
import os

import numpy as np

from pgimp.GimpFile import GimpFile
from pgimp.util import file
from pgimp.util.TempFile import TempFile

if __name__ == '__main__':
    img_path = file.relative_to(__file__, '../../../doc/source/_static/img')
    png_file = os.path.join(img_path, 'sphere.png')

    # generate sphere data
    x = np.arange(-1, 1, 0.01)
    y = np.arange(-1, 1, 0.01)
    xx, yy = np.meshgrid(x, y, sparse=True)
    z = np.sin(xx**2 + yy**2)

    # generate rgb image data
    img = np.zeros(shape=(200, 200, 3), dtype=np.uint8)
    img[:, :, 0] = (1 - z) * 255

    # create temporary gimp file an export to png
    with TempFile('.xcf') as tmp:
        GimpFile(tmp).create('Background', img).export(png_file)
Beispiel #24
0
from pgimp.util.TempFile import TempFile

if __name__ == '__main__':
    img_path = file.relative_to(__file__, '../../../doc/source/_static/img')
    png_file = os.path.join(img_path, 'mask_applied.png')

    height = 100
    width = 200

    # layer content
    bg = np.zeros(shape=(height, width), dtype=np.uint8)
    fg = np.ones(shape=(height, width), dtype=np.uint8) * 255
    mask = np.zeros(shape=(height, width), dtype=np.uint8)
    mask[:, width//4:3*width//4+1] = 255

    with TempFile('.xcf') as xcf, TempFile('.npz') as npz:
        # create gimp file
        gimp_file = GimpFile(xcf) \
            .create('Background', bg) \
            .add_layer_from_numpy('Foreground', fg) \
            .add_layer_from_numpy('Mask', mask)

        # save layer data to numpy arrays
        arr_bg = gimp_file.layer_to_numpy('Background')
        arr_fg = gimp_file.layer_to_numpy('Foreground')
        arr_mask = gimp_file.layer_to_numpy('Mask')

        # save data as npz
        np.savez_compressed(npz, bg=arr_bg, fg=arr_fg, mask=arr_mask)

        # load data from npz
Beispiel #25
0
def test_tempfile_is_removed():
    with TempFile() as f:
        assert 'tmp' in f
        assert os.path.exists(f)

    assert not os.path.exists(f)