diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 5d7ae107..49070540 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,24 +1,96 @@ -name: run-tests +name: Tests -on: [push] +on: [ push, pull_request ] jobs: run: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - php-versions: ['8.0'] - name: Testing on PHP ${{ matrix.php-versions }} + php: [ '8.0', '8.1' ] + imagemagick: [ '6.9.12-43', '7.1.0-28' ] + imagick: [ '3.7.0' ] + stability: [ prefer-lowest, prefer-stable ] + + name: P${{ matrix.php }} - ${{ matrix.stability }} + steps: - - name: 'Checkout Project' + - name: Checkout project uses: actions/checkout@v2 - - name: 'Setup Environment' + + - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - extensions: imagick,gd - tools: phpunit,composer - - name: 'Install Dependencies' - run: composer install -o -q - - name: 'Run PHPUnit' - run: vendor/bin/phpunit \ No newline at end of file + php-version: ${{ matrix.php }} + extensions: mbstring, gd + coverage: none + + - name: Prepare environment for Imagemagick + run: | + sudo apt-get -y remove imagemagick imagemagick-6-common libmagic-dev + sudo apt-get update + sudo apt-get install -y libjpeg-dev libgif-dev libtiff-dev libpng-dev libwebp-dev + sudo apt-get install -y libmagickwand-dev + + - name: Cache ImageMagick + uses: actions/cache@v2 + id: cache-imagemagick + with: + path: /home/runner/im/imagemagick-${{ matrix.imagemagick }} + key: ${{ runner.os }}-ImageMagick-${{ matrix.imagemagick }}-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-ImageMagick-${{ matrix.imagemagick }}- + + - name: Check ImageMagick cache exists + uses: andstor/file-existence-action@v1 + id: cache-imagemagick-exists + with: + files: /home/runner/im/imagemagick-${{ matrix.imagemagick }} + + - name: Install ImageMagick + if: ( steps.cache-imagemagick.outputs.cache-hit != 'true' || steps.cache-imagemagick-exists.outputs.files_exists != 'true' ) + run: | + curl -o /tmp/ImageMagick.tar.gz -sL https://www.imagemagick.org/download/ImageMagick-${{ matrix.imagemagick }}.tar.gz + ( + cd /tmp || exit 1 + tar xf ImageMagick.tar.gz + cd ImageMagick-${{ matrix.imagemagick }} + sudo ./configure --prefix=/home/runner/im/imagemagick-${{ matrix.imagemagick }} + sudo make -j$(nproc) + sudo make install + ) + + - name: Install PHP ImageMagick extension + run: | + curl -o /tmp/imagick.tgz -sL http://pecl.php.net/get/imagick-${{ matrix.imagick }}.tgz + ( + cd /tmp || exit 1 + tar -xzf imagick.tgz + cd imagick-${{ matrix.imagick }} + phpize + sudo ./configure --with-imagick=/home/runner/im/imagemagick-${{ matrix.imagemagick }} + sudo make -j$(nproc) + sudo make install + ) + sudo bash -c 'echo "extension=imagick.so" >> /etc/php/${{ matrix.php }}/cli/php.ini' + php --ri imagick; + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ matrix.stability }}-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ matrix.stability }}- + + - name: Install dependencies + run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction + + - name: Which Imagick Version + run: php -r 'var_dump(Imagick::getVersion());' + + - name: Execute tests + run: vendor/bin/phpunit --no-coverage diff --git a/.gitignore b/.gitignore index 95483750..c7fe04e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ -.DS_Store -composer.lock -vendor/ .idea/ -.phpunit.result.cache \ No newline at end of file +build/ +vendor/ +.DS_Store +.phpunit.result.cache +composer.lock +phpunit.xml diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..63454441 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,23 @@ + + + + + ./tests/ + + + + + + src + + + diff --git a/src/Drivers/Gd/Color.php b/src/Drivers/Gd/Color.php index 46904b37..d4cde720 100644 --- a/src/Drivers/Gd/Color.php +++ b/src/Drivers/Gd/Color.php @@ -34,7 +34,7 @@ class Color extends AbstractColor implements ColorInterface public function toArray(): array { - $a = ($this->value >> 24) & 0xFF; + $a = ($this->value >> 24) & 0x7F; $r = ($this->value >> 16) & 0xFF; $g = ($this->value >> 8) & 0xFF; $b = $this->value & 0xFF; diff --git a/src/Drivers/Gd/Modifiers/FitModifier.php b/src/Drivers/Gd/Modifiers/FitModifier.php index 194376a5..de0e9725 100644 --- a/src/Drivers/Gd/Modifiers/FitModifier.php +++ b/src/Drivers/Gd/Modifiers/FitModifier.php @@ -37,15 +37,14 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface $current = $frame->getCore(); // preserve transparency + imagealphablending($modified, false); $transIndex = imagecolortransparent($current); if ($transIndex != -1) { $rgba = imagecolorsforindex($modified, $transIndex); $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); imagefill($modified, 0, 0, $transColor); - imagecolortransparent($modified, $transColor); } else { - imagealphablending($modified, false); imagesavealpha($modified, true); } @@ -65,7 +64,23 @@ class FitModifier extends AbstractFitModifier implements ModifierInterface imagedestroy($current); - // set new content as recource + if ($transIndex != -1) { // @todo refactor because of duplication + imagecolortransparent($modified, $transIndex); + for ($y = 0; $y < $resize->getHeight(); ++$y) { + for ($x = 0; $x < $resize->getWidth(); ++$x) { + if (((imagecolorat($modified, $x, $y) >> 24) & 0x7F) >= 100) { + imagesetpixel( + $modified, + $x, + $y, + $transIndex + ); + } + } + } + } + + // set new content as resource $frame->setCore($modified); } } diff --git a/src/Drivers/Gd/Modifiers/ResizeModifier.php b/src/Drivers/Gd/Modifiers/ResizeModifier.php index b030a8e3..7646a22f 100644 --- a/src/Drivers/Gd/Modifiers/ResizeModifier.php +++ b/src/Drivers/Gd/Modifiers/ResizeModifier.php @@ -44,15 +44,14 @@ class ResizeModifier implements ModifierInterface $current = $frame->getCore(); // preserve transparency + imagealphablending($modified, false); $transIndex = imagecolortransparent($current); if ($transIndex != -1) { $rgba = imagecolorsforindex($modified, $transIndex); $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); imagefill($modified, 0, 0, $transColor); - imagecolortransparent($modified, $transColor); } else { - imagealphablending($modified, false); imagesavealpha($modified, true); } @@ -72,6 +71,22 @@ class ResizeModifier implements ModifierInterface imagedestroy($current); + if ($transIndex != -1) { // @todo refactor because of duplication + imagecolortransparent($modified, $transIndex); + for ($y = 0; $y < $resizeTo->getHeight(); ++$y) { + for ($x = 0; $x < $resizeTo->getWidth(); ++$x) { + if (((imagecolorat($modified, $x, $y) >> 24) & 0x7F) >= 100) { + imagesetpixel( + $modified, + $x, + $y, + $transIndex + ); + } + } + } + } + // set new content as recource $frame->setCore($modified); } diff --git a/src/Interfaces/SizeInterface.php b/src/Interfaces/SizeInterface.php index 0e8ea82d..fd641fbe 100644 --- a/src/Interfaces/SizeInterface.php +++ b/src/Interfaces/SizeInterface.php @@ -9,6 +9,7 @@ interface SizeInterface public function getPivot(): PointInterface; public function setWidth(int $width): SizeInterface; public function setHeight(int $height): SizeInterface; + public function resize(?int $width = null, ?int $height = null): SizeInterface; public function getAspectRatio(): float; public function fitsInto(SizeInterface $size): bool; public function isLandscape(): bool; diff --git a/tests/ModiferStackTest.php b/tests/ModifierStackTest.php similarity index 100% rename from tests/ModiferStackTest.php rename to tests/ModifierStackTest.php diff --git a/tests/TestCase.php b/tests/TestCase.php index d9b53621..8985b4e8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -3,7 +3,6 @@ namespace Intervention\Image\Tests; use Intervention\Image\Interfaces\ColorInterface; -use PHPUnit\Framework\TestCase as PHPUnitTestCase; use Mockery\Adapter\Phpunit\MockeryTestCase; abstract class TestCase extends MockeryTestCase diff --git a/tests/Traits/CanCreateGdTestImage.php b/tests/Traits/CanCreateGdTestImage.php index e2e5d81a..9d12ed2b 100644 --- a/tests/Traits/CanCreateGdTestImage.php +++ b/tests/Traits/CanCreateGdTestImage.php @@ -21,7 +21,7 @@ trait CanCreateGdTestImage public function createTestImage($filename = 'test.jpg'): Image { - return $this->testImageDecoder()->handle( + return $this->createWithImageDecoder()->handle( $this->getTestImagePath($filename) ); } @@ -41,7 +41,7 @@ trait CanCreateGdTestImage ])); } - protected function testImageDecoder(): FilePathImageDecoder + protected function createWithImageDecoder(): FilePathImageDecoder { return new FilePathImageDecoder(); } diff --git a/tests/Traits/CanCreateImagickTestImage.php b/tests/Traits/CanCreateImagickTestImage.php index 0ff42675..c097c50e 100644 --- a/tests/Traits/CanCreateImagickTestImage.php +++ b/tests/Traits/CanCreateImagickTestImage.php @@ -11,12 +11,12 @@ trait CanCreateImagickTestImage { public function createTestImage($filename = 'test.jpg'): Image { - return $this->testImageDecoder()->handle( + return $this->createWithImageDecoder()->handle( sprintf('%s/../images/%s', __DIR__, $filename) ); } - protected function testImageDecoder(): FilePathImageDecoder + protected function createWithImageDecoder(): FilePathImageDecoder { return new FilePathImageDecoder(); }