Průhlednost PNG a GIF při Image::resize()
- Milo
- Nette Core | 1283
Potřeboval jsem zmenšovat obrázky s průhledným pozadím a s
Image::resize()
jsem se nikdy nedostal ke kýženému výsledku.
Myslím, že to není problém Nette, ale samotných GD knihoven a problémů IE
zobrazovat PNG.
Následující konstrukce nefungovala na GIF. Ten zůstával s černým pozadím. Na PNG fungovala, ale IE6 potom namísto transparentní zobrazilo jakousi kvazišedou. Očividně nějaká chyba v interpretaci palety.
<?php
$img->alphaBlending(false);
$img->saveAlpha(true);
?>
Rozšířil jsem třídu Image
. Nevýhoda toho je, že nelze
použít metody Image::fromFile()
Image::fromString()
a Image::fromBlank()
, protože vždy vytvoří instanci třídy
Image
.
Nová implementace resize()
nepočítá se zápornými rozměry,
tedy flip. Jiné metody jsem nepřepisoval (ani netestoval), ikdyž mohou ve
výsledku generovat chybný obrázek.
Kód je v podstatě směsí z diskuzí na php.net a hodinovým Googlováním. Je pomalý a hodí se v podstatě pouze k jednorázovému vygenerování miniatur.
Použití:
<?php
$img = new MImage( imagecreatefromstring( file_get_contents( $pathToFile )));
$img->resize( "20%", "20%" );
$img->save( $outFile );
?>
<?php
class MImage extends Image
{
public function resize( $width, $height, $flags = self::FIT )
{
list( $newWidth, $newHeight ) = self::calculateSize( $this->getWidth(), $this->getHeight(), $width, $height, $flags );
if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) // resize
{
$newImage = imagecreatetruecolor( $newWidth, $newHeight );
$oldTranIdx = imagecolortransparent( $this->getImageResource() );
if( $oldTranIdx >= 0 ) // transparent color exists
{
imagealphablending( $newImage, false );
$oldTranColor = imagecolorsforindex( $this->getImageResource(), $oldTranIdx );
$tranIdx = imagecolorallocatealpha( $newImage, $oldTranColor['red'], $oldTranColor['green'], $oldTranColor['blue'], 127 );
imagefill( $newImage, 0, 0, $tranIdx );
}
imagecopyresampled( // resize
$newImage, $this->getImageResource(),
0, 0, 0, 0,
$newWidth, $newHeight, $this->getWidth(), $this->getHeight()
);
imagedestroy( $this->getImageResource() );
if( $oldTranIdx >= 0 ) // recover transparency if exists
{
imagecolortransparent( $newImage, $tranIdx );
for( $y = 0; $y < $newHeight; ++$y )
{
for( $x = 0; $x < $newWidth; ++$x )
{
$color = imagecolorat( $newImage, $x, $y );
if((( $color >> 24 ) & 0x7F ) >= 100) imagesetpixel( $newImage, $x, $y, $tranIdx );
}
}
imagetruecolortopalette( $newImage, true, 255 ); // save as palette image
imagesavealpha( $newImage, false );
}
$this->setImageResource( $newImage );
}
return $this;
}
}
?>
- mmm
- Člen | 1
Milo napsal(a):
Potřeboval jsem zmenšovat obrázky s průhledným pozadím a s
Image::resize()
jsem se nikdy nedostal ke kýženému výsledku. Myslím, že to není problém Nette, ale samotných GD knihoven a problémů IE zobrazovat PNG.Následující konstrukce nefungovala na GIF. Ten zůstával s černým pozadím. Na PNG fungovala, ale IE6 potom namísto transparentní zobrazilo jakousi kvazišedou. Očividně nějaká chyba v interpretaci palety.
Na průhledné gif-y mi funguje v PHP tohle :
<?php
$src=ImageCreateFromGIF('src.gif');
$src_size=GetImageSize('src.gif');
// #dstx a $dsty jsou zadane / spocitane ze $src_size...
$dst=ImageCreate($dstx,$dsty);
imagesavealpha($dst, true);
$trans_colour = imagecolorallocatealpha($dst, 0, 0, 0, 127);
imagefill($dst, 0, 0, $trans_colour);
ImageCopyResampled($dst,$src,0,0,0,0,$dstx,$dsty,$src_size[0],$src_size[1]);
//tohle zajisti pruhlednost dst po resample
imagecolortransparent($dst, $trans_colour);
?>
Ten tvůj cyklus není potřeba :-)