Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use highest quality for JPEG and PNG images #2318

Merged
merged 1 commit into from
May 30, 2023

Conversation

MegaChriz
Copy link
Contributor

Description

This sets the quality of JPEG and PNG files to their maximum. It does this by:

  • defining a property called $imageQuality and a method called getImageQuality() to PhpOffice\PhpWord\Element\Image;
  • setting the property $imageQuality to 100 in case of image/jpeg or image/jpg and set it to 0 in case of image/png;
  • PhpOffice\PhpWord\Media and PhpOffice\PhpWord\Writer\AbstractWriter making use of the 'imageQuality' property.

I also added test coverage for PhpOffice\PhpWord\Element\Image::getImageQuality().

Fixes #2317

Checklist:

  • I have run composer run-script check --timeout=0 and no errors were reported
  • The new code is covered by unit tests (check build/coverage for coverage report)
  • I have updated the documentation to describe the changes

src/PhpWord/Element/Image.php Outdated Show resolved Hide resolved
@PowerKiKi PowerKiKi changed the base branch from develop to master November 16, 2022 21:07
Copy link
Member

@Progi1984 Progi1984 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@PowerKiKi
Copy link
Member

@MegaChriz, I pushed the changes I had in mind. Would you mind testing that it still behave as you expect, please ?

@MegaChriz
Copy link
Contributor Author

@PowerKiKi Great! I plan to test it this Wednesday.

$this->imageExtension = 'png';
$this->imageQuality = 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PNG $quality is the zlib compression level, it is a lossless value. $filters is what enables any lossy compression but it is disabled by default. Setting PNG quality to 0 disables all compression resulting in larger files with no quality benefit.

The default for https://www.php.net/imagepng is -1 which in-turn defaults to the zlib compression default which from the zlib documentation is a quality value of 6

The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6).

Suggest changing the PNG quality value to -1 not 0 in this patch.

@MegaChriz
Copy link
Contributor Author

With the latest changes images fail to render in my case:
no-image

I'm using the following code for parsing an image (because the image is not publicly available, a cookie is needed to retrieve it):

protected static function parseImage($node, $element)
{
    $src = $node->attributes->getNamedItem('src')->nodeValue;

    $image_attr = [];
    $attributes = [
      'width',
      'height',
    ];
    foreach ($attributes as $key) {
      $attribute = $node->attributes->getNamedItem($key);
      if ($attribute) {
        $image_attr[$key] = $attribute->nodeValue;
      }
    }
    $context = stream_context_create([
      'http' => [
        'method' => 'GET',
        'header' => [
          'Cookie: ' . $_SERVER['HTTP_COOKIE']."\r\n",
        ],
      ],
    ]);

    try {
      return $element->addImage(file_get_contents($src, FALSE, $context), $image_attr);
    }
    catch (InvalidImageException $e) {
      // Log invalid image exceptions.
      watchdog_exception('panelsreport', $e);
    }
    return NULL;
}

When trying to debug this, I see that previously the image generation happened in AbstractWriter::addFilesToPackage(). Now I assume it should happen in Image::getImageString() but in there $this->sourceType happens to be equal to 'string', not 'gd'. There was no such check in AbstractWriter::addFilesToPackage(), apparently that used the image generation functions regardless of the source type.

This sets the quality of JPEG files to their maximum. It does this by:

- defining a property called `$imageQuality` and a method called `getImageQuality()` to PhpOffice\PhpWord\Element\Image
- setting the property `$imageQuality` to `100` for JPG, but keep default compression level for PNG
- refactor fragile string callbacks into proper closure that use the new `$imageQuality`

In the case of a PNG, this is not the _quality_ of the image, but the
_filesize_ of the image. So we use the default value for best
speed/filesize balance.
@PowerKiKi PowerKiKi merged commit 34eb13b into PHPOffice:master May 30, 2023
8 checks passed
@PowerKiKi
Copy link
Member

Released as 1.1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Use highest quality for JPEG and PNG images
4 participants