Průhlednost PNG a GIF při Image::resize()

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Milo
Nette Core | 1283
+
0
-

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;
    }
}
?>
wdolek
Člen | 331
+
0
-

mam takovy pocit, ze IE6 transparenci u PNG nezvlada vubec (proto ta kvaziseda)

mmm
Člen | 1
+
0
-

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 :-)

Milo
Nette Core | 1283
+
0
-

Ten tvůj cyklus není potřeba :-)

Je potřeba pro obnovu průhlednosti u PNG. Při sloučení se totiž některým pixelům nastaví alpha průsvitnost a je prblém v IE6.