Aktuelle Version |
Dein Text |
Zeile 1: |
Zeile 1: |
| {{Scriptquelltextverwendung}} | | {{Scriptquelltextverwendung}} |
|
| |
| Letzte Änderungen:
| |
| * Umstellung auf "getopt" (Angabe von Optionen auf der Befehlszeile). Neue Features "Atlas" und "Einzelkarten", damit auch Erstellung von Dungeon-Karten. Damit kann man jetzt weitgehend automatisch sowas machen wie http://www.remote-island.org/101912/atlas.pdf (Quelltext: http://www.remote-island.org/101912/atlas.odt) --[[Benutzer:Count Ypsilon|Count Ypsilon]] ([[Benutzer Diskussion:Count Ypsilon|Diskussion]]) 23:24, 17. Feb. 2019 (CET)
| |
|
| |
| <pre> | | <pre> |
| <?php | | <?php |
| header('Content-Type: text/plain; charset=utf-8;'); | | header('Content-Type: text/plain; charset=utf-8;'); |
|
| |
|
| const BERGFELD = 'http://welt1.freewar.de/freewar/images/map/std.jpg';
| | // Bergfeld url |
| const ATLAS_TEMPLATE = 'atlas-vorlage.odt';
| | define("BERGFELD", 'http://welt1.freewar.de/freewar/images/map/std.jpg'); |
| const GESAMTKARTE_LORU = array(2, 2, 170, 400);
| |
| const MAPLIST = 'maplist.txt';
| |
| const MAPCACHE = './map_cache';
| |
|
| |
|
| /* ---------------------------------------------------------------------------- | | $host = 'http://www.fwwiki.de'; |
| * Der Freewar-Kartengenerator
| | $prefix = 'Karte'; // Wiki-Namespace |
| *
| |
| *
| |
| */
| |
|
| |
|
| function show_help() {
| | // pfad zu maplist.txt |
| echo <<<EOF
| | $maplist = 'maplist.txt'; |
|
| |
|
| Befehlszeilenoptionen:
| | // Pfad zur Ausgabedatei |
| | $mapfile = './Gesamtkarte (automatisch generiert).jpg'; |
|
| |
|
| --mode "gesamt": erzeugt eine Gesamtkarte für die Oberfläche
| | // pfad zu map_cache |
| "einzel": erzeugt einzelne Karten für jedes Gebiet
| | $map_cache = './map_cache'; |
| "atlas": erzeugt ein Atlas-Dokument (OpenOffice/Libre-
| |
| Office-Format); benötigt dafür eine Vorlage
| |
| --dungeons auch Dungeons mit ausgeben
| |
| --grid alle X Zeilen/Spalten eine Linie
| |
| --cellspacing Pixel Abstand zwischen Feldern
| |
| --gridlabels Gitternetz mit Koordinaten beschriften
| |
| --rotatelabels Koordinaten an X-Achse rotieren
| |
| --gebietlabel Gebiete beschriften (bei Einzel/Atlas)
| |
| --labelfont TTF-Datei für Beschriftungen
| |
| --lighten nichtbetretbare/gebietsfremde Felder aufhellen
| |
| --output Name der Ausgabedatei/des Ausgabeverzeichnisses
| |
| --bgcolor Bildhintergrund in Hex
| |
| --verbose mehr Meldungen anzeigen
| |
|
| |
|
| Bei Modus "Atlas" zusätzlich
| | # Bereich angeben. Alles ausserhalb wird ignoriert. Die Karte wird aber |
| --dpi Auflösung für die Bildausgabe (Default 140, größere Auflösung
| | # immer nur so gross, wie tatsaechlich Felder da sind, nicht so gross, |
| bringt kleinere Bilder)
| | # wie man hier angibt. |
| --pagewidth druckbare Seitenbreite in cm | | # (nicht mit 1,1 starten, sonst kriegt man den Dummyplace mit) |
| --pageheight druckbare Seitenhöhe in cm
| | $min_x = 2; |
| | $min_y = 2; |
| | $max_x = 170; # oestlicher Rand, damit Itolos und Belpharia-Inseln draussen bleiben |
| | $max_y = 400; |
| | |
| | # Hintergrundfarbe fuer Karte |
| | $bgcolor = "ffffff"; |
|
| |
|
| | # auf z.b. 5 setzen, wenn felder mit luecken gewuenscht |
| | $cellspacing = 0; |
| | |
| | # auf 1 setzen, wenn alle 5 zeilen/spalten linie gewuenscht |
| | $draw_grid = 1; |
|
| |
|
| EOF;
| | // ab hier nichts ändern ohne Kenntnisse über Funktionsweise des Skripts |
| }
| | function get_templates($template, $wiki_text) { |
| | | $pattern = '/\{\{(Vorlage:)?' . preg_quote($template, '/') . '/'; |
| | |
| // --- Einlesen der Befehlszeile ---------------------------------------------- | |
|
| |
|
| $longopts = array( | | $templates = preg_split($pattern, $wiki_text); |
| "mode:", // gesamt (Default), einzel oder atlas
| |
| "dungeons", // sollen Dungeons mit ausgegeben werden?
| |
| "verbose", // soll das Programm geschwätzig sein?
| |
| "lighten", // sollen gebietsfremde Felde aufgehellt werden?
| |
| "bgcolor:", // Kartenhintergrund in Web-Notation (Default weiss)
| |
| "grid:", // Gitternetz-Abstand (Default keins)
| |
| "help", // Hilfe anzeigen
| |
| "gridlabels", // soll das Gitternetz beschriftet sein? (Default nein)
| |
| "gebietlabel", // soll die Gebietskarte ein Label haben? (Default nein)
| |
| "labelfont:", // TTF-Datei für die Beschriftungen
| |
| "rotatelabels", // soll X-Achesen-Label 90° rotiert sein? (Default nein)
| |
| "cellspacing:", // Feld-Abstand (Default 0)
| |
| "dpi:", // dpi für Bilder im Atlas (Default 140)
| |
| "pagewidth:", // druckbare Seitenbreite (cm, Papier-Rand) im Atlas
| |
| "pageheight:", // druckbare Seitenhöhe (cm, Papier-Rand) im Atlas
| |
| "output:", // Ausgabedatei oder -Verzeichnis
| |
| ); | |
|
| |
|
| $o = getopt(NULL, $longopts, $optind);
| | return array_slice($templates, 1); |
| | |
| $o['verbose'] = array_key_exists('verbose', $o); | |
| | |
| if (array_key_exists('help', $o)) {
| |
| show_help();
| |
| exit;
| |
| } | | } |
|
| |
|
| if (!array_key_exists('mode', $o)) {
| | // cacht mapfile |
| $o['mode'] = 'gesamt';
| | function cache_mapfile($url, $map_cache) { |
| echo "Betriebsmodus \"Gesamtkarte\" automatisch gewählt. Programm mit --help\n";
| | $cache_file = "$map_cache/" . md5($url); |
| echo "aufrufen für weitere Funktionen\n";
| | if (!file_exists($cache_file)) { |
| }
| | file_put_contents($cache_file, file_get_contents($url)); |
| | |
| if ($o['mode'] != 'gesamt' && $o['mode'] != 'atlas' && $o['mode'] != 'einzel') {
| |
| echo "mode muss entweder 'atlas', 'einzel' oder 'gesamt' sein\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| if (!array_key_exists('bgcolor', $o)) {
| |
| $o['bgcolor'] = 'ffffff';
| |
| }
| |
| | |
| if (!preg_match('/^[a-f0-9]{6}$/i', $o['bgcolor'])) {
| |
| echo "bgcolor muss eine 6stellige Hexadezimalzahl sein, z.B. fafefa - nicht '".$o['bgcolor']."'\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| if (!array_key_exists('grid', $o)) {
| |
| $o['grid'] = 0;
| |
| }
| |
| | |
| if (!preg_match('/^\d\d?$/', $o['grid'])) {
| |
| echo "grid muss zwischen 0 und 99 liegen\n"; | |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| $o['gridlabels'] = array_key_exists('gridlabels', $o); | |
| if ($o['gridlabels'] && !$o['grid']) {
| |
| echo "gridlabels kann nur zusammen mit grid verwendet werden\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| $o['rotatelabels'] = array_key_exists('rotatelabels', $o);
| |
| if ($o['rotatelabels'] && !$o['gridlabels']) {
| |
| echo "rotatelabels kann nur zusammen mit gridlabels verwendet werden\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| $o['dungeons'] = array_key_exists('dungeons', $o);
| |
| | |
| $o['gebietlabel'] = array_key_exists('gebietlabel', $o);
| |
| if ($o['gebietlabel'] && $o['mode'] == 'gesamt') {
| |
| echo "--gebietlabel geht nur bei --mode atlas oder --mode einzel\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| $o['lighten'] = array_key_exists('lighten', $o);
| |
| if ($o['lighten'] && $o['mode'] == 'gesamt') {
| |
| echo "--lighten geht nur bei --mode atlas oder --mode einzel\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| if (!array_key_exists('cellspacing', $o)) $o['cellspacing'] = 0;
| |
| if (!preg_match('/^\d\d?$/', $o['cellspacing'])) {
| |
| echo "cellspacing muss zwischen 0 und 99 liegen\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| if ($o['mode'] == 'atlas') {
| |
| | |
| if (!array_key_exists('dpi', $o)) {
| |
| $o['dpi'] = 140;
| |
| }
| |
| | |
| if (!preg_match('/^\d\d\d?$/', $o['dpi'])) {
| |
| echo "dpi muss zwischen 10 und 999 liegen\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| if (!array_key_exists('pagewidth', $o)) $o['pagewidth'] = 12.85;
| |
| $o['pagewidth'] = strtr($o['pagewidth'], ",", ".");
| |
| | |
| if (!array_key_exists('pageheight', $o)) $o['pageheight'] = 19;
| |
| $o['pageheight'] = strtr($o['pageheight'], ",", ".");
| |
| | |
| if (!preg_match('/^\d\d?(\.\d+)?$/', $o['pageheight'])) { | |
| echo "pageheight muss zwischen 0 und 99.9 liegen\n"; | |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| if (!preg_match('/^\d\d?(\.\d+)?$/', $o['pagewidth'])) {
| |
| echo "pagewidth muss zwischen 0 und 99.9 liegen\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| | |
| } else {
| |
| if (array_key_exists('dpi', $o) ||
| |
| array_key_exists('pageheight', $o) ||
| |
| array_key_exists('pagewidth', $o)) {
| |
| echo "--dpi, --pageheight, --pagewidth gehen nur mit --mode atlas\n";
| |
| show_help();
| |
| exit;
| |
| } | | } |
| | |
| | return $cache_file; |
| } | | } |
|
| |
|
| if (!array_key_exists("labelfont", $o)) {
| | $parser_function = 'parse_card_article'; // Parser Funktion des Skripts |
| $o['labelfont'] = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf';
| | $api_url = "$host/api.php?format=json"; |
| }
| |
|
| |
|
| if ($o['gebietlabel'] || $o['gridlabels']) {
| | // trennzeichen für positionsschlüssel |
| if (!file_exists($o['labelfont'])) {
| | $pos_delimiter = '|'; |
| echo "Datei ".$o['labelfont']." (--labelfont) nicht gefunden\n";
| |
| show_help();
| |
| exit;
| |
| }
| |
| }
| |
|
| |
|
| if (!array_key_exists("output", $o)) {
| |
| $o['output'] = './karten';
| |
| if ($o['mode'] == 'atlas') $o['output'] = './atlas.odt';
| |
| if ($o['mode'] == 'gesamt' && !$o['dungeons']) $o['output'] = './Gesamtkarte (automatisch generiert).jpg';
| |
| }
| |
|
| |
|
| if ($optind < $argc) {
| | // Rahmen |
| echo "Ungültige Befehlszeilenoption\n";
| | $min_x_found = $max_x; |
| show_help();
| | $min_y_found = $max_y; |
| exit;
| | $max_x_found = $min_x; |
| }
| | $max_y_found = $min_y; |
| | |
| | // zusätzliche Felder, die nicht von Feld-Artikeln erfasst werden |
| | $additional_fields = []; |
|
| |
|
| // --- Einlesen der Befehlszeile beendet -------------------------------------- | | // Bergfeld cachen |
| | cache_mapfile(BERGFELD, $map_cache); |
|
| |
|
| if ($o['mode'] == 'atlas') {
| | // Karten holen |
| | $api_query_url = "$api_url&action=query&list=categorymembers". |
| | "&cmtitle=Kategorie:Karten&cmtype=page". |
| | "&cmprop=ids|sortkeyprefix|title&cmlimit=50"; |
| | $api_query_url_continue = $api_query_url; |
|
| |
|
| // Atlas benötigt eine vorbereitete OpenOffice-Datei
| | // pageids der karten |
| if (!file_exists(ATLAS_TEMPLATE)) {
| | $map_pageids = []; |
| echo "Datei ".ATLAS_TEMPLATE." wird für --mode atlas benötigt, fehlt aber.\n";
| |
| echo "Entweder eine leere OpenOffice-Datei erzeugen, die irgendwo den Text\n";
| |
| echo "ADD CONTENT HERE enthält, oder herunterladen von\n";
| |
| echo "http://www.remote-island.org/101912/atlas-vorlage.odt";
| |
| exit;
| |
| }
| |
|
| |
|
| if ($o['verbose']) echo ATLAS_TEMPLATE.' nach '.$o['output']." kopieren...\n";
| | // kategorieeinträge durchlaufen |
| copy(ATLAS_TEMPLATE, $o['output']); | | while (true) { |
| | | $json = json_decode(file_get_contents($api_query_url_continue), true); |
| $zipfile = new ZipArchive; | | |
| $res = $zipfile->open($o['output']); | | // pageids hinzufügen |
| if (!$res) {
| | $map_pageids = array_merge($map_pageids, array_filter(array_map(function ($row) { |
| echo "Fehler beim Öffnen der Datei ".$o['output']."!\n"; | | // keine ! kategorieeinträge |
| exit; | | return ($row['sortkeyprefix'][0] == '!') ? null : $row['pageid']; |
| }
| | }, $json['query']['categorymembers']))); |
| } else if ($o['mode'] != 'gesamt' || $o['dungeons']) {
| | |
| mkdir($o['output'], 0777, TRUE); | | // continue url |
| if (!is_dir($o['output'])) { | | if (isset($json['continue'])) { |
| echo "'".$o['output']."' ist kein Verzeichnis bzw. kann nicht angelegt werden!\n"; | | $api_query_url_continue = "$api_query_url&cmcontinue={$json['continue']['cmcontinue']}"; |
| exit; | | } else { |
| | break; |
| } | | } |
| } | | } |
|
| |
|
| $count = 10000; | | // karten durchlaufen |
| | $rvlimit = 10; |
|
| |
|
| | | foreach (array_chunk($map_pageids, $rvlimit) as $pageids) { |
| // ab hier nichts ändern ohne Kenntnisse über Funktionsweise des Skripts
| | $api_query_url = "$api_url&action=query&prop=revisions". |
| | | "&rvprop=content&pageids=". implode("|", $pageids); |
| // cacht mapfile | | $json = json_decode(file_get_contents($api_query_url), true); |
| function cache_mapfile($url) { | | |
| $cache_file = MAPCACHE . "/". md5($url);
| | foreach ($json['query']['pages'] as $pageid => $prop) { |
| if (!file_exists($cache_file)) {
| | $raw = $prop['revisions'][0]['*']; |
| file_put_contents($cache_file, file_get_contents($url)); | | |
| | // unbetretbare und rahmenfelder erfassen, durchlaufen und an maplist format anpassen |
| | $additional_fields = array_merge($additional_fields, array_map(function ($template_text) { |
| | preg_match("/([0-9\-]+)\|([0-9\-]+)(\|([^}\|]+))?/", $template_text, $values); |
| | |
| | if (!isset($values[1])) { |
| | return []; |
| | } |
| | |
| | return [ |
| | // array keys entsprechend format in maplist.txt |
| | 2 => $values[1], |
| | 3 => $values[2], |
| | 5 => isset($values[3]) ? $values[4] : BERGFELD |
| | ]; |
| | }, array_merge(get_templates("Karte/Unbetretbar", $raw), get_templates("Karte/Rahmenfeld", $raw)))); |
| } | | } |
|
| |
| return $cache_file;
| |
| } | | } |
|
| |
|
| // trennzeichen für positionsschlüssel | | // zusätzliche Felder geholt |
| $pos_delimiter = '|';
| | // eigentliche maplist holen und mit zusätzlichen zusammenführen |
| | | $field_rows = array_merge(array_map(function ($line) { |
| // Bergfeld cachen
| | return str_getcsv($line, ";"); |
| cache_mapfile(BERGFELD);
| | }, explode("\n", file_get_contents($maplist))), $additional_fields); |
| | |
| // maplist holen | |
| if ($o['verbose']) echo "Felder aus ".MAPLIST." holen und Bilder laden...\n";
| |
| | |
| $handle = fopen(MAPLIST, "r"); | |
| if (!$handle) {
| |
| echo "Kann Feldliste aus ".MAPLIST." nicht laden\n"; | |
| exit;
| |
| }
| |
| $field_rows = array();
| |
| while ($data = fgetcsv($handle, 1000, ";")) {
| |
| array_push($field_rows, $data);
| |
| }
| |
| fclose($handle);
| |
|
| |
|
| // felder in `position` => `url` format überführen | | // felder in `position` => `url` format überführen |
| $fields = []; | | $fields = []; |
| foreach ($field_rows as $field) { | | foreach ($field_rows as $field) { |
| $x = array_key_exists(2, $field) ? $field[2] : NULL; | | # Koordinaten-Check |
| $y = array_key_exists(3, $field) ? $field[3] : NULL;
| | if ($field[2] < $min_x || $field[2] > $max_x || $field[3] < $min_y || $field[3] > $max_y) { |
| $g = array_key_exists(0, $field) ? $field[0] : NULL;
| | continue; |
| $b = array_key_exists(1, $field) ? $field[1] : NULL;
| | } |
| | | if ($field[2] < $min_x_found) { |
| if ($o["mode"] == "gesamt") {
| | $min_x_found = $field[2] ; |
| | | } |
| // Für die Gesamtkarte werden die Felder des Kontinents als ein Gebiet | | if ($field[3] < $min_y_found) { |
| // behandelt
| | $min_y_found = $field[3]; |
| if ($x>GESAMTKARTE_LORU[0] && $y>GESAMTKARTE_LORU[1] &&
| |
| $x<GESAMTKARTE_LORU[2] && $y<GESAMTKARTE_LORU[3]) {
| |
| $g="Oberfläche";
| |
| } else {
| |
| // Dungeons (und Außenbereiche des Kontinents wie Narubia)
| |
| // nur, wenn --dungeons gesetzt ist
| |
| if (!$o['dungeons']) continue;
| |
| }
| |
| | |
| } else {
| |
| | |
| // Für Einzelkarten und Atlas kann man mit $dungeons steuern, | |
| // ob auch Dungeons ausgegeben werden sollen
| |
| if (!$o['dungeons'] && $x<2) continue;
| |
| } | | } |
| | | if ($field[2] > $max_x_found) { |
| $lim = &$gebiet_limits[$g]; | | $max_x_found = $field[2] ; |
| if (!$lim) {
| |
| $lim["minx"] = 99999; | |
| $lim["miny"] = 99999;
| |
| $lim["maxx"] = -99999;
| |
| $lim["maxy"] = -99999;
| |
| } | | } |
| | | if ($field[3] > $max_y_found) { |
| // Hier wird die Größe jedes Gebiets ermittelt; dazu berücksichtigen
| | $max_y_found = $field[3]; |
| // wir aber nur die begehbaren Teile, sonst haben Karten wie z.B.
| |
| // Düsterfrostinsel einen unnötig großen Platzbedarf. TODO, dies
| |
| // konfigurierbar machen | |
| if ($b) {
| |
| if ($x < $lim["minx"]) $lim["minx"] = $x;
| |
| if ($y < $lim["miny"]) $lim["miny"] = $y;
| |
| if ($x > $lim["maxx"]) $lim["maxx"] = $x; | |
| if ($y > $lim["maxy"]) $lim["maxy"] = $y;
| |
| } | | } |
| | | |
| // und gleich bilddatein holen | | // und gleich bilddatein holen |
| $cache_file = cache_mapfile(array_key_exists(5, $field) ? $field[5] : NULL); | | $cache_file = cache_mapfile($field[5], $map_cache); |
| | | |
| // kein Feldtitel oder `Feldtitel Pensal (brennend)` | | // kein Feldtitel oder `Feldtitel Pensal (brennend)` |
| if (!isset($g) || strpos($g, ' (brennend)') === false) { | | if (!isset($field[1]) || strpos($field[1], ' (brennend)') === false) { |
| $fields["{$x}$pos_delimiter{$y}"] = [ | | $fields["{$field[2]}$pos_delimiter{$field[3]}"] = [ |
| 'x' => $x, | | 'x' => $field[2], |
| 'y' => $y, | | 'y' => $field[3], |
| 'g' => $g,
| |
| 'begehbar' => $b,
| |
| 'file' => $cache_file | | 'file' => $cache_file |
| ]; | | ]; |
Zeile 353: |
Zeile 181: |
| 'x' => $field['x'] + $diff_x, | | 'x' => $field['x'] + $diff_x, |
| 'y' => $field['y'] + $diff_y, | | 'y' => $field['y'] + $diff_y, |
| 'file' => MAPCACHE . '/' . md5(BERGFELD) | | 'file' => "$map_cache/" . md5(BERGFELD) |
| ]; | | ]; |
| } | | } |
Zeile 362: |
Zeile 190: |
| # Groesse eines Kartenfelds feststellen | | # Groesse eines Kartenfelds feststellen |
| list($tilewidth, $tileheight) = getimagesize($cache_file); | | list($tilewidth, $tileheight) = getimagesize($cache_file); |
| if ($o['verbose']) echo "tile size: $tilewidth x $tileheight\n";
| | echo "tile size: $tilewidth x $tileheight\n"; |
| | |
| // ein weisses Kartenfeld herstellen
| |
| if ($o['lighten']) {
| |
| $aufheller = imagecreatetruecolor($tilewidth, $tileheight);
| |
| $farbe = imagecolorallocate($aufheller, 255, 255, 255);
| |
| imagefilledrectangle($aufheller, 0, 0, $tilewidth, $tileheight, $farbe);
| |
| }
| |
| | |
| if ($o["mode"] == 'atlas')
| |
| {
| |
| file_put_contents("odt/content.xml", file_get_contents("head.xml"));
| |
| $dungeons = "";
| |
| $oberflaeche = "";
| |
| }
| |
| | |
| foreach($gebiet_limits as $gebiet => $limits) {
| |
| | |
| // Bereich ermitteln
| |
| | |
| $max_x_found = $limits['maxx'] + 1;
| |
| $max_y_found = $limits['maxy'] + 1;
| |
| $min_x_found = $limits['minx'] - 1;
| |
| $min_y_found = $limits['miny'] - 1;
| |
| | |
| // Leeres Kartenbild erstellen
| |
| | |
| $mapwidth = ($max_x_found - $min_x_found + ($o['grid'] ? 3 : 1)) * $tilewidth +
| |
| ($max_x_found - $min_x_found + 2) * $o['cellspacing'];
| |
| $mapheight = ($max_y_found - $min_y_found + ($o['grid'] ? 3 : 1)) * $tileheight +
| |
| ($max_y_found - $min_y_found + 2) * $o['cellspacing'];
| |
| | |
| if ($o['verbose']) {
| |
| echo "Karte für '$gebiet': x_min: $min_x_found; x_max: $max_x_found; y_min: $min_y_found; y_max: $max_y_found; ";
| |
| echo "Bildgröße: $mapwidth x $mapheight\n";
| |
| }
| |
| | |
| $mapimage = imagecreatetruecolor($mapwidth, $mapheight);
| |
| if (!$mapimage) {
| |
| echo "Fehler bei der Erstellung des Kartenbilds für '$gebiet'\n";
| |
| continue;
| |
| }
| |
| | |
| // Hintergrundfarbe setzen
| |
| | |
| $bgarray = sscanf($o['bgcolor'], "%02X%02X%02X");
| |
| $bgindex = imagecolorallocate($mapimage, $bgarray[0], $bgarray[1], $bgarray[2]);
| |
| imagefill($mapimage, 0, 0, $bgindex);
| |
| | |
| // Gitternetz einzeichnen und ggf. beschriften
| |
| | |
| if ($o['grid']) {
| |
| for ($x = $min_x_found; $x <= $max_x_found; $x++) {
| |
| if ($x%$o['grid'] == 0) {
| |
| $mpx = ($x - $min_x_found + 1) * ($tilewidth + $o['cellspacing']) + $o['cellspacing'] + $tilewidth/2;
| |
| imageline($mapimage, $mpx, $o['rotatelabels'] ? 0 : 40, $mpx, $o['rotatelabels'] ? $mapheight : $mapheight - 40, 0);
| |
| if (!$o['gridlabels']) continue;
| |
| $t = $x;
| |
| if (strlen($t) > 4) $t=substr($t,0,2)."\n".substr($t,3);
| |
| | |
| // X-Achsen-Labels können entweder gerade stehen oder
| |
| // entlang der Achse (rotatelabels)
| |
| if ($o['rotatelabels']) {
| |
| imagettftext($mapimage, 11, 270, $mpx + 3, 5, 0, $o['labelfont'], $t);
| |
| $ar = imagettfbbox (11, 270, $o['labelfont'], $t);
| |
| imagettftext($mapimage, 11, 270, $mpx + 3, $mapheight - $ar[3] - 5, 0, $o['labelfont'], $t);
| |
| } else {
| |
| $ar = imagettfbbox (11, 0, $o['labelfont'], $t);
| |
| imagettftext($mapimage, 11, 0, $mpx + 3 - $ar[4]/2, 22 - $ar[5], 0, $o['labelfont'], $t);
| |
| imagettftext($mapimage, 11, 0, $mpx + 3 - $ar[4]/2, $mapheight + $ar[5] - 10, 0, $o['labelfont'], $t);
| |
| }
| |
| }
| |
| }
| |
| for ($y = $min_y_found; $y <= $max_y_found; $y++) {
| |
| if ($y%$o['grid'] == 0) {
| |
| $mpy = ($y - $min_y_found + 1) * ($tileheight + $o['cellspacing']) + $o['cellspacing'] + $tileheight/2;
| |
| imageline($mapimage, 0, $mpy, $mapwidth, $mpy, 0);
| |
| if (!$o['gridlabels']) continue;
| |
| $t = $y;
| |
| if (strlen($t) > 4) $t=substr($t,0,2)."\n".substr($t,3);
| |
| imagettftext($mapimage, 11, 0, 5, $mpy - 2, 0, $o['labelfont'], $t);
| |
| $ar = imagettfbbox (11, 0, $o['labelfont'], $t);
| |
| imagettftext($mapimage, 11, 0, $mapwidth - 5 - $ar[4], $mpy - 2, 0, $o['labelfont'], $t);
| |
| }
| |
| }
| |
| }
| |
| | |
| // Label für Gebiet einzeichnen; schwarze Box, darin weisse Box,
| |
| // darin Text
| |
| | |
| if ($o['gebietlabel']) {
| |
| $ar = imagettfbbox (16, 0, $o['labelfont'], $gebiet);
| |
| // FIXME die Zahlen hier sind etwas magisch durch Ausprobieren
| |
| // gewählt
| |
| imagefilledrectangle($mapimage, $mapwidth - $ar[4] - 55,
| |
| $mapheight + $ar[7] - 26, $mapwidth-51, $mapheight-21, 0);
| |
| imagefilledrectangle($mapimage, $mapwidth - $ar[4] - 54,
| |
| $mapheight + $ar[7] - 25, $mapwidth-52, $mapheight-22, $bgindex);
| |
| imagettftext($mapimage, 16, 0, $mapwidth - $ar[4] - 52,
| |
| $mapheight + $ar[7] - 7, 0, $o['labelfont'], $gebiet);
| |
| }
| |
| | |
| // Feldbilder an die richtige Stelle im Gebiet einzeichnen.
| |
| // Diese Schleife geht alle Felder durch, die im Rechteck liegen, das
| |
| // das Gebiet umgibt.
| |
| foreach ($fields as $key => $data) {
| |
|
| |
|
| // weiter, wenn das Feld ausserhalb ist
| | # Leeres Kartenbild erstellen |
| if ($data['x'] < $min_x_found) continue;
| | $mapwidth = ($max_x_found - $min_x_found + 3) * $tilewidth + |
| if ($data['x'] > $max_x_found) continue;
| | ($max_x_found - $min_x_found + 2) * $cellspacing; |
| if ($data['y'] < $min_y_found) continue;
| | $mapheight = ($max_y_found - $min_y_found + 3) * $tileheight + |
| if ($data['y'] > $max_y_found) continue;
| | ($max_y_found - $min_y_found + 2) * $cellspacing; |
| | $mapimage = imagecreatetruecolor($mapwidth, $mapheight); |
| | echo "x_min: $min_x_found; x_max: $max_x_found; y_min: $min_y_found; y_max: $max_y_found;"; |
| | echo "map size: $mapwidth x $mapheight\n"; |
|
| |
|
| // Feld kopieren
| | // hintergrundfarbe |
| $offset = ($o['grid']) ? 1 : 0;
| | imagefill($mapimage, 0, 0, imagecolorallocate($mapimage, hexdec(substr($bgcolor, 0, 2)), |
| imagecopy($mapimage,
| | hexdec(substr($bgcolor, 2, 2)), |
| imagecreatefromjpeg($data['file']),
| | hexdec(substr($bgcolor, 4, 2)))); |
| ($data['x'] - $min_x_found + $offset) *
| |
| ($tilewidth + $o['cellspacing']) + $o['cellspacing'],
| |
| ($data['y'] - $min_y_found + $offset) *
| |
| ($tileheight + $o['cellspacing']) + $o['cellspacing'],
| |
| 0, 0,
| |
| $tilewidth, $tileheight);
| |
|
| |
|
| // Feld aufhellen, wenn es nicht zum Gebiet gehört
| | // Gitter malen, wenn angefordert |
| if ($o['lighten'] && (!array_key_exists('begehbar', $data) || !$data['begehbar'] || $gebiet != $data['g'])) {
| | if ($draw_grid) { |
| imagecopymerge($mapimage,
| | for ($x = $min_x_found; $x <= $max_x_found; $x++) { |
| $aufheller,
| | if ($x%5 == 0) { |
| ($data['x'] - $min_x_found + $offset) *
| | $mpx = ($x - $min_x_found + 1) * ($tilewidth + $cellspacing) + $cellspacing + $tilewidth/2; |
| ($tilewidth + $o['cellspacing']) + $o['cellspacing'],
| | imageline($mapimage, $mpx, 0, $mpx, $mapheight, 0); |
| ($data['y'] - $min_y_found + $offset) *
| |
| ($tileheight + $o['cellspacing']) + $o['cellspacing'],
| |
| 0, 0,
| |
| $tilewidth, $tileheight,
| |
| 50);
| |
| } | | } |
|
| |
| } | | } |
| | | for ($y = $min_y_found; $y <= $max_y_found; $y++) { |
| // Ausgabe des Bildes für ein Gebiet. Im Gesamtkartenmodus gibt es nur
| | if ($y%5 == 0) { |
| // ein Gebiet, also auch nur eine Ausgabe; in den anderen Modi passiert
| | $mpy = ($y - $min_y_found + 1) * ($tileheight + $cellspacing) + $cellspacing + $tileheight/2; |
| // das hier öfter.
| | imageline($mapimage, 0, $mpy, $mapwidth, $mpy, 0); |
| | |
| if ($o["mode"] == 'atlas') { | |
| | |
| // Für die Atlas-Ausgabe werden Bilder, die nicht auf die Seite
| |
| // passen, eventuell gedreht oder zweigeteilt oder beides. Mehr
| |
| // ist aber nicht drin - wenn das Bild auch gedreht und zweigeteilt
| |
| // nicht passt, fliegt es raus.
| |
| | |
| $px_per_cm = $o['dpi'] / 2.54;
| |
| | |
| // Bildgröße in cm
| |
| $w = $mapwidth / $px_per_cm;
| |
| $h = $mapheight / $px_per_cm;
| |
| | |
| // Bild-Pixel-Spalte, an der wir durchschneiden, wenn nötig
| |
| // (wird gerundet auf ganze Felder, damit wir nicht mitten in
| |
| // einem Feld schneiden)
| |
| $cutoff = floor($o['pagewidth'] * $px_per_cm / ($tilewidth + $o['cellspacing']))
| |
| * ($tilewidth + $o['cellspacing']) - $o['cellspacing']/2 + 2;
| |
| | |
| // Leeres Array initialisieren; eventuell haben wir mehr als
| |
| // ein Ausgabebild
| |
| $images = array();
| |
| | |
| if ($w <= $o['pagewidth'] && $h <= $o['pageheight']) { | |
| | |
| // alles super, Bild passt auf Seite | |
| array_push($images, $mapimage);
| |
| | |
| } elseif ($h <= $o['pagewidth'] && $w <= $o['pageheight']) {
| |
| | |
| // Bild passt, wenn wir es drehen
| |
| array_push($images, imagerotate($mapimage, 90, $bgindex));
| |
| imagedestroy($mapimage);
| |
| | |
| } elseif ($w <= 2* $o['pagewidth'] && $h <= $o['pageheight']) {
| |
| | |
| // Bild passt, wenn wir es durchschneiden - also schneiden
| |
| // und zwei Teile in Ausgabe-Array stecken
| |
| // TODO: Formel 2*pagewidth nicht ganz korrekt, da cutoff
| |
| // bedeutet, dass wir die Seite nicht 100% ausnutzen
| |
| array_push($images, imagecrop($mapimage,
| |
| [ 'x' => 0, 'y' => 0, 'height' => $mapheight, 'width' => $cutoff ]));
| |
| array_push($images, imagecrop($mapimage,
| |
| [ 'x' => $cutoff, 'y' => 0, 'height' => $mapheight,
| |
| 'width' => $mapwidth - $cutoff]));
| |
| imagedestroy($mapimage);
| |
| | |
| } elseif ($w <= $o['pageheight'] && $h <= 2 * $o['pagewidth']) {
| |
| | |
| // Bild passt rotiert und geschnitten
| |
| $m = imagerotate($mapimage, 90, $bgindex);
| |
| imagedestroy($mapimage); | |
| $mapimage = $m;
| |
| $temp = $w; $w = $h; $h = $temp;
| |
| array_push($images, imagecrop($m, [ 'x' => 0, 'y' => 0,
| |
| 'height' => $mapwidth, 'width' => $cutoff ]));
| |
| array_push($images, imagecrop($m, [ 'x' => $cutoff, 'y' => 0,
| |
| 'height' => $mapwidth, 'width' => $mapheight - $cutoff]));
| |
| imagedestroy($m);
| |
| | |
| } else {
| |
| | |
| echo "Bild für '$gebiet' zu groß. Wähle höhere DPI oder größeres Papier\n";
| |
| | |
| }
| |
| | |
| // Wir führen zwei Ausgabedokumente, eins mit den oberirdischen
| |
| // Gebieten und eins mit den Dungeons:
| |
| if ($min_x_found < 0) {
| |
| $xml = & $dungeons;
| |
| } else {
| |
| $xml = & $oberflaeche;
| |
| } | | } |
|
| |
| // OpenOffice-XML an das passende Dokument anfügen
| |
| $xml .= '<text:h text:style-name="Heading_20_2" text:outline-level="2">'.
| |
| $gebiet."</text:h>";
| |
| foreach ($images as $image) {
| |
| $count++;
| |
| // TODO: Dieser Dateiname muss eigentlich eine Prüfsumme des Inhalts
| |
| // sein. Ist er es nicht, meldet LibreOffice immer ein "defektes
| |
| // Dokument", bietet aber eine Reparatur an.
| |
| ob_start();
| |
| imagepng($image);
| |
| $imagestring = ob_get_clean();
| |
| $imagename = sprintf("Pictures/10000000%08X%08XDEADBEEF%08X.png",
| |
| imagesx($image), imagesy($image), $count);
| |
| $zipfile->addFromString($imagename, $imagestring);
| |
| $h = imagesy($image) / $px_per_cm;
| |
| $w = imagesx($image) / $px_per_cm;
| |
| $xml .= <<<EOF
| |
| <text:p text:style-name="P1">
| |
| <draw:frame draw:style-name="fr1" draw:name="Image$count" text:anchor-type="as-char" svg:width="${w}cm" svg:height="${h}cm" draw:z-index="0">
| |
| <draw:image xlink:href="$imagename" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" loext:mime-type="image/png"/>
| |
| </draw:frame>
| |
| </text:p>
| |
| EOF;
| |
| imagedestroy($image);
| |
| }
| |
|
| |
| } elseif ($o['mode'] == 'einzel' || ($o['mode'] == 'gesamt' && $o['dungeons'])) {
| |
|
| |
| // Bei Einzelbildausgabe einfach PNG schreiben
| |
| imagepng($mapimage, $o['output']."/".$gebiet.".png");
| |
| imagedestroy($mapimage);
| |
|
| |
| } else {
| |
|
| |
| // Bei Gesamtbild traditionell JPG
| |
| // TODO was wenn ein .png als Ausgabename gewählt wurde?
| |
| imagejpeg($mapimage, $o['output']);
| |
| imagedestroy($mapimage);
| |
|
| |
| } | | } |
| } | | } |
| if ($o["mode"] == 'atlas')
| | |
| {
| | // Felder einzeichnen |
| $old_contents = $zipfile->getFromName('content.xml');
| | foreach ($fields as $key => $data) { |
| if (!$old_contents) {
| | // bild in map einfügen |
| echo ATLAS_TEMPLATE." enthält keine Datei content.xml - kein .odt-Dokument?\n";
| | imagecopy($mapimage, |
| } | | imagecreatefromjpeg($data['file']), |
| if (!preg_match('/(.*)<text:p[^<]*<text:span[^<]*ADD_CONTENT_HERE[^<]*<\/text:span>[^<]*<\/text:p>(.*)/', $old_contents, $matches)) { | | ($data['x'] - $min_x_found + 1) * ($tilewidth + $cellspacing) + $cellspacing, |
| if (!preg_match('/(.*)<text:p[^<]*ADD CONTENT HERE[^<]*<\/text:p>(.*)/', $old_contents, $matches)) {
| | ($data['y'] - $min_y_found + 1) * ($tileheight + $cellspacing) + $cellspacing, |
| echo "Die contents.xml im Atlas-Template entspricht nicht der erwarteten Form.\n";
| | 0, 0, |
| echo $old_contents;
| | $tilewidth, $tileheight); |
| exit;
| |
| }
| |
| }
| |
| $contents = $matches[1] . $oberflaeche . $dungeons . $matches[2];
| |
| $zipfile->addFromString('content.xml', $contents);
| |
| $zipfile->close();
| |
| echo "Atlas erstellt. Die fertige Datei muss nun im OpenOffice/LibreOffice\n";
| |
| echo "geöffnet und \"repariert\" werden.\n";
| |
| } | | } |
|
| |
|
| | // ausgabe |
| | imagejpeg($mapimage, $mapfile); |
| | imagedestroy($mapimage); |
| </pre> | | </pre> |