crop.php

Z thewoodcraft.org

Jedním z velkých oříšků jsou u MediaWiki obrázky, protože by default nelze použít procentuální nastavení velikosti obrázku. Nicméně jsem přišel na to, jak se to dá obejít. Pokud se povolí použití html elementu img nastavením proměnné $wgAllowImageTag = true;. Kromě toho potřebujete ještě rozšíření ImageSizeInfoFunctions, které umožňuje vytáhnout rozměry použitého obrázku (či stránky DjVu dokumentu), aby pak bylo možné přepočítat ostatní parametry podle originální velikosti. Pro zjednodušení jsem vytvořil šablonu {{Image}}, která se používá podobně, jako když se obrázky vkládají do stránky standardním způsobem.

Je-li velikost obrázků nastavena v procentech, nedochází po přeškálování obsahu stránky k jejich přeskupení – vše se přepočítá podle aktuální šíře okna webového prohlížeče. Díky tomu stránka vypadá stejně bez ohledu na to, jestli si ji prohlížíte v mobilu či na počítači. Podrobněji je to vysvětleno v dokumentaci k šabloně {{Image}}.

Bohužel původní šablonu {{Image}} nebylo možné použít na obrázky ze stránek generovaných z DjVu dokumentů přes rozšíření Proofreadpage. Současná verze MediaWiki (1.34) by default nenabízí nic, co by umožnilo udělat z vloženého obrázku pouhý výřez. Existuje sice způsob, kterým to lze obejít pomocí CSS, jenomže ten má svá omezení:

  • Nedá se použít na stránky generované z DjVu či PDF souborů.
  • Umí použít pouze originální obrázek, který se natahuje vždy v plné velikosti.

Zkoušel jsem to řešit nejrůznějšími způsoby, ale každý měl nějaké nedostatky. Nakonec nezbylo než si napsat wrapper crop.php, který volá distribuční generátor náhledů Thumb.php, jenž umí generovat náhledy stránek. Wrapper crop.php vygenerovaný náhled zpracuje ještě před odesláním do webového prohlížeče na straně serveru podle dalších parametrů. Takže se po síti posílá jen nezbytně nutné množství dat.

Použití souboru crop.php

Obrázek zpracovaný přes šablonu {{Image}} se vkládá přes element img rovnou do stránky. Šablona ho umožňuje dále upravit, např. zarovnat do středu či k pravému okraji stránky a případně i pootočit. Jaký je rozdíl mezi použitím souboru thumb.php a crop.php pochopíte ihned, když si otevřete do nových panelů následující odkazy a podíváte se na vlastnosti vygenerovaných obrázků.

https://www.thewoodcraft.org/wiki/thumb.php?f=new_york-panorama_1909.jpg&width=400
https://www.thewoodcraft.org/wiki/crop.php?f=new_york-panorama_1909.jpg&width=400&cx=-80&cy=-60&cw=280&ch=210&resize=1.45

Zatím co první link vrátí zmenšený náhled celého obrázku. Druhý link vrátí výřez z jeho zmenšené verze, přeškálovaný zhruba na stejnou velikost. V obou případech bude velikost obrázků v kB přibližně stejná (30kB). Při aplikaci výřezu přes CSS by se stahoval obrázek v plné velikosti, což obnáší cca 10,63MB (viz Soubor:new_york-panorama_1909.jpg). A navíc by jeho velikost nešlo přizpůsobit obsahu stránky.

Co si musíte pohlídat

  • thumb.php selže, pokud se pokusíte vygenerovat náhled o velikosti stejné, či větší, než je originální velikost obrázku
  • Při generování náhledů obrázků se využívá volání shellu a MediaWiki má limitované jednak množství serverové paměti $wgMaxShellMemory, použitelné při zpracování skriptu (cca 200MB), ale i maximální velikost souboru $wgMaxShellFileSize (zde cca 100MB). U své vlastní wiki si ale můžete upravit tyto limity dle možností vašeho serveru. Viz https://www.mediawiki.org/wiki/Topic:Vh0jjxqoihx8pj33
  • Když se pokusíte vygenerovat obrázek o šířce větší než 3500px, vygenerování náhledu s velkou pravděpodobností selže. Pamatujte na to, že u obrázků určených ke zobrazení na webových stránkách bohatě stačí maximální šířka do 1000px. U velkých obrázků může generování náhledu selhat kvůli nastaveným limitům. Proto byste měli při vygenerování obrázků přes crop.php používat atribut width, kterým "natvrdo" omezíte velikost náhledu ze kterého se pak bude udělat výřez. Budete-li ho chtít mít větší, můžete si vypomoci atributem resize, který umožňuje až trojnásobné zvětšení výřezu.
Občas ale chcete dostat na stránku obrázek v plném rozlišení. Pro takové případy má {{Image}} implementovaný jednoduchý trik. Pokud je hodnota width stejná jako velikost originálního obrázku, použije se místo náhledu originál. Stačí tedy vynechat atribut width. Má to ovšem jedno omezení. Z takového obrázku neuděláte výřez. Přes thumb.php se totiž nedá vytáhnou obrázek v originální velikosti. Obejít to lze jednoduchým způsobem – stačí id originální velikosti odečíst jeden pixel. Pak už vás bude limitovat pouze dostupné množství paměti shellu.

Atributy

Aktuální php kód souboru crop.php je uveden níže, z něj můžete snadno zjistit jaké atributy předávané přes URL lze použít. Pokud chcete mít u své wiki podobnou funkcionalitu jako je zde, můžete tento kód, s uvedením zdroje – www.thewoodcraft.org, i obsah šablony {{Image}} použít. Nezapomeňte ale šablonu upravit podle konfigurace vaší vlastní MediaWiki.

Následující atributy zpracovává thumb.php. Bez nich skončí volání oznámením chyby.

f – Wiki jméno souboru (obrázek v JPG, PNG či GIF formátu, nebo PDF či DjVu dokument). Nikoliv jeho URL!
width – Šířka náhledu.
page – Číslo stránky se používá pouze u DjVu a PDF dokumentů. Pokud není uvedeno, vrátí thumb.php automaticky vygenerovaný náhled titulní stránky (page=1).
Upozornění Jméno souboru předávané atributem f, nesmí obsahovat mezery. Pokud je obsahuje, nahraďte je podtržítkem – velmi častá a záludná chyba!!!

Další atributy:

cx, cy – nastavují posun obsahu výchozího obrázku (v pixelech), vůči vygenerovanému náhledu! Tzn. že pokud změníte šířku náhledu (attribut width) budete muset upravit i hodnotu těchto parametrů.
cw, ch – nastavení velikosti zobrazené plochy v pixelech. Platí zde totéž co pro nastavení posunu. Při změně šířky náhledu musíte upravit i velikost zobrazené plochy – výřezu, pokud chcete aby zobrazoval stále stejný obsah.
resize – je atribut, kterým lze vygenerovaný výřez zvětšit, nebo zmenšit ještě před odesláním obrázku webovému prohlížeči. Tzn. že není nezbytně nutné měnit velikost výřezu změnou atributů width, cx, cy, cw, ch. Stačí použít atribut resize, jehož hodnota se musí pohybovat v rozmezí od 0.01 do 3 (trojnásobné zvětšení výřezu). Pokud tento atribut není uveden, je výsledek stejný, jako kdyby měl hodnotu 1 (default)
Upozornění Pokud nebude uveden atribut cw, budou všechny atributy pro nastavení výřezu i atribut resize opomenuty a výsledkem bude zobrazení náhledu, bez ořezání

PHP kód souboru crop.php

<?php
/**
 * PHP script pro výřez a přeškálování náhledu obrázku.
 */

parse_str( $_SERVER[ 'QUERY_STRING'] , $query);

$query['f'] ?? die('Missing media file') ;
$query['width'] ?? die('Missing default thumbail size') ;

// Sestavení URL pro thumb.php; šířka musí být vždy minimálně o 1 pixel menší než originální velikost obrazu!
// $urlfile = "https://www.thewoodcraft.org/wiki/thumb.php?f=indian_1923.djvu&page=4&width=100";
isset($query['page'])
    ? $urlfile = 'https://' . $_SERVER[ 'HTTP_HOST' ] . '/wiki/thumb.php?' . http_build_query( array (
        'f'     => $query['f'],
        'page'  => $query['page'],
        'width' => $query['width']
        ) )
    : $urlfile = 'https://' . $_SERVER[ 'HTTP_HOST' ] . '/wiki/thumb.php?' . http_build_query( array (
        'f'     => $query['f'],
        'width' => $query['width']
        ) ) ;

// $query['cx'] - posun obrazu v pixelech; kladná hodnota doprava záporná doleva (default 0)
// $query['cy'] - posun obrazu v pixelech; kladná hodnota dolů záporná nahoru (default 0)
// $query['cw'] - šířka zobrazovaného výřezu v pixelech
// $query['ch'] - výška zobrazovaného výřezu v pixelech
// $query['resize'] - přeškálování výřezu; 0.01 < (default 1) < 3
// $query['type'] - jpeg , gif nebo png (default jpeg)

$cx = $query['cx'] ?: 0;
$cy = $query['cy'] ?: 0;

$remote_file = $urlfile;

// Vytvoření obrázku ze staženého souboru
$content = file_get_contents($remote_file);
$params = getimagesizefromstring($content);
$image = imagecreatefromstring($content);
        
function viewimage($mtype, $image) {
    header ('Content-Type: '. $mtype ) ;
    switch ($mtype) {
        case 'image/jpeg' : imagejpeg($image) ;
        break;
        case 'image/gif' : imagegif($image) ;
        break;
        case 'image/png' : imagepng($image) ;
        break;
    }
    imagedestroy($image);
}

if ( ! isset($query['cw']) ) {
        viewimage($params['mime'], $image);
        exit;
    } else {
        $width = $params[0];
        $height = $params[1];

        // Rozměry nového obrázku s posunem
        $image_p = imagecreatetruecolor($width, $height);

        // Naplácnutí posunutého obsahu na obrázek o původní velikosti
        imagecopyresampled($image_p, $image, $cx, $cy, 0, 0, $width, $height, $width, $height);

        // Výřez z posunutého obrázku
        $image_c = imagecrop( $image_p, [ 'x' => 0, 'y' => 0, 'width' => $query['cw'], 'height' => $query['ch'] ] );
        imagedestroy($image_p);
    }

if ( isset($query['resize'] ) ) {
        // Změna velikosti
        if ( $query['resize'] > 3 &&  $query['resize'] < 0.01 ) {
            die('Minimal value of the resize is 0.01 and max 3') ;
        }

        $neww = $query['cw'] * $query['resize'];
        $newh = $query['ch'] * $query['resize'];
        // Zmenšení obrázku podle nastaveného poměru
        $image_r = imagecreatetruecolor( $neww , $newh );

        imagecopyresampled($image_r, $image_c, 0, 0, 0, 0, $neww, $newh, $query['cw'], $query['ch']);
        imagedestroy($image_c);
        viewimage($params['mime'], $image_r);
        exit;
    } else {
        // Zobrazeno bez změny rozlišení
        viewimage($params['mime'], $image_c);
        exit;
    }
?>