Portál o technologiích a vývoji

Obrázky ve webových aplikacích – Ukládání obrázků

Autor: Adam Klvač Datum: 10.10.2013 Počet shlédnutí: 3 991 367x

Obrázek jsme v minulém dílu ořezali, otočili, přebarvili, vložili vodoznak a popsali jsme jej. Jenže máme pořád jenom jakousi obrazovou mapu typu resource – jak obrázek zobrazíme, nebo uložíme?

Pro jednotlivé formáty existují funkce pro jejich uložení. Jejich povinným parametrem je resource obrázku, pokud neuvedeme další parametry, obrázek se odešle do prohlížeče. Druhým parametrem je název souboru k uložení a třetím kompresní poměr či kvalita.

// Odešleme obrázek k uživateli jako JPG
imagejpeg($image);

// Uložíme obrázek jako PNG
// (kompresní level není uveden - výchozí je 0, tedy bez komprese)
imagepng($image, __DIR__ . '/uploads/' . $name . '.png');

// Uložíme obrázek jako JPG v 80% kvalitě
imagejpeg($image, __DIR__ . '/uploads/' . $name . '.jpg', 80);

// Uložíme obrázek jako GIF (nemá parametr udávající kompresi)
imagegif($image, __DIR__ . '/uploads/' . $name . '.gif');

Občas se hodí získat řetězec obrázku jako řetězec. Funkce, která by to umožnila přímo, není. Dá se ale použít output buffering, kterým můžeme výstup skriptu zachytit do proměnné.

// Zahájíme zachytávání výstupu
ob_start();

// Odešleme obrázek jako PNG
imagepng($image);

// Zachytíme jeho výstup do proměnné, k uživateli nic nepřijde
$binary = ob_get_clean();

Je také dobré poznamentat, že při odesílání obrázku do prohlížeče uživatele to musíme uvést v HTTP hlavičce.

header('Content-Type: image/gif'); // Pro GIF
header('Content-Type: image/jpeg'); // Pro JPG
header('Content-Type: image/png'); // Pro PNG

Obrázek smažeme funkcí unlink.

unlink($name);

Ukázka celkového zpracování

Následující ukázkový kód přijme obrázek od uživatele, zmenší jej na polovinu, otočí o 90° doprava a uloží jej v takovém formátu, v jakém přišel.

if($_POST) { // Formulář byl odeslán

    // Detekce chyby
    if($_FILES['soubor']['error'] !== UPLOAD_ERR_OK) {

        // Rozpoznání chybového kódu
        switch($_FILES['soubor']['error']) {

            case UPLOAD_ERR_NO_FILE:
                error("Vyberte, prosím, obrázek.");
            break;

            case UPLOAD_ERR_INI_SIZE:
                error("Obrázek je příliš velký.");
            break;

            default:
                error("Obrázek se nepodařilo nahrát.");
            break;

        }

    }

    // Kontrola, zda server disponuje extenzí GD
    if(!function_exists('gd_info')) {

        // Poněkud matoucí, ale je nutné mít toto
        // ohlídáno (lepší než prázdná stránka po fatal error)
        error("Obrázek není možné nahrát.");

    }

    // Informace o obrázku
    $info = getimagesize($_FILES['soubor']['tmp_name']);

    // Kontrola, zda jde o obrázek
    if(!$info) {
        error("Zvolený soubor není platným obrázkem.");
    }

    $image = imagecreatefromstring($_FILES['soubor']['tmp_name']);
    $width = $info[0];
    $height = $info[1];
    $type = $info[2];

    // Kontrola, zda jde o podporovaný typ
    $allowed = array(IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_JPEG);
    if(!in_array($type, $allowed)) {
        error("Obrázek musí být ve formátu PNG, JPG nebo GIF.");
    }

    // Zmenšení obrázku
    $newWidth = $width / 2;
    $newHeight = $height / 2;

    $resized = imagecreatetruecolor($newWidth, $newHeight);
    imagealphablending($resized, false);
    imagesavealpha($resized,true);
    $transparent = imagecolorallocatealpha($resized, 255, 255, 255, 127);
    imagefilledrectangle($resized, 0, 0, $newWidth, $newHeight, $transparent);
    imagecopyresampled(
        $resized, $image,
        0, 0, 0, 0,
        $newWidth, $newHeight,
        $width, $height
    );
    imagedestroy($image);
    $image = $resized;

    // Rotace obrázku
    $rotated = imagerotate($image, 360 - 90, 0xFF0000);
    imagedestroy($image);
    $image = $rotated;

    // Vytvoříme jméno obrázku
    $name = uniqid();
    $dbimage = $database->images->insert(array(
        'name' => $name
    ));
    $name .= $dbimage->id;

    // Uložení obrázku
    switch($type) {

        case IMAGETYPE_PNG:
            imagepng($image, $name . '.png');
        break;

        case IMAGETYPE_JPEG:
            imagejpeg($image, $name . '.jpg');
        break;

        case IMAGETYPE_GIF:
            imagegif($image, $name . '.gif');
        break;

    }

}

Protože by mohlo v průběhu zpracování dojít k netušeným chybám, jako všechno doporučuji používat nějakou vrstvu na zachytávání chyb. Pro pohodlnější práci s obrázky se mi velmi osvědčila třída Nette\Image, která obaluje práci s obrázky do objektu a vyhazuje vyjímky, se kterými je mnohem snadnější pracovat.

Práce s obrázky může být poněkud ošemetná a je při ní nutné myslet na všechna rizika. Na druhou stranu to není nic až tak složitého a v dnešní sféře webových aplikací je vlastně nutné umět obrázky zpracovat. Funkcí pro práci s obrázky není nijak mnoho a ukázal jsem zde pouze ty nejzákladnější, s trochou času se ale dá vytvořit například vyobrazení křivek, není nic složitého například přebarvovat obrázky, či je analyzovat (to se může hodit pro hlídání obrázků s pornografickým materiálem). To jsou ale již operace s jednotlivými pixely, což není z technického hlediska tak složité, není to ale podle mne předmětem tohoto článku. Nejdůležitější body – přejmenovat, nevěřit hlavičce s formátem a předpokládat problémy.

Štítky: | | | | | |

Žádné komentáře

Poslat komentář

Vaše e-mailová adresa nebude zveřejněna.