Good evening.
I'm having a virtual store script here, but I'm having problems with PNG images.
When uploading an image like this: .
Thescriptcheckstheextensionbasedonmimetype,"sanitizes" the file name and after that, generates 3 sizes of that image, such as Default, Thumbnail and Zoom. Being that in the "Standard" and "Thumbnail" images it resizes and in Zoom, if the image is large 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 the thumbnail it gets even worse. How can I make this image smoother?
The script for uploading and handling this image is a bit complex, so I'll post here the snippets that I think are the main ones.
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;
}
The below loads the image and then resizes it:
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 set to 0, I already tried to leave it with 1, 5, and 9, all stayed the same.
"getFilters ()" is as "PNG_ALL_FILTERS".
The PHP version is larger than 5.1.3, so it is using the first option.
I can not post the entire script here, as there are multiple files for the whole upload / resize process, many of them are not part of this problem either. But if anything was missing, just tell me that I look in the scripts and report how it is.
This problem is only happening with PNG. JPEG and GIF are both clean and smooth, both "zoom" and "standard" and "thumbnail" images.
Is there any way to work with PNG in PHP? Anything related to Alpha (I do not work too much with images, so I do not know what might be happening).
Thank you.