mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-23 00:02:38 -05:00
162 lines
6.4 KiB
Python
Executable File
162 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
***************************************************************************
|
|
generate_test_mask_image.py
|
|
---------------------
|
|
Date : February 2015
|
|
Copyright : (C) 2015 by Nyall Dawson
|
|
Email : nyall dot dawson at gmail dot com
|
|
***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************
|
|
"""
|
|
|
|
__author__ = 'Nyall Dawson'
|
|
__date__ = 'February 2015'
|
|
__copyright__ = '(C) 2015, Nyall Dawson'
|
|
|
|
# Generates (or updates) a unit test image mask, which is used to specify whether
|
|
# a pixel in the control image should be checked (black pixel in mask) or not (white
|
|
# pixel in mask). For non black or white pixels, the pixels lightness is used to
|
|
# specify a maximum delta for each color component
|
|
|
|
import os
|
|
import sys
|
|
import argparse
|
|
from PyQt5.QtGui import QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb
|
|
import struct
|
|
import urllib.request
|
|
import urllib.error
|
|
import urllib.parse
|
|
import glob
|
|
|
|
|
|
def error(msg):
|
|
print(msg)
|
|
sys.exit(1)
|
|
|
|
|
|
def colorDiff(c1, c2):
|
|
redDiff = abs(qRed(c1) - qRed(c2))
|
|
greenDiff = abs(qGreen(c1) - qGreen(c2))
|
|
blueDiff = abs(qBlue(c1) - qBlue(c2))
|
|
alphaDiff = abs(qAlpha(c1) - qAlpha(c2))
|
|
return max(redDiff, greenDiff, blueDiff, alphaDiff)
|
|
|
|
|
|
def imageFromPath(path):
|
|
if (path[:7] == 'http://' or path[:7] == 'file://' or path[:8] == 'https://'):
|
|
# fetch remote image
|
|
data = urllib.request.urlopen(path).read()
|
|
image = QImage()
|
|
image.loadFromData(data)
|
|
else:
|
|
image = QImage(path)
|
|
return image
|
|
|
|
|
|
def getControlImagePath(path):
|
|
if os.path.isfile(path):
|
|
return path
|
|
|
|
# else try and find matching test image
|
|
script_folder = os.path.dirname(os.path.realpath(sys.argv[0]))
|
|
control_images_folder = os.path.join(script_folder, '../tests/testdata/control_images')
|
|
|
|
matching_control_images = [x[0] for x in os.walk(control_images_folder) if path in x[0]]
|
|
if len(matching_control_images) > 1:
|
|
error('Found multiple matching control images for {}'.format(path))
|
|
elif len(matching_control_images) == 0:
|
|
error('No matching control images found for {}'.format(path))
|
|
|
|
found_control_image_path = matching_control_images[0]
|
|
|
|
# check for a single matching expected image
|
|
images = glob.glob(os.path.join(found_control_image_path, '*.png'))
|
|
filtered_images = [i for i in images if not i[-9:] == '_mask.png']
|
|
if len(filtered_images) > 1:
|
|
error('Found multiple matching control images for {}'.format(path))
|
|
elif len(filtered_images) == 0:
|
|
error('No matching control images found for {}'.format(path))
|
|
|
|
found_image = filtered_images[0]
|
|
print('Found matching control image: {}'.format(found_image))
|
|
return found_image
|
|
|
|
|
|
def updateMask(control_image_path, rendered_image_path, mask_image_path):
|
|
control_image = imageFromPath(control_image_path)
|
|
if not control_image:
|
|
error('Could not read control image {}'.format(control_image_path))
|
|
|
|
rendered_image = imageFromPath(rendered_image_path)
|
|
if not rendered_image:
|
|
error('Could not read rendered image {}'.format(rendered_image_path))
|
|
if not rendered_image.width() == control_image.width() or not rendered_image.height() == control_image.height():
|
|
print(('Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(control_image.width(),
|
|
control_image.height(),
|
|
rendered_image.width(),
|
|
rendered_image.height())))
|
|
|
|
max_width = min(rendered_image.width(), control_image.width())
|
|
max_height = min(rendered_image.height(), control_image.height())
|
|
|
|
# read current mask, if it exist
|
|
mask_image = imageFromPath(mask_image_path)
|
|
if mask_image.isNull():
|
|
print('Mask image does not exist, creating {}'.format(mask_image_path))
|
|
mask_image = QImage(control_image.width(), control_image.height(), QImage.Format_ARGB32)
|
|
mask_image.fill(QColor(0, 0, 0))
|
|
|
|
# loop through pixels in rendered image and compare
|
|
mismatch_count = 0
|
|
linebytes = max_width * 4
|
|
for y in range(max_height):
|
|
control_scanline = control_image.constScanLine(y).asstring(linebytes)
|
|
rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes)
|
|
mask_scanline = mask_image.scanLine(y).asstring(linebytes)
|
|
|
|
for x in range(max_width):
|
|
currentTolerance = qRed(struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0])
|
|
|
|
if currentTolerance == 255:
|
|
# ignore pixel
|
|
continue
|
|
|
|
expected_rgb = struct.unpack('I', control_scanline[x * 4:x * 4 + 4])[0]
|
|
rendered_rgb = struct.unpack('I', rendered_scanline[x * 4:x * 4 + 4])[0]
|
|
difference = colorDiff(expected_rgb, rendered_rgb)
|
|
|
|
if difference > currentTolerance:
|
|
# update mask image
|
|
mask_image.setPixel(x, y, qRgb(difference, difference, difference))
|
|
mismatch_count += 1
|
|
|
|
if mismatch_count:
|
|
# update mask
|
|
mask_image.save(mask_image_path, "png")
|
|
print('Updated {} pixels in {}'.format(mismatch_count, mask_image_path))
|
|
else:
|
|
print('No mismatches in {}'.format(mask_image_path))
|
|
|
|
|
|
parser = argparse.ArgumentParser() # OptionParser("usage: %prog control_image rendered_image mask_image")
|
|
parser.add_argument('control_image')
|
|
parser.add_argument('rendered_image')
|
|
parser.add_argument('mask_image', nargs='?', default=None)
|
|
args = parser.parse_args()
|
|
|
|
args.control_image = getControlImagePath(args.control_image)
|
|
|
|
if not args.mask_image:
|
|
args.mask_image = args.control_image[:-4] + '_mask.png'
|
|
|
|
updateMask(args.control_image, args.rendered_image, args.mask_image)
|