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)
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()
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]
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
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
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)'))
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()
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'))
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
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']
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))
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)
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']
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
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']
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]
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
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)
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)
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
def test_read(): content = 'abc' * 1000000 with TempFile() as tmp: fh = open(tmp, 'w') fh.write(content) assert read(tmp) == content
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()
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)
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
def test_tempfile_is_removed(): with TempFile() as f: assert 'tmp' in f assert os.path.exists(f) assert not os.path.exists(f)