Commit e479a8e4 authored by Chris Lamb's avatar Chris Lamb 💬

Tidy comparators.{gif,image,png}

Gbp-Dch: ignore
Signed-off-by: Chris Lamb's avatarChris Lamb <lamby@debian.org>
parent b799a145
...@@ -18,16 +18,16 @@ ...@@ -18,16 +18,16 @@
# along with diffoscope. If not, see <https://www.gnu.org/licenses/>. # along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
import re import re
import subprocess
import logging import logging
import subprocess
from diffoscope.tools import tool_required from diffoscope.tools import tool_required
from diffoscope.difference import Difference
from diffoscope.config import Config from diffoscope.config import Config
from diffoscope.difference import Difference
from .image import pixel_difference, flicker_difference, same_size
from .utils.file import File from .utils.file import File
from .utils.command import Command from .utils.command import Command
from .image import pixel_difference, flicker_difference, same_size
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -47,19 +47,24 @@ class Gifbuild(Command): ...@@ -47,19 +47,24 @@ class Gifbuild(Command):
return b"" return b""
return line return line
@tool_required('identify') @tool_required('identify')
def is_image_static(image): def is_image_static(image):
try: try:
return subprocess.check_output(( return subprocess.check_output((
'identify', 'identify',
'-format', '%n', '-format', '%n',
image.path)) == b'1' image.path,
)) == b'1'
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
return False return False
def can_compose_gif_images(image1, image2): def can_compose_gif_images(image1, image2):
return same_size(image1, image2) and is_image_static(image1) and \ return same_size(image1, image2) and \
is_image_static(image2) is_image_static(image1) and \
is_image_static(image2)
class GifFile(File): class GifFile(File):
RE_FILE_TYPE = re.compile(r'^GIF image data\b') RE_FILE_TYPE = re.compile(r'^GIF image data\b')
...@@ -69,14 +74,16 @@ class GifFile(File): ...@@ -69,14 +74,16 @@ class GifFile(File):
Gifbuild, Gifbuild,
self.path, self.path,
other.path, other.path,
source='gifbuild', source="gifbuild",
) )
differences = [gifbuild_diff] differences = [gifbuild_diff]
if gifbuild_diff is not None and Config().compute_visual_diffs and \ if gifbuild_diff is not None and Config().compute_visual_diffs and \
can_compose_gif_images(self, other): can_compose_gif_images(self, other):
try: try:
logger.debug( logger.debug(
'Generating visual difference for %s and %s', "Generating visual difference for %s and %s",
self.path, self.path,
other.path, other.path,
) )
...@@ -84,13 +91,14 @@ class GifFile(File): ...@@ -84,13 +91,14 @@ class GifFile(File):
None, None,
self.path, self.path,
other.path, other.path,
source='Image content', source="Image content",
) )
content_diff.add_visuals([ content_diff.add_visuals([
pixel_difference(self.path, other.path), pixel_difference(self.path, other.path),
flicker_difference(self.path, other.path), flicker_difference(self.path, other.path),
]) ])
differences.append(content_diff) differences.append(content_diff)
except subprocess.CalledProcessError: #noqa except subprocess.CalledProcessError: # noqa
pass pass
return differences return differences
...@@ -18,14 +18,14 @@ ...@@ -18,14 +18,14 @@
# along with diffoscope. If not, see <https://www.gnu.org/licenses/>. # along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
import re import re
import subprocess
import base64 import base64
import logging import logging
import subprocess
from diffoscope.config import Config
from diffoscope.tools import tool_required from diffoscope.tools import tool_required
from diffoscope.tempfiles import get_named_temporary_file from diffoscope.tempfiles import get_named_temporary_file
from diffoscope.difference import Difference, VisualDifference from diffoscope.difference import Difference, VisualDifference
from diffoscope.config import Config
from .utils.file import File from .utils.file import File
from .utils.command import Command from .utils.command import Command
...@@ -49,6 +49,7 @@ class Img2Txt(Command): ...@@ -49,6 +49,7 @@ class Img2Txt(Command):
# Strip ANSI escapes # Strip ANSI escapes
return re_ansi_escapes.sub('', line.decode('utf-8')).encode('utf-8') return re_ansi_escapes.sub('', line.decode('utf-8')).encode('utf-8')
class Identify(Command): class Identify(Command):
ATTRIBUTES = ( ATTRIBUTES = (
'Image format: %m', 'Image format: %m',
...@@ -82,38 +83,58 @@ class Identify(Command): ...@@ -82,38 +83,58 @@ class Identify(Command):
self.path, self.path,
] ]
@tool_required('compare') @tool_required('compare')
def pixel_difference(image1_path, image2_path): def pixel_difference(image1_path, image2_path):
compared_filename = get_named_temporary_file(suffix='.png').name compared_filename = get_named_temporary_file(suffix='.png').name
try: try:
subprocess.check_call(('compare', image1_path, image2_path, subprocess.check_call((
'-compose', 'src', compared_filename)) 'compare',
image1_path,
image2_path,
'-compose', 'src',
compared_filename,
))
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
# ImageMagick's `compare` will return 1 if images are different # ImageMagick's `compare` will return 1 if images are different
if e.returncode == 1: if e.returncode == 1:
pass pass
content = base64.b64encode(open(compared_filename, 'rb').read())
content = content.decode('utf8') with open(compared_filename, 'rb') as f:
datatype = 'image/png;base64' content = base64.b64encode(f.read()).decode('utf8')
result = VisualDifference(datatype, content, "Pixel difference")
return result return VisualDifference('image/png;base64', content, "Pixel difference")
@tool_required('convert') @tool_required('convert')
def flicker_difference(image1_path, image2_path): def flicker_difference(image1_path, image2_path):
compared_filename = get_named_temporary_file(suffix='.gif').name compared_filename = get_named_temporary_file(suffix='.gif').name
subprocess.check_call(
('convert', '-delay', '50', image1_path, image2_path, subprocess.check_call((
'-loop', '0', '-compose', 'difference', compared_filename)) 'convert',
content = base64.b64encode(open(compared_filename, 'rb').read()) '-delay', '50',
content = content.decode('utf8') image1_path,
datatype = 'image/gif;base64' image2_path,
result = VisualDifference(datatype, content, "Flicker difference") '-loop', '0',
return result '-compose', 'difference',
compared_filename,
))
with open(compared_filename, 'rb') as f:
content = base64.b64encode(f.read()).decode('utf8')
return VisualDifference('image/gif;base64', content, "Flicker difference")
@tool_required('identify') @tool_required('identify')
def get_image_size(image_path): def get_image_size(image_path):
return subprocess.check_output(('identify', '-format', return subprocess.check_output((
'%[h]x%[w]', image_path)) 'identify',
'-format', '%[h]x%[w]',
image_path,
))
def same_size(image1, image2): def same_size(image1, image2):
try: try:
...@@ -121,6 +142,7 @@ def same_size(image1, image2): ...@@ -121,6 +142,7 @@ def same_size(image1, image2):
except subprocess.CalledProcessError: # noqa except subprocess.CalledProcessError: # noqa
return False return False
class JPEGImageFile(File): class JPEGImageFile(File):
RE_FILE_TYPE = re.compile(r'\bJPEG image data\b') RE_FILE_TYPE = re.compile(r'\bJPEG image data\b')
...@@ -135,7 +157,7 @@ class JPEGImageFile(File): ...@@ -135,7 +157,7 @@ class JPEGImageFile(File):
same_size(self, other): same_size(self, other):
try: try:
logger.debug( logger.debug(
'Generating visual difference for %s and %s', "Generating visual difference for %s and %s",
self.path, self.path,
other.path, other.path,
) )
...@@ -155,6 +177,7 @@ class JPEGImageFile(File): ...@@ -155,6 +177,7 @@ class JPEGImageFile(File):
), ),
] ]
class ICOImageFile(File): class ICOImageFile(File):
RE_FILE_TYPE = re.compile(r'\bMS Windows icon resource\b') RE_FILE_TYPE = re.compile(r'\bMS Windows icon resource\b')
...@@ -177,7 +200,7 @@ class ICOImageFile(File): ...@@ -177,7 +200,7 @@ class ICOImageFile(File):
same_size(self, other): same_size(self, other):
if get_image_size(self.path) == get_image_size(other.path): if get_image_size(self.path) == get_image_size(other.path):
logger.debug( logger.debug(
'Generating visual difference for %s and %s', "Generating visual difference for %s and %s",
self.path, self.path,
other.path, other.path,
) )
......
...@@ -18,17 +18,17 @@ ...@@ -18,17 +18,17 @@
# along with diffoscope. If not, see <https://www.gnu.org/licenses/>. # along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
import re import re
import logging
import functools import functools
import subprocess import subprocess
import logging
from diffoscope.config import Config
from diffoscope.tools import tool_required from diffoscope.tools import tool_required
from diffoscope.difference import Difference from diffoscope.difference import Difference
from diffoscope.config import Config
from .image import pixel_difference, flicker_difference, same_size
from .utils.file import File from .utils.file import File
from .utils.command import Command from .utils.command import Command
from .image import pixel_difference, flicker_difference, same_size
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -50,11 +50,12 @@ class PngFile(File): ...@@ -50,11 +50,12 @@ class PngFile(File):
def compare_details(self, other, source=None): def compare_details(self, other, source=None):
sng_diff = Difference.from_command(Sng, self.path, other.path, source='sng') sng_diff = Difference.from_command(Sng, self.path, other.path, source='sng')
differences = [sng_diff] differences = [sng_diff]
if sng_diff is not None and Config().compute_visual_diffs and \ if sng_diff is not None and Config().compute_visual_diffs and \
same_size(self, other): same_size(self, other):
try: try:
logger.debug( logger.debug(
'Generating visual difference for %s and %s', "Generating visual difference for %s and %s",
self.path, self.path,
other.path, other.path,
) )
...@@ -71,4 +72,5 @@ class PngFile(File): ...@@ -71,4 +72,5 @@ class PngFile(File):
differences.append(content_diff) differences.append(content_diff)
except subprocess.CalledProcessError: # noqa except subprocess.CalledProcessError: # noqa
pass pass
return differences return differences
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment