Zmenšování obrázků

Školení, která pořádám

Jednu funkci na změnu velikosti obrázků jsem už uváděl. Pokud je zdrojový obrázek menší než maximální povolené rozměry, může být zvětšení, které daná funkce provede, nežádoucí. Pokud si navíc chceme do databáze poznamenat výsledné rozměry, tak bychom je potřebovali vrátit. A pokud soubor navíc chceme pojmenovat podle ID přidruženého záznamu, tak bude nejšikovnější funkci rozdělit do dvou:

<?php
/** Vrácení rozměrů obrázku po zmenšení
* @param string název zmenšovaného souboru
* @param int maximální šířka výsledného obrázku, 0 pokud na ní nezáleží
* @param int maximální výška výsledného obrázku, 0 pokud na ní nezáleží
* @return array ($width, $height) výsledná šířka a výška
* @copyright Jakub Vrána, http://php.vrana.cz/
*/
function image_shrink_size($file_in, $max_x = 0, $max_y = 0) {
    list($width, $height) = getimagesize($file_in);
    if (!$width || !$height) {
        return array(0, 0);
    }
    if ($max_x && $width > $max_x) {
        $height = round($height * $max_x / $width);
        $width = $max_x;
    }
    if ($max_y && $height > $max_y) {
        $width = round($width * $max_y / $height);
        $height = $max_y;
    }
    return array($width, $height);
}

/** Převzorkování obrázku GIF, PNG nebo JPG
* @param string název zmenšovaného souboru
* @param string název výsledného souboru
* @param int šířka výsledného obrázku
* @param int výška výsledného obrázku
* @return bool true, false v případě chyby
* @copyright Jakub Vrána, http://php.vrana.cz/
*/
function image_resize($file_in, $file_out, $width, $height) {
    $imagesize = getimagesize($file_in);
    if ((!$width && !$height) || !$imagesize[0] || !$imagesize[1]) {
        return false;
    }
    if ($imagesize[0] == $width && $imagesize[1] == $height) {
        return copy($file_in, $file_out);
    }
    switch ($imagesize[2]) {
        case 1: $img = imagecreatefromgif($file_in); break;
        case 2: $img = imagecreatefromjpeg($file_in); break;
        case 3: $img = imagecreatefrompng($file_in); break;
        default: return false;
    }
    if (!$img) {
        return false;
    }
    $img2 = imagecreatetruecolor($width, $height);
    imagecopyresampled($img2, $img, 0, 0, 0, 0, $width, $height, $imagesize[0], $imagesize[1]);
    if ($imagesize[2] == 2) {
        return imagejpeg($img2, $file_out);
    } elseif ($imagesize[2] == 1 && function_exists("imagegif")) {
        imagetruecolortopalette($img2, false, 256);
        return imagegif($img2, $file_out);
    } else {
        return imagepng($img2, $file_out);
    }
}

// použití
list($width, $height) = image_shrink_size($_FILES["obrazek"]["tmp_name"], 760, 760);
if ($width && $height && mysql_query("INSERT INTO obrazky (jmeno, sirka, vyska) VALUES ('" . $_FILES["obrazek"]["name"] . "', $width, $height)")) {
    $filename = mysql_insert_id() . "." . pathinfo($_FILES["obrazek"]["name"], PATHINFO_EXTENSION);
    image_resize($_FILES["obrazek"]["tmp_name"], $filename, $width, $height);
}
?>
Jakub Vrána, Řešení problému, 3.4.2006, diskuse: 74 (nové: 0)

Diskuse

Michal:

Jelikoz zmensovani obrazku je vypecetne celkem narocne, je velice vhodne vyledne zmensene obrazky ukladat na serveru na disk.

Termiter:

A pokud ti hosting příliš omezí přidělenou paměť, nebo je obrázek moc velký (oroginál foto), tak to moc nefunguje.
Z tohoto důvodu při práci s fotografiemi používám náhled v EXIFu.
ALe jinak pro menší obrázky je to v pohodě.

lukas:

S timhle problemem se dost casto setkavam. Nijak se mi dopredu zjistit, jestli gd funkce ma dost pameti a pri zavolani nespadne. Jedine, cim tenhle problem trochu omezuju je, ze si pres ini_set zvetsim velikost dostupne pameti na 32 MB a pak je obtiznejsi vytvorit obrazek, ktery nebude mozne zpracovat. Nicmene pokud se to i pres to stane, tak cely skript konci chybou a stranky, kde je ten obrazek vlozeny, se nezobrazi (popr. se zobrazi jen cast, zalezi na tom, jak se zastaveni skriptu projevi).

Jinak resamplovane obrazky si ukladam na disk vetsinou ve formatu puvodnijmeno_w200_h133.jpg (kde 200 a 133 muzou byt odlisne).

lukas:

Jinak, pokud se pred zminene funkce da @ tak to taky spadne.

karel:

nezapomeň ještě taky, že když zmenšuješ GIF s průhlednou barvou, musíš touto barvou nejprve vyplnit cílový obrázek a nastavit ji jako průhlednou

Lampicka:

osobne bych GD asi nepouzil; myslim ze podstatne lepsi vysledky se daji dosahnout pomoci imagicku/magickwandu

ikona Jakub Vrána OpenID:

Mluv prosím konkrétně - v čem jsou ty výsledky lepší?

Filip:

Konkretne treba to, ze na tech x radku ktere tam mas staci jeden radek exec('....');

Navic moznosti imagemagicku co se tyce konverzi obrazku jsou diametralne odlisne od moznosti gd

vice: man convert

ondra:

pri zmenseni bych rad vyuzil nejakou funkci pro zostreni fotky, ale nepodarilo sem mi nic takoveho v php najit, zmensenim (treba nahledy fotek) dost kvalita trpi

martin:

Kdysi jsem zkoušel tento skript http://vikjavev.no/computing/ump.php , ale Imagemagick je mnohem lepší, výkonnější. Pomocí volby -sharpen se jím dá i ostřit (resp. měnit kontrast v hranách - zlepšení ostrosti za cenu horší kontrasti).

ondra:

jeste jednou, funkce imagejpeg ma treti parametr pro kvalitu vysledneho jpg, tim se da regulovat vysledna velikost a kvalita samozrejme, ale zostreni to neni

ikona MiSHAK:

Hm... čekal jsem něco bombastického (asi jsem naivní), ale tento příklad se hodí.
Abych se přidal :) "V minulosti jsem "taky" něco podobného řešil."

No max_x = 0 stačí napsat max_x, protože zatím nikde překladač neuhádné jaky parametr máme na mysli.

Možná by se hodilo určit v parametrech i výstupní formát...
Třeba pomocí dalšího parametru img_type. Například u malých fotek ( 50x50 nebo 100x100 atp.) by bylo jpg větší než třeba png. Je to jen domněnka...

ikona Jakub Vrána OpenID:

$max_x = 0, $max_y = 0 znamená, že oba parametry jsou nepovinné. Výstupní formát se nastavuje podle vstupního, což je obvykle ta nejlepší volba.

Juraj:

Co sa tyka formatov, na ukladanie fotiek je najlepsi jpeg i u velkosti 50x50. Format png(8 bit) doporucujem pouzivat iba u graf. materialov s poctom farieb < 256 (napr. zoscanovane dokumenty).

Abulafia:

A nechce se náhodou někomu napsat nějakou chytrou a jednoduchou fci na doostřování fotek? Co si budem povídat - když fotografii zmenšujete a nedoostříte, tak vám vypadnou pěkný blafy :-)

Jája:

Při použití této funkce se mi obrázky občas uloží nedodělané. Kus je obrázek OK a kus jen šedivej. Nevíte čím to je a jak se toho zbavit?

Pepino:

Nevím jestli jsem něco udělal špatně, ale ta první funkce na získání velikosti náhledu, mi blbne například při velikosti obrázku 384x477. Vrátilo mi to asi jenom výšku, šířka byla 0.

kachnak:

zdravim prosim vas tato funkcia imagecopyresized ak zmensi obrazok tak je taky "kockaty" hranaty nezaostreny a ked zmensim obrazok v PC pomocou irfanview softu tak je ovela krajsi ako ked sa zmensi na servery s atributom kvality 100 ( imagejpeg($thumb,"$meno",100); )... neviete ako spravit aby bol aj ten na servery po zmenseni pekny ako cez soft v pc..
ten na servery po zmenseni zabera ovela viac KB ako ten povodny vacsieho rozslisenia pred uploadom na net.. a i ked zabera viac kb je ovela skaredsi... :(
dakujem

jakub:

mam stejny problem a reseni jsem este nenasel
jde to nejvice vydet na nocnich fotografii...je tam mnoho sumu

jakub:

odpovim si sam :) .. nasel jsem fci imagecopyresampled, ktera dava vyrazne lepsi vysledky, bohuzel jsem ale take zaznamenal jeji vetsi narocnost na vypocetni vykon

ikona Jakub Vrána OpenID:

Je to tak. Jen nevím, proč to píšete pod ukázku kódu, která používá imagecopyresampled() od samého začátku :-).

ikona temistokles:

Ono je všeobecne vhodnejšie po zistení rozmerov sa rozhodnúť, či najskôr nebude vhodné obrázok zmenšiť pomocou imagecopyresized() a až následne pomocou imagecopyresampled(). Kvalitou je výsledok skoro rovnaký a pamäťová náročnosť podstatne klesne. Je už len potrebné rozhodnúť sa, od akej veľkosti sa podstúpi medzikrok s imagecopyresized().

ikona Jakub Vrána OpenID:

Rozhodně bych neřekl, že je výsledek skoro stejný. U funkce imagecopyresized() jsou výsledky naopak dost žalostné a odpovídají zhruba zmenšení obrázku v prohlížečích uvedením jiných rozměrů.

J4cker:

nefunguje mi $file_in jsem zadal $file_in = $nazev_obrazku_uploadovaneho a nejde potreboval bych vice porad 316-071-469 dík

Vigez:

Je tato myslienka spravna?
<?php
   
if ($max_x && $width > $max_x) {
        $height = round($height * $max_x / $width);
        $width = $max_x;
    }
    if ($max_y && $height > $max_y) {
        $width = round($width * $max_y / $height);
        $height = $max_y;
    }
?>
Totiz ak je obrazok nizsi a sirsi, zmensi ho na vysku $max_y a sirku vypocita proporcialne, cize zrejme viac ako 100px.
Skusal som si spravit priklad a nastava tam tento problem.

ikona Jakub Vrána OpenID:

Tak ten příklad uveď... První větev zaručí, že obrázek nebude širší než $max_x. Druhá větev může šířku pouze zmenšit (protože $height > $max_y => $max_y/$height < 1).

Vigez:

Tu je spominany priklad:
<?php
if(($maxx >= $imagesize[0]) && ($maxy >= $imagesize[1]))
                      {
                        @copy($inputfile,$outputfile);
                        @chmod($outputfile,0644);
                      }
                    else
                      {
                        if($maxx && $imagesize[0]>$maxx)
                          {
                            $height = round($imagesize[1] * $maxx / $imagesize[0]);
                            $width = $maxx;
                          }
                        if($maxy && $imagesize[1]>$maxy)
                          {
                            $width = round($imagesize[0] * $maxy / $imagesize[1]);
                            $height = $maxy;
                          }
                        switch ($imagesize[2])
                        {
                        case 1: $img = imagecreatefromgif($inputfile); break;
                        case 2: $img = imagecreatefromjpeg($inputfile); break;
                        case 3: $img = imagecreatefrompng($inputfile); break;
                        }

                        $img2 = imagecreatetruecolor($width, $height);
                        imagecopyresampled($img2, $img, 0, 0, 0, 0, $width, $height, $imagesize[0], $imagesize[1]);

...

                      }
?>
...

Popis: $maxx - maximalna sirka
       $maxy - maximalna vyska
       $imagesize[0] - skutocna sirka obrazku
       $imagesize[1] - skutocna vyska obrazku

ikona Jakub Vrána OpenID:

Čeho to je prosímtě příklad? Chtěl jsem, abys uvedl čtyři čísla ($max_x, $max_y, $width, $height), pro která můj kód podle tebe nefunguje.

Vigez:

$max_x=100;
$max_y=100;
$width=420;
$height=70;

Ak sirka $width prekracuje hranicu $max_x a pritom je vyska $height mensia ako $max_y narazim na neuspech.

ikona Jakub Vrána OpenID:

V čem spočívá ten neúspěch? Pro tento vstup vrátí můj kód správný výstup (100, 17).

ikona Jakub Vrána OpenID:

Chyba spočívá v tom, že místo $height>$max_y používáš $imagesize[1]>$maxy.

DrMizerie:

Mám problém s ukládáním a následným zmenšováním pro ukládání požívám skript z vašich stránek:
<?php
  $koncovky
= array('jpg', 'jpeg', 'png', 'gif');
  $chybao = "";

  if (!$_FILES || $_FILES["fotka1"]["error"] == UPLOAD_ERR_INI_SIZE) {
      $chybao = "Soubor je příliš velký, maximální velikost je " . ini_get('upload_max_filesize') . ".\n";
  } elseif ($_FILES["fotka1"]["error"] == UPLOAD_ERR_NO_FILE) {
      $chybao = "Nevybrali jste soubor, který chcete nahrát.\n";
  } elseif ($_FILES["fotka1"]["error"]) {
      $chybao = "Soubor se nepodařilo nahrát, kontaktujte prosím správce serveru.\n";
  } elseif (!in_array(strtolower(pathinfo($_FILES["fotka1"]["name"], PATHINFO_EXTENSION)), $koncovky)) {
      $chybao = "Koncovka souboru musí být jedna z: " . implode(", ", $koncovky) . ".\n";
  } elseif (!($imagesize = getimagesize($_FILES["fotka1"]["tmp_name"])) || $imagesize[2] > 3 ) {
      $chybao = "Typ obrázku musí být JPG, PNG nebo GIF.\n";
  } else {
      move_uploaded_file($_FILES["fotka1"]["tmp_name"], "Photo/" . $_FILES["fotka1"]["name"]);
  }
  if ($chybao) echo "<span style=\"color: red\"><p><b>Došlo k chybě!!!!!</b>
                <p>
$chybao<p>Opravte tyto chyby a odešlete formulář znovu.<p></span>";
?>

A když použiji vaše funkce pro zmenšení a skript:
<?php
IF (!$chybao){
    list($width, $height) = image_shrink_size($_FILES["fotka1"]["tmp_name"], 150, 150);
    If ($width && $height){
      $filename = "./Photo/" .$_FILES["fotka1"]["name"] . "_X" . pathinfo($_FILES["fotka1"]["name"], PATHINFO_EXTENSION);
      image_resize($_FILES["fotka1"]["tmp_name"], $filename, $width, $height);
   }
  }
?>

Tak to hlásí neustále chybu....Neveděl by někdo kde je chyba nebo co dělám špatně? Díky za odpověď 

ikona Jakub Vrána OpenID:

Kdybys aspoň napsal, jakou chybu to hlásí. Potom by třeba někomu stálo za to se tvým problémem zabývat.

DrMizerie:


Warning: getimagesize() [function.getimagesize]: Unable to access /tmp/phpmW5xye in /home/www/.... on line 38

Warning: getimagesize(/tmp/phpmW5xye) [function.getimagesize]: failed to open stream: No such file or directory in /home/www/.... on line 38

Štěpán Svoboda:

Tohle nemá nic společného se zmenšováním obrázků, nýbrž s nastavením oprávnění souborového systému. Obrázek se Vám po upoloadu uloží pod dočasným jménem (/tmp/phpmW5xye), který webový server (PHP) nemůže přečíst.

maylow:

mam problem. nevite cim to muze byt, že všechny gify i png se najednou tmavujou? mám pocit, ze driv nedelalo. teprve pak jsem objevil tento clanek a dělá to uplne to samé. stalo se to taky nekomu?

lubo:

Skús ppoužiť ImageCreateTrueColor

Petr Chmelar:

Toz jsem si s tim chvili taky hral a vymyslel (prevzal ode vseho to nejlepsi :) tuhle funkci... Jinak souhlasim a jeste ji rozdelim na 2 ;)
Pokud myslite, ze nefunguje, piste na chmelarp at fit vutbr cz (se zavinacem a teckama).

Petan

<?php

$file_in
= "img.jpg";
// get width, height

if (! imagemagic($file_in, null, 400, 300) ) {
     print("<b>Nevyslo to...</b><br />");
}

/**
* need GD library (first PHP line WIN: dl("php_gd.dll"); UNIX: dl("gd.so");
* www.boutell.com/gd/
* interval.cz/clanky/php-skript-pro-generovani-galerie-obrazku-2/
* cz.php.net/imagecopyresampled
* www.linuxsoft.cz/sw_detail.php?id_item=871
* www.webtip.cz/art/wt_tech_php/liquid_ir.html
* php.vrana.cz/zmensovani-obrazku.php
* diskuse.jakpsatweb.cz/
*
* @param string $file_in Vstupni soubor (mel by existovat)
* @param string $file_out Vystupni soubor, null ho jenom zobrazi (taky kdyz nema pravo se zapsat :)
* @param int $width Vysledna sirka (maximalni)
* @param int $height Vysledna vyska (maximalni)
* @param bool $crop Orez (true, obrazek bude presne tak velky), jinak jenom Resample (udane maximalni rozmery)
* @param int $type_out IMAGETYPE_type vystupniho obrazku
* @return bool Chyba kdyz vrati false
*/
function imagemagic($file_in, $file_out=null, $width=null, $height=null, $crop=null, $type_out=null) {
    if ($file_in !=="" && File_Exists($file_in))
    {
        // get width, height, IMAGETYPE_type
        list($w, $h, $type) = GetImageSize($file_in); //array of width, height, IMAGETYPE, "height=x width=x" (string)
        // print("Input: ". image_type_to_mime_type($type) ." $w x $h<br>");

        // vyber funkce pro nacteni vstupu
        switch($type)
        {
            case IMAGETYPE_JPEG: $imgIn = 'ImageCreateFromJPEG'; break;
            case IMAGETYPE_PNG : $imgIn = 'ImageCreateFromPNG';  break;
            case IMAGETYPE_GIF : $imgIn = 'ImageCreateFromGIF';  break;
            case IMAGETYPE_WBMP: $imgIn = 'ImageCreateFromWBMP'; break;
            default: return false; break;
        }

        // jaky typ chcem vyrobit? jestli je to fuk, tak ten samy...
        if ($type_out == null) {    // ...krom Wbitmapy, ta je blba :)
            $type_out = ($type == IMAGETYPE_WBMP) ? IMAGETYPE_PNG : $type;
        }
        switch($type_out)
        {
            case IMAGETYPE_JPEG: $imgOut = 'ImageJPEG'; break;
            case IMAGETYPE_PNG : $imgOut = 'ImagePNG';  break;
            case IMAGETYPE_GIF : $imgOut = 'ImageGIF';  break;
            case IMAGETYPE_WBMP: $imgOut = 'ImageWBMP'; break; // bitmapa je blbost
            default: return false; break;
        }

        // toz, jak ma byt vysledek veliky?
        if ($width == null || $width == 0) { // neni zadana sirka
            $width = $w;
        }
        else if ($height == null || $height == 0) { // neni zadana vyska, ale sirka jo... hmm, toz je dam stejne :)
            $height = $width;
        }

        if ($height == null || $height == 0) { // neni zadana vyska, ale sirka taky ne :)
            $height = $h;
        }

        // jestli se ma jenom zmensovat...
        if (!$crop) { // prepocti velikost - nw, nh (new width/height)
            $scale = (($width / $w) < ($height / $h)) ? ($width / $w) : ($height / $h); // vyber mensi pomer

            $src = array(0,0, $w, $h);
            $dst = array(0,0, floor($w*$scale), floor($h*$scale));
        }
        else { // bude se orezavat
            $scale = (($width / $w) > ($height / $h)) ? ($width / $w) : ($height / $h); // vyber vetsi pomer a zkus to nejak dopasovat...
            $newW = $width/$scale;    // jak by mel byt zdroj velky (pro poradek :)
            $newH = $height/$scale;

            // ktera strana precuhuje vic (kvuli chybe v zaokrouhleni)
            if (($w - $newW) > ($h - $newH)) {
                $src = array(floor(($w - $newW)/2), 0, floor($newW), $h);
            }
            else {
                $src = array(0, floor(($h - $newH)/2), $w, floor($newH));
            }

            $dst = array(0,0, floor($width), floor($height));
        }

        // print("posX\t posY\t widt\t heig\t - transformation:<br>"."$src[0]\t $src[1]\t $src[2]\t $src[3]\t <br>"."$dst[0]\t $dst[1]\t $dst[2]\t $dst[3]\t <br>");
        // print("Output: ". image_type_to_mime_type($type) ." $dst[2] x $dst[3]<br>");

        // proved resampling...
        if (@$image1 = $imgIn($file_in))
        {
            $image2 = ImageCreateTruecolor($dst[2], $dst[3]);
            ImageCopyResampled($image2, $image1, $dst[0],$dst[1], $src[0],$src[1], $dst[2],$dst[3], $src[2],$src[3]);

            // pokud se ma pouze zobrazit, dej vedet co prijde (MIME type)... (tedko uz se snad nic nepokazi)
            if ($file_out == null) {
                header("Content-type: ". image_type_to_mime_type($type_out));
            }

            // set jpeg/png quality to 85 before saving
            if ($type_out == IMAGETYPE_JPEG || $type_out == IMAGETYPE_PNG)    {

                $imgOut($image2, $file_out, 85);
            }
            else { // save the image
                $imgOut($image2, $file_out);
            }

            ImageDestroy($image1); // free memory
            ImageDestroy($image2);

            return true; // tohle je jediny misto, kde se da vratit uspech
        }
    }
    return false;
}
?>

Honza:

Ahoj, poradil by mi někdo jak z tohodle posledního skriptu od Petra dostanu kopii obrázku resp. nově změněný obrázek

něco jako return copy (file_in, $file_out);

SeET:

no sice asi nechápu jakou kopii chces ale poduk myslíš jak nový obrázek uložit, tak tady je řešení :

<?php

$file_in
= "img.jpg";
// get width, height

$nazev_noveho = "img2.jpg";

if (!
imagemagic($file_in, $nazev_noveho, 400, 300) ) {
     print("<b>Nevyslo to...</b><br />");
}
?>
......

je to puze zmenseny obrazek ve stejnem formatu.

Stefan:

Použil som to takto:

<?php
     include_once
("zmensimg.php");
?>
<HTML><HEAD>
<META content="text/html; charset=windows-1250" http-equiv=Content-Type>
<META name=GENERATOR content="MSHTML 8.00.6001.18854">
<STYLE></STYLE>
</HEAD>
<BODY bgColor=#ffffff>

<IMG border=0 hspace=0 align=baseline src="<?php imagemagic("hus_hody.gif",null, 0, 100);?>">;

</BODY></HTML>

zobrazuje mi vsak namiesto obrázku <„2 9ćtĐŤ   5  ĆĆ4ň  ÜčrĂ <ęňOŽl<ÂÍ .l!  ät Ę ä( A"ˇt A Ęt †•Ćx ... atď... Pritom tam je header ... atď... V čom je problém? Ako to použiť ako funkciu na zobrazenie zmenšeniny? Ďakujem

Jirka:

Díky, výborný script

Traverz:

Tento script mi nefunguje pre znacne sirsie obrazky napr.: sirka: 760px a vyska: 151px
Ine obrazky funguju perfektne az na obrazky s vacsiou velkostou, pri ktorych sa zmensenina neulozi ale vytvori iba ciernu zmenseninu. No toto nemusi byt chyba scriptu.
Zial doposial som nevedel vyriesit problem so sirsimi obrazkami.
Neviete niekto pomoct?

ikona Jakub Vrána OpenID:

Dej odkaz na obrázek, se kterým jsou problémy, a uveď přesný kód, který pro zmenšení používáš (musí obsahovat stanovení výsledných rozměrů).

Teprve potom máš šanci, že se tvým dotazem bude někdo zabývat.

Traverz:

Obrazok: http://geryon.org/adds/gallery/normal/14_goticky-kriz.jpg

Zdrojovy kod:
<?php
                    $path
="adresar_full/"; //adresar pre plne nahlady
                    $pathmini="adresar_mini/"; //adresar pre zmenseniny
                    $maxsize=524288; //maximalna velkost v b
                    $inputfile = $path.$name; //vstupny udaj
                    $outputfile = $pathmini.$name; //vystupny udaj
                    $maxx=100; //maximalny rozmer sirky
                    $maxy=100; //maximalny rozmer vysky

                    $imagesize = @getimagesize($inputfile);

                    if($imagesize[0] && $imagesize[1])
                      {

                    if(($maxx >= $imagesize[0]) && ($maxy >= $imagesize[1]))
                      {
                        @copy($inputfile,$outputfile);
                        @chmod($outputfile,0644);
                      }
                    else
                      {
                        if($maxx && $imagesize[0]>$maxx)
                          {
                            $height = round($imagesize[1] * $maxx / $imagesize[0]);
                            $width = $maxx;
                          }
                        if($maxy && $imagesize[1]>$maxy)
                          {
                            $width = round($imagesize[0] * $maxy / $imagesize[1]);
                            $height = $maxy;
                          }

                        switch ($imagesize[2])
                        {
                        case 1: $img = imagecreatefromgif($inputfile); break;
                        case 2: $img = imagecreatefromjpeg($inputfile); break;
                        case 3: $img = imagecreatefrompng($inputfile); break;
                        }

                        $img2 = imagecreatetruecolor($width, $height);
                        imagecopyresampled($img2, $img, 0, 0, 0, 0, $width, $height, $imagesize[0], $imagesize[1]);

                        if ($imagesize[2] == 2)
                          {
                            imagejpeg($img2,$outputfile);
                          }
                        elseif ($imagesize[2] == 1 && function_exists("imagegif"))
                          {
                            imagetruecolortopalette($img2, false, 256);
                            imagegif($img2,$outputfile);
                          }
                        else
                          {
                            imagepng($img2,$outputfile);
                          }

                        ImageDestroy($img);
                        ImageDestroy($img2);
                        @chmod($outputfile,0644);
}
}
?>

Toto je kod, ktory pouzivam, prosim ak by mi vedel niekto pomoct, budem mu velmi povdacny, lebo tento problem ma valmi trapi.

ikona Jakub Vrána OpenID:

Chyba spočívá v tom, že místo $height>$max_y používáš $imagesize[1]>$maxy.

Traverz:

Mozno je to neprofesionalna otazka, ale neviem sa dopatrat k spravnemu rieseniu.
Je nejaky vyrazny rozdiel medzi $imagesize[1] ($imagesize = @getimagesize($inputfile);) a $height (list($width, $height) = getimagesize($file_in);) ?

ikona Jakub Vrána OpenID:

Zásadní rozdíl spočívá v tom, že proměnná $height se o kousek výš může nastavit na jinou hodnotu než $imagesize[1].

Traverz:

Skusal som si zostavit novy script a tato zmena nepriniesla ziaden uspech, tiez nepredpokladam, ze by sa premenna prepisala.

machajda:

jak se ty skripty používaj? teprve sem začal

máca:

Nevím jak vám, ale tenhle kód (jak jsem již tušil dle náhledu) mi nevyřešil problém s žalostnou kvalitou zmenšenin obrázků typu gif a černým pozadím u obrázků typu png.

ikona Jakub Vrána OpenID:

Pro zmenšování paletových obrázků se je vyplatí nejdříve převést na plné barvy a potom zase zpátky. Průhlednost respektuje funkce imagecopymerge().

Jirka:

Mohl by jste rozvést tu informaci více uvedením příkladu, jak se zbavit toho černého pozadí u formátu PNG. např. jak tam dát pozadí bílé ?

ikona Ma.Cizek:

Já mám též problém při ukládání do databáze se mi všechny proměné i data z originálního obrázku uloží ale z proměné $file_out kdy by měla být data ze zmensěného obrázku se nic neuloží možná ta proměná něco udělala ale uložila jen 0b. Nemohl by mi někdo poradit.

<?php

require('xxx.php'); // Připojení k MySQL serveru

// Pokud uživatel nevybral žádný soubor, nastane chyba.

if($_FILES['soubor']['error']) {

   die('Chyba při získávání souboru');

}
$jmeno = $_POST['jmeno'];

$obsah = $_FILES['soubor']['tmp_name']; // Umístění dočasného souboru

$nazev = $_FILES['soubor']['name']; // Původní název

$mime = $_FILES['soubor']['type']; // MIME typ

// Načteme obsah dočasného souboru

$file_in = implode('', file("$obsah"))

   or die("Nelze načíst dočasný soubor $obsah");

/** Vrácení rozměrů obrázku po zmenšení
* @param string $file_in název zmenšovaného souboru
* @param int [$max_x] maximální šířka výsledného obrázku, 0 pokud na ní nezáleží
* @param int [$max_y] maximální výška výsledného obrázku, 0 pokud na ní nezáleží
* @return array ($width, $height) výsledná šířka a výška
* @copyright Jakub Vrána, http://php.vrana.cz
*/
function image_shrink_size($obsah, $max_x = 0, $max_y = 180) {
    list($width, $height) = getimagesize($obsah);
    if (!$width || !$height) {
        return array(0, 0);
    }
    if ($max_x && $width > $max_x) {
        $height = round($height * $max_x / $width);
        $width = $max_x;
    }
    if ($max_y && $height > $max_y) {
        $width = round($width * $max_y / $height);
        $height = $max_y;
    }
    return array($width, $height);
}

/** Převzorkování obrázku GIF, PNG nebo JPG
* @param string $file_in název zmenšovaného souboru
* @param string $file_out název výsledného souboru
* @param int $width šířka výsledného obrázku
* @param int $height výška výsledného obrázku
* @return bool true, false v případě chyby
* @copyright Jakub Vrána, http://php.vrana.cz
*/
function image_resize($obsah, $file_out, $width, $height) {
    $imagesize = getimagesize($obsah);
    if ((!$width && !$height) || !$imagesize[0] || !$imagesize[1]) {
        return false;
    }
    if ($imagesize[0] == $width && $imagesize[1] == $height) {
        return copy($obsah, $file_out);
    }
    switch ($imagesize[2]) {
        case 1: $img = imagecreatefromgif($obsah); break;
        case 2: $img = imagecreatefromjpeg($obsah); break;
        case 3: $img = imagecreatefrompng($obsah); break;
        default: return false;
    }
    if (!$img) {
        return false;
    }
    $img2 = imagecreatetruecolor($width, $height);
    imagecopyresampled($img2, $img, 0, 0, 0, 0, $width, $height, $imagesize[0], $imagesize[1]);
    if ($imagesize[2] == 2) {
        return imagejpeg($img2, $file_out);
    } elseif ($imagesize[2] == 1 && function_exists("imagegif")) {
        imagetruecolortopalette($img2, false, 256);
        return imagegif($img2, $file_out);
    } else {
        return imagepng($img2, $file_out);
    }
}
// použití
$dc=Date("Y-m-d H:i:s");
$da=Date("d.m. Y H:i:s");
list(
$width, $height) = image_shrink_size($_FILES["obrazek"]["tmp_name"], 760, 760);
if (
mysql_query (sprintf ("INSERT INTO obrazky (mime, obsah, mini, jmeno, datum, datim) VALUES ('$mime', '%s', '%s', '$nazev', '$da', '$dc')",mysql_escape_string("$file_in"),mysql_escape_string("$file_out")))) {
    $filename = mysql_insert_id() . "." . pathinfo($_FILES["obrazek"]["name"], PATHINFO_EXTENSION);
    image_resize($_FILES["obrazek"]["tmp_name"], $filename, $width, $height);
}
?>

ikona Mch81:

Zdravim,
mam problem s touto casti kodu     <?php imagecopyresampled($image_p, $image, 0, 0, 0, 0, $NewWidth, $NewHeight, $OrigWidth, $OrigHeight);?>
Na lokalu mi to jede, ale na hostingu u OneBit uz ne, na tomto radku se to kousne. Jen dodam max uploaded file size je 30M.

Diky za odpoved
Michal

ikona Mch81:

Problem hledejte u allow_url_fopen musi byt ON. Aspon tak jsem vyresil problem ja

Honza:

Ví někdo, jak je funkce getimagesize náročná na paměť? Můžu ji s klidným svědomím použít před každým zobrazením obrázku na stránce (pro nastavení atributů width a height)?

ikona Jakub Vrána OpenID:

Paměťově náročná funkce není, ze souboru načte jen prvních 12 bajtů. Nicméně pokud se seznam obrázků načítá např. z databáze, doporučil bych uložení rozměrů tam, což ušetří provádění souborových operací.

Honza:

Diky moc za odpoved, predpokladal jsem to, ale nikde jsem nemohl nalezt potvrzeni.

ikona Jakub Vrána OpenID:

Potvrzení je na http://cvs.php.net/viewvc.cgi/php-src/ext/…=markup#l1184 :-).

David:

mám menší problém...při použiti imagecreatefromJPEG mi to celé spadne s tím že jsem překročil množství přidělené paměti

Kubajs:

Zdravím, mám script, který sice nepracuje s databazí, ale jinak zmenšování je prakticky shodné s tím vaším.
Problém: obrázek (png) se sice zmenší, ale rozměry podkladu zůstanou stejné (zmenšený obrázek zůstane jen usazený v rohu). Nemáte tip v čem by mohl být problém?

Kubajs:

Tak už nic, chyba ve verzi GD knihovny.

Jarda:

Byl by někdo tak hodný a vysvětlil mi matematicky toto:

<?php
   
if ($max_x && $width > $max_x) {
        $height = round($height * $max_x / $width);
        $width = $max_x;
    }
    if ($max_y && $height > $max_y) {
        $width = round($width * $max_y / $height);
        $height = $max_y;
    }
?>

Respektive nejsem si jistý proč se takto  vypočítává ten poměr $height = round($height * $max_x / $width);

Děkuji

ikona Jakub Vrána OpenID:

$max_x / $height je poměr zvětšení. Po vynásobení původní výškou vyjde nová výška.

Jarda:

Předpokládám, že si chtěl napsat $max_y / $height. Nějak mi to nedocvaklo, že tím vlastně počítám poměr :) Děkuji.

Ještě jednu otázečku bych však měl. Řeší uvedené jestli je obrázek orientován na výšku nebo na šířku? Nedokážu totiž najít, jestli např. poměr zmenšení strany X je větší než poměr zmenšení strany Y a proto se má zmenšit na výchozí hodnotu jedna ze stran dle výsledku.

Podle uvedené rovnice bych totiž předpokládal že se bude v drtivé většině zmenšovat dle výšky a šířka se bude dopočítávat. (Neboť předpokládám poslední if bude skoro pokaždé true).

Možná se mýlím, nejsem v matematice moc dobrý (ale snažím se :))

ikona Jakub Vrána OpenID:

Chtěl jsem napsat $max_x / $width. Ale platí to samozřejmě i pro $max_y / $height.

Druhý if přijde ke slovu tehdy, když je obrázek víc na výšku než požadované rozměry. Takže když jsou požadované maximální rozměry třeba 100x100, tak se spustí pro všechny obrázky na výšku.

Jarda:

Mějme obrázek o rozměrech 1000 (šířka) x 200 (výška)

Chci ho zmenšit např. na max rozměry 150 x 100.

<?php
$width
= 1000;
$height = 200;
$max_y = 100;

    if (100 &&  200 > 100) { //TRUE
        $width = round($width * $max_y / $height); //$width = 500;
        $height = 100;
    }
?>

Obrázek je tedy orientován na šířku a přesto se bude zmenšovat podle poměru výšky a dostávám tak na šířku větší rozměr (500), než který jsem si určil na začátku (150)

Nebo dělám někde chybu?

ikona Jakub Vrána OpenID:

Nebylo by jednodušší si to spustit (nezapomeň nastavit $max_x)? Před tím, než se testuje $max_y, se ověří $max_x, které výšku upraví. Výsledné rozměry budou tedy 150 x 30.

Jarda:

Já jsem blbec, nedošlo mi, že se vlastně už pracuje s upravenou výškou. Děkuji, teď už mi to je vše jasné. :D

ikona Aleš Spurný:

Dobrý den,

zkoušel jsem Váš kód na zmenšení obrázků. Zjistil jsem ale, že při zmenšení obrázku dojde ke zhoršení kvality a ptám se, jestli jde napsat takový script, který by patřičně změnil rozměry obrázku a přitom nechal kvalitu stejnou ? Jinak se omlouvám, pokud je dotaz nevhodný.

Výtvarník Jiří Dvořák:

Zdravím, přesně tak.
Když zmenšuji pomocí imagecopyresampled, tak stejnak i když vypnu antialiasing, tak fotografie jsou nepatrně roostřené, i když výstup imagejpeg je na 100. Když je antialiasing zapnut tak je to hrůza, když to dělám přes imagecopyresized, tak je to o něco lepší, ale stejnak to není úplně ostrý, tak jako původní fotografie. Nevím jak na to. Ale si Vítek Č. bude muset zmenšit fotografie ručně. Sice mají 500 kB, což je zlo pro isdn gprs káře, ale to mi řeší preloader. Předem díky za jakékoliv rady ohledně zachování ostrosti (nikoliv doostřování) při zmenšování nahrávaných fotografiích.
JD

Oldřich Válek:

Možná zkusit Imagick, když na všech serverech není k dispozici.

Marek:

Zdar děcka, mám dotaz dá se změnit rozlišení obrázku? Z 300 obr/palec na 72 v PHP? Díky Mára

Vložit příspěvek

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2016 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.