Skip to content
Permalink
Browse files

fix php_compress alpha channel bug

  • Loading branch information...
Patrick Schmalstig
Patrick Schmalstig committed Jul 24, 2019
1 parent b555e1b commit 67754b8e366d7303c7e42e3793265f5a00007c53
Showing with 147 additions and 13 deletions.
  1. +137 −9 _tests/tests/unit_tests/images.php
  2. +1 −1 sources/images.php
  3. +8 −2 sources/images2.php
  4. +1 −1 sources/images_cleanup_pipeline.php
@@ -1,11 +1,13 @@
<?php /*
<?php
Composr
Copyright (c) ocProducts, 2004-2018
/*
See text/EN/licence.txt for full licencing information.
Composr
Copyright (c) ocProducts, 2004-2018
*/
See text/EN/licence.txt for full licencing information.
*/
/**
* @license http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
@@ -16,10 +18,9 @@
/**
* Composr test case class (unit testing).
*/
class images_test_set extends cms_test_case
{
public function testIsAnimated()
{
class images_test_set extends cms_test_case {
public function testIsAnimated() {
require_code('images_cleanup_pipeline');
$this->assertTrue(is_animated_image(file_get_contents(get_file_base() . '/themes/default/images/under_construction_animated.gif'), 'gif'));
@@ -28,4 +29,131 @@ public function testIsAnimated()
//$this->assertTrue(is_animated_image(file_get_contents(get_file_base() . '/themes/default/images/TODO'), 'png')); TODO: Enable in v11 with an APNG
$this->assertTrue(!is_animated_image(file_get_contents(get_file_base() . '/themes/default/images/video_thumb.png'), 'png'));
}
public function testConvertImageDimensions() {
require_code('images');
require_code('images2');
$file_aspects = array(
16 => 9,
9 => 16,
4 => 3,
3 => 4,
1 => 1
);
$file_types = array('png', 'jpg', 'jpeg', 'gif');
function runDimensionTest($extension, $start_width, $start_height, $convert_width, $convert_height, $box_width, $only_make_smaller, $expected_width, $expected_height, &$additional_information) {
$additional_information = '';
$path = cms_tempnam();
$successful = convert_image(get_file_base() . '/_tests/assets/images/' . $start_width . 'x' . $start_height . '.' . $extension, $path, $convert_width, $convert_height, $box_width, true, null, true, $only_make_smaller);
if ($successful) {
list($image_width, $image_height) = getimagesize($path);
if (($image_width !== $expected_width && $expected_width !== -1) || ($image_height !== $expected_height && $expected_height !== -1)) {
$additional_information = 'Instead, the dimensions of the new image were ' . $image_width . 'x' . $image_height . '.';
$successful = false;
} else {
$additional_information = 'The test passed.';
}
} else {
$additional_information = 'Instead, convert_image failed.';
}
unlink($path);
return $successful;
}
function runTransparencyTest($file, $convert_width, $convert_height, $transparency, &$additional_information) {
$path = cms_tempnam();
$ret = _runTransparencyTest($path, $file, $convert_width, $convert_height, $transparency, $additional_information);
if (!$ret) {
require_code('mime_types');
echo '<br style="clear: both" />';
echo '<img style="float: left; width: 50px; margin-right: 10px; margin-bottom: 10px" src="data:' . get_mime_type(get_file_extension($file), false) . ';base64,' . base64_encode(file_get_contents($path)) .'" />';
}
unlink($path);
return $ret;
}
function _runTransparencyTest(&$path, $file, $convert_width, $convert_height, $transparency, &$additional_information) {
$additional_information = '';
if (!convert_image(get_file_base() . '/_tests/assets/images/' . $file, $path, $convert_width, $convert_height, -1, true, null, true, false)) {
$additional_information = 'convert_image failed.';
return false;
}
$file_contents = file_get_contents($path);
if (!$file_contents) {
$additional_information = 'The contents of the generated convert_image file could not be read.';
return false;
}
$image_resource = imagecreatefromstring($file_contents);
if (!$image_resource) {
$additional_information = 'A PHP image resource could not be created from the contents of the file.';
return false;
}
$transparent_pixel = imagecolorat($image_resource, intval($convert_width / 4), intval($convert_height / 2));
$transparent_data = imagecolorsforindex($image_resource, $transparent_pixel);
if ($transparent_data['alpha'] !== $transparency) {
$additional_information = 'Expected pixel ' . intval($convert_width / 4) . 'x' . intval($convert_height / 2) . ' to have ' . $transparency . ' alpha, but instead it was ' . $transparent_data['alpha'];
return false;
}
$visible_pixel = imagecolorat($image_resource, intval($convert_width * 0.75), intval($convert_height / 2));
$visible_data = imagecolorsforindex($image_resource, $visible_pixel);
if ($visible_data['alpha'] !== 0) {
$additional_information = 'Expected pixel ' . intval($convert_width * 0.75) . 'x' . intval($convert_height / 2) . ' to have 0 alpha, but instead it was ' . $visible_data['alpha'];
return false;
}
return true;
}
foreach ($file_types as $extension) {
foreach ($file_aspects as $width => $height) {
$additional_information;
// Grow tests
$this->assertTrue(runDimensionTest($extension, $width, $height, $width * 2, $height * 2, -1, false, $width * 2, $height * 2, $additional_information), 'Double width and height of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . $width * 2 . 'x' . $height * 2 . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, $width * 2, $height * 3, -1, false, $width * 2, $height * 2, $additional_information), 'Double width, 3x height of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . $width * 2 . 'x' . $height * 2 . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, $width * 3, $height * 2, -1, false, $width * 2, $height * 2, $additional_information), 'Double height, 3x width of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . $width * 2 . 'x' . $height * 2 . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, $width, $height, -1, false, $width, $height, $additional_information), 'Keep the same width and height of ' . $width . 'x' . $height . '.' . $extension . '. We expected the image to remain the same. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, $width * 2, -1, -1, false, $width * 2, $height * 2, $additional_information), 'Double width, ignore (-1) height of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . $width * 2 . 'x' . $height * 2 . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, -1, $height * 2, -1, false, $width * 2, $height * 2, $additional_information), 'Double height, ignore (-1) width of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . $width * 2 . 'x' . $height * 2 . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, -1, -1, 32, false, ($width > $height ? 32 : -1), ($height > $width ? 32 : -1), $additional_information), 'Use box width 16 of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . ($width > $height ? 32 : $width) . 'x' . ($height > $width ? 32 : $height) . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, -1, -1, 8, false, ($width > $height ? 8 : -1), ($height > $width ? 8 : -1), $additional_information), 'Use box width 4 of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . ($width > $height ? 8 : $width) . 'x' . ($height > $width ? 8 : $height) . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, -1, -1, 2, false, ($width > $height ? 2 : -1), ($height > $width ? 2 : -1), $additional_information), 'Use box width 1 of ' . $width . 'x' . $height . '.' . $extension . '. We expected the new image to be ' . ($width > $height ? 2 : $width) . 'x' . ($height > $width ? 2 : $height) . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width, $height, $width * 2, $height * 2, -1, true, $width, $height, $additional_information), 'Double width and height with only make smaller = true of ' . $width . 'x' . $height . '.' . $extension . '. We expected the image to remain the same (enforce only make smaller). ' . $additional_information);
// Shrink tests
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, $width, $height, -1, false, $width, $height, $additional_information), 'Half the width and height of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . $width . 'x' . $height . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, $width, $height * 2, -1, false, $width, $height, $additional_information), 'Half width, keep height of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . $width . 'x' . $height . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, $width * 2, $height, -1, false, $width, $height, $additional_information), 'Half height, keep width of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . $width . 'x' . $height . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, $width * 2, $height * 2, -1, false, $width * 2, $height * 2, $additional_information), 'Keep the same width and height of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the image to remain the same. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, $width, -1, -1, false, $width, -1, $additional_information), 'Half the width, ignore height of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . $width . 'x' . $height . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, -1, $height, -1, false, -1, $height, $additional_information), 'Half the height, ignore width of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . $width . 'x' . $height . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, -1, -1, 16, false, ($width > $height ? 16 : -1), ($height > $width ? 16 : -1), $additional_information), 'Use box width 16 of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . ($width > $height ? 16 : $width * 2) . 'x' . ($height > $width ? 16 : $height * 2) . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, -1, -1, 4, false, ($width > $height ? 4 : -1), ($height > $width ? 4 : -1), $additional_information), 'Use box width 4 of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . ($width > $height ? 4 : $width * 2) . 'x' . ($height > $width ? 4 : $height * 2) . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, -1, -1, 1, false, ($width > $height ? 1 : -1), ($height > $width ? 1 : -1), $additional_information), 'Use box width 1 of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . '. We expected the new image to be ' . ($width > $height ? 1 : $width * 2) . 'x' . ($height > $width ? 1 : $height * 2) . '. ' . $additional_information);
$this->assertTrue(runDimensionTest($extension, $width * 2, $height * 2, $width, $height, -1, true, $width, $height, $additional_information), 'Half the width and height with only make smaller = true of ' . $width * 2 . 'x' . $height * 2 . '.' . $extension . 'We expected the new image to be ' . $width . 'x' . $height . '. ' . $additional_information);
// TODO: Add test cases for cropping and padding in v11 after refactoring convert_image
}
// Edge Cases
if ($extension === 'png' || $extension === 'gif') {
$this->assertTrue(runTransparencyTest('transparent.' . $extension, 16, 16, 127, $additional_information), 'Increased 8x8 transparent.' . $extension . ' to 16x16 and tested for transparency on the left side and visible color on the right side. ' . $additional_information);
$this->assertTrue(runTransparencyTest('transparent.' . $extension, 4, 4, 127, $additional_information), 'Decreased 8x8 transparent.' . $extension . ' to 4x4 and tested for transparency on the left side and visible color on the right side. ' . $additional_information);
if ($extension === 'png') {
$this->assertTrue(runTransparencyTest('translucent.' . $extension, 16, 16, 63, $additional_information), 'Increased 8x8 translucent.' . $extension . ' to 16x16 and tested for 50 percent opacity on the left side and 100 percent opacity on the right side. ' . $additional_information);
$this->assertTrue(runTransparencyTest('translucent.' . $extension, 4, 4, 63, $additional_information), 'Decreased 8x8 translucent.' . $extension . ' to 4x4 and tested for 50 percent opacity on the left side and 100 percent opacity on the right side. ' . $additional_information);
}
}
}
}
}
@@ -551,7 +551,7 @@ function ensure_thumbnail($full_url, $thumb_url, $thumb_dir, $table, $id, $thumb
* @param ?array $thumb_options This optional parameter allows us to specify cropping or padding for the image. See comments in the function. (null: no details passed)
* @return boolean Success
*/
function convert_image($from, $to, $width, $height, $box_width = -1, $exit_on_error = true, $ext2 = null, $using_path = false, $only_make_smaller = true, $thumb_options = null)
function convert_image($from, &$to, $width, $height, $box_width = -1, $exit_on_error = true, $ext2 = null, $using_path = false, $only_make_smaller = true, $thumb_options = null)
{
require_code('images2');
cms_profile_start_for('convert_image');
@@ -102,7 +102,7 @@ function _ensure_thumbnail($full_url, $thumb_url, $thumb_dir, $table, $id, $thum
*
* @ignore
*/
function _convert_image($from, $to, $width, $height, $box_width = -1, $exit_on_error = true, $ext2 = null, $using_path = false, $only_make_smaller = false, $thumb_options = null)
function _convert_image($from, &$to, $width, $height, $box_width = -1, $exit_on_error = true, $ext2 = null, $using_path = false, $only_make_smaller = false, $thumb_options = null)
{
disable_php_memory_limit();
@@ -485,6 +485,12 @@ function _convert_image($from, $to, $width, $height, $box_width = -1, $exit_on_e
// Save
if (is_null($ext2)) {
$ext2 = get_file_extension($to);
if ($ext2 == '') {
$ext2 = get_file_extension($from);
if ($ext2 == '') {
$ext2 = null;
}
}
}
// If we've got transparency then we have to save as PNG
@@ -499,7 +505,7 @@ function _convert_image($from, $to, $width, $height, $box_width = -1, $exit_on_e
}
$lossy = ($width <= 300 && $width != -1 || $height <= 300 && $height != -1 || $box_width <= 300 && $box_width != -1);
$unknown_format = false;
$test = cms_imagesave($dest, $to, $ext2, $lossy, $unknown_format);
@@ -623,7 +623,7 @@ function png_compress($path, $lossy = false)
$parsed_colour = imagecolorsforindex($img, $at);
if ((isset($parsed_colour['alpha'])) && ($parsed_colour['alpha'] != 0)) {
$has_alpha = true;
if ($parsed_colour['alpha'] != 127) {
if ($parsed_colour['alpha'] != 0) {
// Blended alpha, cannot handle as anything other than a proper 32-bit PNG
imagedestroy($img);
return;

0 comments on commit 67754b8

Please sign in to comment.
You can’t perform that action at this time.