Soutěž Root.cz

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

Když se na serveru Root.cz chystalo uvedení nové verze, byla s tím spojená soutěž. Nejzajímavější mi přišel 4. díl, jehož řešení jsem si napsal v PHP. Nejprve je samozřejmě nutné na postup řešení přijít – to je asi ta zajímavější část, takže pokud o radost z vlastního vyřešení nechcete být ochuzeni, dále nečtěte a s řešením se nejprve sami potrapte.

První úkol je relativně jednoduchý – dvojbarevný obrázek má obě barvy v paletě nastavené na stejnou hodnotu RGB, takže splývají. Když jim nastavíme různou barvu, můžeme si všimnout, že je obrázek složen z kousků stejné šířky a různé výšky. Seřazením těchto kousků podle velikosti by mohlo něco vzniknout:

<?php
$step = 30;

// rozřezání obrázku na části
$im = imagecreatefromgif("http://www.root.cz/data/soutez-4.gif");
imagecolorset($im, 1, 255, 255, 255);
imagecolorset($im, 2, 0, 0, 0);
$parts = array();
$max_y = 0;
for ($x=0; $x < imagesx($im); $x += $step) {
    for ($y=0; $y < imagesy($im); $y++) {
        if (imagecolorat($im, $x, $y) != 0) {
            $y0 = $y;
            $y++;
            while (imagecolorat($im, $x, $y) != 0 && $y < imagesy($im)) {
                $y++;
            }
            $parts[$y-$y0] = array($x, $y0);
            $max_y = max($max_y, $y-$y0);
        }
    }
}
ksort($parts);

// poskládání částí do nového obrázku
$im2 = imagecreate(30 * count($parts), $max_y);
imagepalettecopy($im2, $im);
$x = 0;
foreach ($parts as $key => $val) {
    imagecopy($im2, $im, $x, 0, $val[0], $val[1], $step, $key);
    $x += $step;
}
imagedestroy($im);
?>

Práci máme usnadněnou tím, že kousky nejsou v obrázku rozházeny náhodně, ale jsou seřazeny do pravidelných sloupců. Po zatřídění kousků do pole se zkopírují do nového obrázku, který se následně zobrazí:

<?php
// OCR :-)
header("Content-Type: image/gif");
imagegif($im2); // po přečtení obsahu obrázku zakomentovat
$url = "http://www.root.cz/data/soutez-4-wsxqaz.zip";
imagedestroy($im2);
?>

URL je jednodušší z obrázku přečíst, než si psát OCR… Z uvedené adresy stáhneme archiv, ve kterém najdeme dva soubory. Jeden soubor obsahuje liché řádky výsledného obrázku, druhý sudé, barvy jsou uložené v hexadecimálním tvaru se znaky fedcba zaměněnými za uvwxyz:

<?php
// načtení souborů v ZIPu
$filename = "soutez-4.zip";
copy($url, $filename);
$files = array();
$zip = zip_open($filename);
while ($zip_entry = zip_read($zip)) {
    zip_entry_open($zip, $zip_entry);
    $file = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
    $files[zip_entry_name($zip_entry)] = explode("\n", strtr($file, "uvwxyz", "fedcba"));
    zip_entry_close($zip_entry);
}
zip_close($zip);
unlink($filename);
?>

Práci se vzdálenými soubory knihovna ZIP nedovoluje, proto je soubor nejprve zkopírován. Do každého ze dvou prvků pole $files je uloženo pole jednotlivých řádek souborů již s opravenými kódy barev. Spojení těchto dvou polí do jednoho řetězce je tedy jednoduché:

<?php
// spojení lichých a sudých řádek
$output = "";
foreach ($files["1.txt"] as $l => $line) {
    $output .= $files["2.txt"][$l] . " ";
    $output .= "$line ";
}
?>

Nyní již zbývá řetězec jen rozdělit do jednotlivých řádek obrázku podle oddělovače  X  a výsledný obrázek vypsat:

<?php
// poskládání výsledného obrázku
$lines = explode(" X ", substr($output, 0, -1));
$im = imagecreatetruecolor(2 * substr_count(reset($lines), " ") + 1, count($lines));
$y = 0;
foreach ($lines as $line) {
    $x = 0;
    foreach (explode(" ", $line) as $color) {
        imagesetpixel($im, $x, $y, hexdec($color));
        $x++;
    }
    $y++;
}
header("Content-Type: image/png");
imagepng($im);
?>

Zdrojová data obsahují chybu, proto je obrázek vytvořen v dvojnásobné šířce, aby se špatně umístěné řádky měly kam vypsat.

Je radost v PHP takový kód psát – především díky mocným polím a také díky hotovým knihovnám – zde na práci s obrázky a se ZIP archivy.

Jakub Vrána, Řešení problému, 12.10.2005, diskuse: 0 (nové: 0)

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 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.