1
Good night.
I’m with a virtual store script here, but I’m having problems with PNG images.
When uploading an image like this: .
The script checks the extension based on mimetype, "sanitize" the file name and after all, generates 3 sizes of this image, being Standard, Thumbnail and Zoom. Being that in the images "Standard" and "Thumbnail" it makes the resizing and in Zoom, if the image is big enough it keeps the same size.
The problem is that when it resizes to a smaller size, the image gets kind of "broken":
And in miniature it gets even worse. How can I make this image smoother?
The upload and processing script of this image is a bit complex, so I will post here the excerpts that I think are the main.
The script below uploads the image:
public static function importImage($temporaryPath, $originalFilename, $productId, $hash = false, $moveTemporaryFile = true, $generateImages = true)
{
if (!file_exists($temporaryPath)) {
throw new ISC_PRODUCT_IMAGE_SOURCEFILEDOESNTEXIST_EXCEPTION($temporaryPath);
}
try {
$library = ISC_IMAGE_LIBRARY_FACTORY::getImageLibraryInstance($temporaryPath);
} catch (ISC_IMAGE_LIBRARY_FACTORY_INVALIDIMAGEFILE_EXCEPTION $ex) {
throw new ISC_PRODUCT_IMAGE_IMPORT_INVALIDIMAGEFILE_EXCEPTION();
} catch (ISC_IMAGE_LIBRARY_FACTORY_NOPHPSUPPORT_EXCEPTION $ex) {
throw new ISC_PRODUCT_IMAGE_IMPORT_NOPHPSUPPORT_EXCEPTION();
}
if ($library->getWidth() < 1 || $library->getHeight() < 1) {
throw new ISC_PRODUCT_IMAGE_IMPORT_EMPTYIMAGE_EXCEPTION();
}
$finalName = $originalFilename;
$finalName = basename($finalName); // remove any path components from the filename
$finalName = self::sanitiseFilename($finalName);
if (!self::isValidFilename($finalName, false)) {
throw new ISC_PRODUCT_IMAGE_IMPORT_INVALIDFILENAME_EXCEPTION($finalName);
}
// correct the uploaded extension
$correctExtension = $library->getImageTypeExtension(false);
if (strtolower(pathinfo($finalName, PATHINFO_EXTENSION)) != $correctExtension) {
// remove existing extension and trailing . if any
$finalName = preg_replace('#\.[^\.]*$#', '', $finalName);
// add correct extension
$finalName .= '.' . $correctExtension;
}
// generate a path for storing in the product_images directory
$finalRelativePath = self::generateSourceImageRelativeFilePath($finalName);
$image = new ISC_PRODUCT_IMAGE();
$image->setSourceFilePath($finalRelativePath);
$finalAbsolutePath = $image->getAbsoluteSourceFilePath();
$finalDirectory = dirname($finalAbsolutePath);
if (!file_exists($finalDirectory)) {
if (!isc_mkdir($finalDirectory, ISC_WRITEABLE_DIR_PERM, true)) {
throw new ISC_PRODUCT_IMAGE_IMPORT_CANTCREATEDIR_EXCEPTION($finalDirectory);
}
}
if ($moveTemporaryFile) {
if (!@rename($temporaryPath, $finalAbsolutePath)) {
throw new ISC_PRODUCT_IMAGE_IMPORT_CANTMOVEFILE_EXCEPTION($finalAbsolutePath);
}
} else {
if (!@copy($temporaryPath, $finalAbsolutePath)) {
throw new ISC_PRODUCT_IMAGE_IMPORT_CANTMOVEFILE_EXCEPTION($finalAbsolutePath);
}
}
// check to see if the uploaded image exceeds our internal maximum image size: ISC_PRODUCT_IMAGE_MAXLONGEDGE
if ($library->getWidth() > ISC_PRODUCT_IMAGE_MAXLONGEDGE || $library->getHeight() > ISC_PRODUCT_IMAGE_MAXLONGEDGE) {
// if it is, resize it and overwrite the uploaded source image because we only want to store images to a maximum size of ISC_PRODUCT_IMAGE_MAXLONGEDGE x ISC_PRODUCT_IMAGE_MAXLONGEDGE
$library->setFilePath($finalAbsolutePath);
$library->loadImageFileToScratch();
$library->resampleScratchToMaximumDimensions(ISC_PRODUCT_IMAGE_MAXLONGEDGE, ISC_PRODUCT_IMAGE_MAXLONGEDGE);
$library->saveScratchToFile($finalAbsolutePath, self::getWriteOptionsForImageType($library->getImageType()));
}
if ($productId === false) {
// do not assign product hash, id or save to database if $productId is false
if ($generateImages) {
// manually generate images since, normally, a call to saveToDatabase would do it
$image->getResizedFileDimensions(ISC_PRODUCT_IMAGE_SIZE_TINY, true, false);
$image->getResizedFileDimensions(ISC_PRODUCT_IMAGE_SIZE_THUMBNAIL, true, false);
$image->getResizedFileDimensions(ISC_PRODUCT_IMAGE_SIZE_STANDARD, true, false);
$image->getResizedFileDimensions(ISC_PRODUCT_IMAGE_SIZE_ZOOM, true, false);
}
return $image;
}
if ($hash) {
$image->setProductHash($productId);
} else {
$image->setProductId($productId);
}
// ISC_PRODUCT_IMAGE_SOURCEFILEDOESNTEXIST_EXCEPTION should never really happen at this point with all the checks above so, if it does, let the exception go unhandled to bubble up to a fatal error
$image->saveToDatabase($generateImages);
return $image;
}
Below loads the image and then resize:
public function loadImageFileToScratch()
{
$filePath = $this->getFilePath();
$imageType = $this->getImageType();
// Attempt to increase the memory limit before loading in the image, to ensure it'll fit in memory
ISC_IMAGE_LIBRARY_FACTORY::setImageFileMemLimit($filePath);
switch ($imageType) {
case IMAGETYPE_GIF:
$this->_scratchResource = @imagecreatefromgif($filePath);
if ($this->getScratchResource()) {
imagecolortransparent($this->getScratchResource());
}
break;
case IMAGETYPE_PNG:
$this->_scratchResource = @imagecreatefrompng($filePath);
if ($this->_scratchResource) {
// this sets up alpha transparency support when manipulating and saving the in-memory image
imagealphablending($this->getScratchResource(), false);
imagesavealpha($this->getScratchResource(), true);
}
break;
case IMAGETYPE_JPEG:
$this->_scratchResource = @imagecreatefromjpeg($filePath);
break;
default:
throw new ISC_IMAGE_LIBRARY_GD_UNSUPPORTEDIMAGETYPE_EXCEPTION($imageType);
}
$this->_updateImageInformation(true);
if (!$this->getScratchResource()) {
throw new ISC_IMAGE_LIBRARY_GD_IMAGECREATEFROMFILE_EXCEPTION($imageType, $filePath);
}
}
After loading the image and making the necessary changes, the script below saves:
public function saveScratchToFile($destinationFilePath, ISC_IMAGE_WRITEOPTIONS $imageWriteOptions)
{
$imageType = $imageWriteOptions->getImageType();
switch ($imageType) {
case IMAGETYPE_JPEG:
imagejpeg($this->getScratchResource(), $destinationFilePath, (int)$imageWriteOptions->getQuality());
break;
case IMAGETYPE_PNG:
if (version_compare(PHP_VERSION, '5.1.3', '>=')) {
// filters parameter was added in 5.1.3
imagepng($this->getScratchResource(), $destinationFilePath, (int)$imageWriteOptions->getCompression(), (int)$imageWriteOptions->getFilters());
} else if (version_compare(PHP_VERSION, '5.1.2', '>=')) {
// quality parameter was added in 5.1.2
imagepng($this->getScratchResource(), $destinationFilePath, (int)$imageWriteOptions->getCompression());
} else {
imagepng($this->getScratchResource(), $destinationFilePath);
}
break;
case IMAGETYPE_GIF:
imagegif($this->getScratchResource(), $destinationFilePath);
break;
default:
throw new ISC_IMAGE_LIBRARY_GD_UNSUPPORTEDIMAGETYPE_EXCEPTION($imageType);
break;
}
isc_chmod($destinationFilePath, ISC_WRITEABLE_FILE_PERM);
}
"getCompression()" is 0, I tried to leave with 1, 5 and 9, all were the same.
"getFilters()" is like "PNG_ALL_FILTERS".
The PHP version is larger than 5.1.3, so it is using the first option.
I can’t post the whole script here as it is multiple files for the whole upload/resize process, many of them are not even part of this problem. But if anything is missing, just tell me that I look in the scripts and let me know how it is.
This problem is happening only with PNG. JPEG and GIF are forming clean and smooth images, both in "zoom", as in "pattern" and "thumbnail".
Are there any tricks to work with PNG in PHP? Something related to Alpha (I don’t work much with images, so I don’t know what might be going on).
Thank you.
Junior, just to be sure, is the serrated PNG image actually being resized and saved into a new dimension? Check the image properties and check the original dimensions to see if it is not being resized by HTML, I do not know the GD do this with the image, except if there is a bug in the compression function of your script, value "0" is without any compression, that is, quality, and 9 is total compression, and even so the PNG compression of GD changes very little the quality, unlike the 'quality' from 0 to 100 for JPG, which leaving "0" is horrible image.
– Thyago ThySofT
@Thyagothysoft I hadn’t even touched it, but after you spoke I went to see the image, I even downloaded it and actually it was resized.
– Junior Zancan
Junior, I hadn’t really come across this situation yet. From what I understood in the code, first is made the
resize
then transparency is applied. If this is indeed the case, the process withimagecolorallocatealpha
in the original size applying transparency, and then performing resize? Maybe it will improve. I tested with white background and this serration effect is not caused.– Thyago ThySofT
Forget it, it’s not that, I just tested your image on my function and it didn’t serrate like yours. I’ll draw up an answer based on my role, it’ll be easier to adapt.
– Thyago ThySofT
Okay, thank you very much.
– Junior Zancan