ImageConverter now uses generic context; #562
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.44.2"
|
__version__ = "0.44.3"
|
||||||
|
|||||||
@@ -17,25 +17,25 @@ from wurlitzer import pipes
|
|||||||
|
|
||||||
|
|
||||||
class ImageConversionError(Exception):
|
class ImageConversionError(Exception):
|
||||||
"""Base class for exceptions in this module. """
|
"""Base class for exceptions in this module."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ImageConverter:
|
class ImageConverter:
|
||||||
""" Convert images to jpeg. This class is a singleton
|
"""Convert images to jpeg. This class is a singleton
|
||||||
which will re-use the Core Image CIContext to avoid
|
which will re-use the Core Image CIContext to avoid
|
||||||
creating a new context for every conversion. """
|
creating a new context for every conversion."""
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
""" create new object or return instance of already created singleton """
|
"""create new object or return instance of already created singleton"""
|
||||||
if not hasattr(cls, "instance") or not cls.instance:
|
if not hasattr(cls, "instance") or not cls.instance:
|
||||||
cls.instance = super().__new__(cls)
|
cls.instance = super().__new__(cls)
|
||||||
|
|
||||||
return cls.instance
|
return cls.instance
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
""" return existing singleton or create a new one """
|
"""return existing singleton or create a new one"""
|
||||||
|
|
||||||
if hasattr(self, "context"):
|
if hasattr(self, "context"):
|
||||||
return
|
return
|
||||||
@@ -47,13 +47,10 @@ class ImageConverter:
|
|||||||
"workingFormat": Quartz.kCIFormatRGBAh,
|
"workingFormat": Quartz.kCIFormatRGBAh,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
mtldevice = Metal.MTLCreateSystemDefaultDevice()
|
self.context = Quartz.CIContext.contextWithOptions_(context_options)
|
||||||
self.context = Quartz.CIContext.contextWithMTLDevice_options_(
|
|
||||||
mtldevice, context_options
|
|
||||||
)
|
|
||||||
|
|
||||||
def write_jpeg(self, input_path, output_path, compression_quality=1.0):
|
def write_jpeg(self, input_path, output_path, compression_quality=1.0):
|
||||||
""" convert image to jpeg and write image to output_path
|
"""convert image to jpeg and write image to output_path
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
input_path: path to input image (e.g. '/path/to/import/file.CR2') as str or pathlib.Path
|
input_path: path to input image (e.g. '/path/to/import/file.CR2') as str or pathlib.Path
|
||||||
@@ -104,9 +101,12 @@ class ImageConverter:
|
|||||||
if input_image is None:
|
if input_image is None:
|
||||||
raise ImageConversionError(f"Could not create CIImage for {input_path}")
|
raise ImageConversionError(f"Could not create CIImage for {input_path}")
|
||||||
|
|
||||||
output_colorspace = input_image.colorSpace() or Quartz.CGColorSpaceCreateWithName(
|
output_colorspace = (
|
||||||
|
input_image.colorSpace()
|
||||||
|
or Quartz.CGColorSpaceCreateWithName(
|
||||||
Quartz.CoreGraphics.kCGColorSpaceSRGB
|
Quartz.CoreGraphics.kCGColorSpaceSRGB
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
output_options = NSDictionary.dictionaryWithDictionary_(
|
output_options = NSDictionary.dictionaryWithDictionary_(
|
||||||
{"kCGImageDestinationLossyCompressionQuality": compression_quality}
|
{"kCGImageDestinationLossyCompressionQuality": compression_quality}
|
||||||
@@ -123,4 +123,3 @@ class ImageConverter:
|
|||||||
raise ImageConversionError(
|
raise ImageConversionError(
|
||||||
f"Error converting file {input_path} to jpeg at {output_path}: {error}"
|
f"Error converting file {input_path} to jpeg at {output_path}: {error}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2393,10 +2393,6 @@ def test_export_original_suffix_template():
|
|||||||
assert sorted(files) == sorted(CLI_EXPORT_FILENAMES_ORIGINAL_SUFFIX_TEMPLATE)
|
assert sorted(files) == sorted(CLI_EXPORT_FILENAMES_ORIGINAL_SUFFIX_TEMPLATE)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"OSXPHOTOS_TEST_CONVERT" not in os.environ,
|
|
||||||
reason="Skip if running in Github actions, no GPU.",
|
|
||||||
)
|
|
||||||
def test_export_convert_to_jpeg():
|
def test_export_convert_to_jpeg():
|
||||||
"""test --convert-to-jpeg"""
|
"""test --convert-to-jpeg"""
|
||||||
import glob
|
import glob
|
||||||
@@ -2420,10 +2416,6 @@ def test_export_convert_to_jpeg():
|
|||||||
assert large_file.stat().st_size > 7000000
|
assert large_file.stat().st_size > 7000000
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"OSXPHOTOS_TEST_CONVERT" not in os.environ,
|
|
||||||
reason="Skip if running in Github actions, no GPU.",
|
|
||||||
)
|
|
||||||
def test_export_convert_to_jpeg_quality():
|
def test_export_convert_to_jpeg_quality():
|
||||||
"""test --convert-to-jpeg --jpeg-quality"""
|
"""test --convert-to-jpeg --jpeg-quality"""
|
||||||
import glob
|
import glob
|
||||||
@@ -2455,10 +2447,6 @@ def test_export_convert_to_jpeg_quality():
|
|||||||
assert large_file.stat().st_size < 1000000
|
assert large_file.stat().st_size < 1000000
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"OSXPHOTOS_TEST_CONVERT" not in os.environ,
|
|
||||||
reason="Skip if running in Github actions, no GPU.",
|
|
||||||
)
|
|
||||||
def test_export_convert_to_jpeg_skip_raw():
|
def test_export_convert_to_jpeg_skip_raw():
|
||||||
"""test --convert-to-jpeg"""
|
"""test --convert-to-jpeg"""
|
||||||
import glob
|
import glob
|
||||||
@@ -6678,10 +6666,6 @@ def test_export_jpeg_ext_edited_movie():
|
|||||||
assert f"{filename}_edited.{ext}".lower() in files
|
assert f"{filename}_edited.{ext}".lower() in files
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"OSXPHOTOS_TEST_CONVERT" not in os.environ,
|
|
||||||
reason="Skip if running in Github actions, no GPU.",
|
|
||||||
)
|
|
||||||
def test_export_jpeg_ext_convert_to_jpeg():
|
def test_export_jpeg_ext_convert_to_jpeg():
|
||||||
"""test --jpeg-ext with --convert-to-jpeg"""
|
"""test --jpeg-ext with --convert-to-jpeg"""
|
||||||
import glob
|
import glob
|
||||||
@@ -6713,10 +6697,6 @@ def test_export_jpeg_ext_convert_to_jpeg():
|
|||||||
assert f"{filename}.jpg" in files
|
assert f"{filename}.jpg" in files
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"OSXPHOTOS_TEST_CONVERT" not in os.environ,
|
|
||||||
reason="Skip if running in Github actions, no GPU.",
|
|
||||||
)
|
|
||||||
def test_export_jpeg_ext_convert_to_jpeg_movie():
|
def test_export_jpeg_ext_convert_to_jpeg_movie():
|
||||||
"""test --jpeg-ext with --convert-to-jpeg and a movie, shouldn't convert or change extensions, #366"""
|
"""test --jpeg-ext with --convert-to-jpeg and a movie, shouldn't convert or change extensions, #366"""
|
||||||
import glob
|
import glob
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ import os
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
skip_test = "OSXPHOTOS_TEST_CONVERT" not in os.environ
|
|
||||||
pytestmark = pytest.mark.skipif(
|
|
||||||
skip_test, reason="Skip if running on GitHub actions, no GPU."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
TEST_HEIC = "tests/test-images/IMG_3092.heic"
|
TEST_HEIC = "tests/test-images/IMG_3092.heic"
|
||||||
TEST_RAW = "tests/test-images/IMG_0476_2.CR2"
|
TEST_RAW = "tests/test-images/IMG_0476_2.CR2"
|
||||||
@@ -19,7 +14,7 @@ TEST_IMAGE_DOES_NOT_EXIST = "tests/test-images/NOT-A-FILE.heic"
|
|||||||
|
|
||||||
|
|
||||||
def test_image_converter_singleton():
|
def test_image_converter_singleton():
|
||||||
""" test that ImageConverter is a singleton """
|
"""test that ImageConverter is a singleton"""
|
||||||
from osxphotos.imageconverter import ImageConverter
|
from osxphotos.imageconverter import ImageConverter
|
||||||
|
|
||||||
convert1 = ImageConverter()
|
convert1 = ImageConverter()
|
||||||
@@ -29,7 +24,7 @@ def test_image_converter_singleton():
|
|||||||
|
|
||||||
|
|
||||||
def test_image_converter():
|
def test_image_converter():
|
||||||
""" test conversion of different image types """
|
"""test conversion of different image types"""
|
||||||
import pathlib
|
import pathlib
|
||||||
import tempfile
|
import tempfile
|
||||||
from osxphotos.imageconverter import ImageConverter
|
from osxphotos.imageconverter import ImageConverter
|
||||||
@@ -50,7 +45,7 @@ def test_image_converter():
|
|||||||
|
|
||||||
|
|
||||||
def test_image_converter_compression_quality():
|
def test_image_converter_compression_quality():
|
||||||
""" test conversion of different image types with custom compression quality """
|
"""test conversion of different image types with custom compression quality"""
|
||||||
import pathlib
|
import pathlib
|
||||||
import tempfile
|
import tempfile
|
||||||
from osxphotos.imageconverter import ImageConverter
|
from osxphotos.imageconverter import ImageConverter
|
||||||
@@ -69,7 +64,7 @@ def test_image_converter_compression_quality():
|
|||||||
|
|
||||||
|
|
||||||
def test_image_converter_bad_compression_quality():
|
def test_image_converter_bad_compression_quality():
|
||||||
""" test illegal compression quality """
|
"""test illegal compression quality"""
|
||||||
import pathlib
|
import pathlib
|
||||||
import tempfile
|
import tempfile
|
||||||
from osxphotos.imageconverter import ImageConverter
|
from osxphotos.imageconverter import ImageConverter
|
||||||
@@ -86,7 +81,7 @@ def test_image_converter_bad_compression_quality():
|
|||||||
|
|
||||||
|
|
||||||
def test_image_converter_bad_file():
|
def test_image_converter_bad_file():
|
||||||
""" Try to convert a file that's not an image """
|
"""Try to convert a file that's not an image"""
|
||||||
import pathlib
|
import pathlib
|
||||||
import tempfile
|
import tempfile
|
||||||
from osxphotos.imageconverter import ImageConverter, ImageConversionError
|
from osxphotos.imageconverter import ImageConverter, ImageConversionError
|
||||||
@@ -101,7 +96,7 @@ def test_image_converter_bad_file():
|
|||||||
|
|
||||||
|
|
||||||
def test_image_converter_missing_file():
|
def test_image_converter_missing_file():
|
||||||
""" Try to convert a file that's not an image """
|
"""Try to convert a file that's not an image"""
|
||||||
import pathlib
|
import pathlib
|
||||||
import tempfile
|
import tempfile
|
||||||
from osxphotos.imageconverter import ImageConverter
|
from osxphotos.imageconverter import ImageConverter
|
||||||
@@ -113,4 +108,3 @@ def test_image_converter_missing_file():
|
|||||||
outfile = pathlib.Path(tempdir.name) / f"{imgfile.stem}.jpeg"
|
outfile = pathlib.Path(tempdir.name) / f"{imgfile.stem}.jpeg"
|
||||||
with pytest.raises(FileNotFoundError):
|
with pytest.raises(FileNotFoundError):
|
||||||
converter.write_jpeg(imgfile, outfile)
|
converter.write_jpeg(imgfile, outfile)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user