Durch das Photoshopgewinnspiel auf dem Photoshop Weblog inspiriert möchte ich an dieser Stelle einmal kundtun, warum ich Photoshop liebe:

Kurz und knapp kann man sagen: Das Schnellauswahlwerkzeug und die Automatisierung von Arbeitsabläufen. Für den Bier-Index muss ich oft Fotos freistellen, was generell eine nicht besonders schwere, aber zeitintensive Arbeit ist. Danach werden die Fotos zugeschnitten und skaliert, um ins einheitliche Bild zu passen. Doch mit Photoshop ist die Welt so schön einfach:

Alternativ zum Zauberstab-Auswahlwerkzeug gibt es für mich das wohl beste Feature Photoshops, das Schnellauswahlwerkzeug:

Mit dem Schnellauswahlwerkzeug kann man eine Auswahl schnell mit einem runden Pinsel malen. Durch das Malen (sprich Ziehen) über das Bild erweitert sich die Auswahl und orientiert sich dabei den definierten Kanten. Das ist nicht nur praktikabel zum Freistellen, sondern auch zum Kolorieren von Handgezeichnetem mit offenen Pfaden.

Wenn man sich dann die Arbeit mit dem Werkzeug leicht gemacht hat, müsste man eigentlich beginnen jedes einzelne Bild zu beschneiden und zu verkleinern, wenn es da nicht die tolle Automatierung gäbe. Knapp zusammengefasst zeichnet man einen Arbeitsablauf auf und kann diesen auf jedes Bild anwenden. Zwar ist ein wenig Fummelei von Nöten, wenn man seine ersten Schritte mit diesem Funktionsbündel macht, aber die Kniffe hat man schnell raus.

Ich hatte das Problem bei einem meiner Projekte, dass URLs beim Umschreiben einen Fehler ins Errorlog schrieben, obwohl das Umschreiben an sich funktionierte:

[...] [error] [client 1.2.3.4] File does not exist: www/brauereien
[...] [error] [client 1.2.3.4] File does not exist: www/biere

Mein Problem, ich wollte lediglich von

http://www.bier-index.de/biere auf
http://www.bier-index.de/biere/

umschreiben und natürlich existieren die Ordner im Filesystem mal wieder nicht.

Lange Rede, kurzer Sinn... Hier die adäquate Lösung:

<IfModule mod_rewrite.c>

RewriteEngine On
AcceptPathInfo Off

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*).html
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://www.bier-index.de/$1/ [L,R=301]

</IfModule>

Das Wichtigste befindet sich zwischen RewriteBase und selbiger Rule, aber der Vollständigkeit halber einmal komplett.

Damit man endlich mal eine gute Übersicht über Webfarben und deren Gegenfarben erhält, habe ich eine neue Seite eingerichtet, die alle schicken Farben für's Web auflistet... und zwar mit Hex-Werte, Namen und RGB-Farbwert.

Hier geht es zur Übersicht der Webfarben

Bei vielen Webseiten machen die Javascriptdateien einen Großteil der geladenene Daten aus. Besonders über ist dies, bedenkt man, dass Javascriptdateien vom Browser (im Gegensatz zu HTML, Bildern und CSS) einzeln nacheinander geladen werden. Dies verzögert die Ladezeit der Seite.

Deswegen sollte man sein fertig gedebugtes JS final komprimieren. Dies spart Serverressourcen und kommt dem Benutzer zu Gute. Dafür einfach auf der Linux-Kommandozeile folgenden Befehl ausführen:

java -jar /path/to/yuicompressor-x.x.x/build/yuicompressor-x.x.x.jar /path/to/htdocs/js/search.js -o /path/to/htdocs/js/search-mini.js

Die aktuelle yuicompressor-Bibliothek solltet Ihr unter www.julienlecomte.net/yuicompressor/ finden.

Manchmal kommt der Moment im Leben, wo man sich mal wieder fragt: Warum geht denn das nicht? Genau solch ein Moment kam mir als ich gezwungen war, mein komplettes Repository zu sichern, ich jedoch nur die Fehlermeldung von svnadmin bekam, dass es als Quelle keine URL akzeptiert (sondern nur lokale Pfade à la svnadmin dump pfad/zum/repository > repo.dump) und ich nur einen Billighoster ohne SSH-Zugriff hatte.

Die Lösung des Problems ist einfach, wenn man sie einmal gefunden hat: Hole Dir Dein Remoterepository ins lokale Dateisystem. Das Zauberwort lautet svk. (Insofern svk noch nicht installiert ist, tut diese für Eure Linuxdistribution.)

Kurz und knapp einmal hier die Reihenfolge der Befehle:

svk ls http://svn.example.com/repo
svnadmin dump -r2:HEAD ~/.svk/local > subversion.dump

Svk ls lädt das Remoterepository ins Dateisystem ein. Dabei fragt es unzählige Fragen, in meinem Fall genügte simples Bestätigen und Nutzen der Defaults. Beim dumpen muss man die 1. Revision auslassen, da diese nur SVK Metadaten enthält.

Das so gewonnene Dumpfile kann dann wie gewohnt mit svnadmin load in ein beliebiges neues Ziel eingeladen werden.

20.10.2008

XHTML 1.1 Vorlage

Für alle, die mal ein XHTML-Skelett brauchen, welches die wichtigsten Elemente bereits beeinhaltet und nicht immer wieder auf Quelltext eigener Seiten zurückgreifen wollen:

< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title></title>
<link rel="stylesheet" type="text/css" href="" />
<link rel="stylesheet" type="text/css" href="" media="print" />
<link rel="alternate" type="application/rss+xml" title="" href="" />
<link rel="alternate" type="application/atom+xml" title="" href="" />
    <script type="text/javascript" src=""></script>
  </head>
  <body>
<h1></h1>
 
  </body>
</html>

Eine tolle Neuerung erwartet uns mit dem Firefox 3.1. Mit diesem wird es möglich sein, die Geo-Position des Benutzers mittels Javascript auszulesen. Dabei steht es dem Nutzer frei, wieviel er von seiner Position preisgeben möchte: exakte Position, Nachbarschaft, Stadt oder gar nichts.

Das Ganze sieht dann wie folgt aus:


Diese Seite gibt es weiter unten.

Die Implementation in Javascript ist denkbar einfach und kann beispielsweise so aussehen:

  1. function showMap(position)
  2. {
  3. var ll = position.longitude + " " + position.latitude;
  4. document.getElementById("geoinfo").innerHTML = ll;
  5. }
  6.  
  7. navigator.geolocation.getCurrentPosition(showMap);

Die Spezifikation stammt hierbei vom W3-Konsortium und steht in einer Vorabversion unter dev.w3.org/geo/api/spec-source.html zur Verfügung.
Das passende Geode-Plugin für den Firefox 3.x gibt es auf den Seiten von Mozilla.

Probiert es doch einfach mal aus: Firefox 3.x Geode-Testseite

Hier einmal außer der Reihe ein paar ASCII-Art-Schweine, variable Beinchen, Schwänzchen und Äuglein.

      _____
  ^..^     \9
  (oo)_____/
     WW  WW
      _____
  ^..^     \9
  (oo)_____/
     ""  ""
      ______
  ^..^      \9
  (oo)______/
     ""   ""
      ____
  ^..^    \9
  (oo)____/
     "" ""
      _____
  ^..^     \ß
  (oo)_____/
     ""  ""
       _____
  ^...^     \9
  (ooo)_____/
      ""  ""
      _____
  ^>< ^     \9
  (oo)_____/<<<
     ""  ""
      _____
  ^@@^     \9
  (oo)_____/
     ""  ""
      _____
  ^--^     \9
  (oo)_____/
     WW  WW

Heute wollte ich einmal testen, ob ich ohne Weiteres die Geoinformationen aus Bildern auslesen kann, die ich mit meinem iPhone 3G gemacht habe... Foto gemacht und auf den Rechner gezogen.

Wie komme ich aber nun für eine weitere Verarbeitung (zum Beispiel im Web) an die Informationen? Der Schlüssel lautet "Exchangeable image information" (kurz EXIF). Als PHP-Fuzzi tippte ich einfach mal php.net/exif ein und wurde prompt fündig:

function exif_read_data($filename) : array

Leider enthielt das zurückgegebene Array keine einfach weiter zu verwendenden Koordinaten, sondern leicht verworrene Infos:

  1. [GPSLatitudeRef] => N
  2. [GPSLatitude] => Array
  3. (
  4. [0] => 52/1
  5. [1] => 3367/100
  6. [2] => 0/1
  7. )
  8.  
  9. [GPSLongitudeRef] => E
  10. [GPSLongitude] => Array
  11. (
  12. [0] => 13/1
  13. [1] => 2460/100
  14. [2] => 0/1
  15. )

Um diese Infos in Dezimalwerte zu überführen, kann man folgende Funktion nutzen:

  1. function exifGeoCoordinateToDecimal($reference, array $coordinate)
  2. {
  3. list($a,$b) = explode("/", $coordinate[0]);
  4. list($c,$d) = explode("/", $coordinate[1]);
  5. list($e,$f) = explode("/", $coordinate[2]);
  6. $prefix = $reference == 'S' || $reference == 'W' ? -1 : 1;
  7.  
  8. $a = $b > 0 ? $a / $b : $a;
  9. $c = $d > 0 ? $c / $d : $c;
  10. $e = $f > 0 ? $e / $f : $e;
  11.  
  12. return $prefix * round(($a + ($c * 60 + $e) / 3600), 6);
  13. }

Und 1-fix-3 wird aus "52/1, 3367/100, 0/1 N" ein normaler Wert: 52.561167. Wem das nicht genug ist, hier eine fertige Variante zum Kopieren: geopoint.php

  1. /**
  2.  * @author Florian Sternke, www.bananenhand.de/blog/
  3.  * @version 1.0.0.0
  4.  */
  5. class GeoPoint
  6. {
  7. /**
  8.   * Longitude
  9.   *
  10.   * @var double
  11.   */
  12. protected $dblLongitude = 0.0;
  13. /**
  14.   * Latitude
  15.   *
  16.   * @var double
  17.   */
  18. protected $dblLatitude = 0.0;
  19.  
  20. /**
  21.   * Initialize an instance of GeoPoint
  22.   *
  23.   * @param double $dblLon Longitude
  24.   * @param double $dblLat Latitude
  25.   */
  26. public function __construct($dblLon, $dblLat)
  27. {
  28. // Option: check against a regexp to filter crap like 180.1
  29. $this->dblLongitude = (double)$dblLon;
  30. $this->dblLatitude = (double)$dblLat;
  31. }
  32.  
  33. /**
  34.   * Output the point as string (lon,lat)
  35.   *
  36.   * Some strange people (like Google) display coordinates like
  37.   * y,x instead of the logical x,y-way (see cartesian coordinate
  38.   * system). If you prefer the first way, feel free to switch both...
  39.   *
  40.   * @return string
  41.   */
  42. public function __toString()
  43. {
  44. return "({$this->dblLongitude},{$this->dblLatitude})";
  45. }
  46.  
  47. /**
  48.   * Returns the latitude of the geo coord
  49.   *
  50.   * @return double
  51.   */
  52. public function getLatitude()
  53. {
  54. return $this->dblLatitude;
  55. }
  56.  
  57. /**
  58.   * Returns the longitude of the geo coord
  59.   *
  60.   * @return double
  61.   */
  62. public function getLongitude()
  63. {
  64. return $this->dblLongitude;
  65. }
  66.  
  67. /**
  68.   * Transforms the EXIF geo cood array into a decimal format
  69.   *
  70.   * Array
  71.   * (
  72.   * [0] => 52/1
  73.   * [1] => 3367/100
  74.   * [2] => 0/1
  75.   * )
  76.   *
  77.   * to 52.561167
  78.   *
  79.   * @param string $reference N, E, W or S
  80.   * @param array $coordinate Coordinate
  81.   */
  82. protected static function exifGeoCoordinateToDecimal($reference, array $coordinate)
  83. {
  84. list($a,$b) = explode("/", $coordinate[0]);
  85. list($c,$d) = explode("/", $coordinate[1]);
  86. list($e,$f) = explode("/", $coordinate[2]);
  87. $prefix = $reference == 'S' || $reference == 'W' ? -1 : 1;
  88.  
  89. $a = $b > 0 ? $a / $b : $a;
  90. $c = $d > 0 ? $c / $d : $c;
  91. $e = $f > 0 ? $e / $f : $e;
  92.  
  93. return $prefix * round(($a + ($c * 60 + $e) / 3600), 6);
  94. }
  95.  
  96. /**
  97.   * Reads an image file and returns the extracted geo information
  98.   *
  99.   * Reads an image file, transforms the exif geo information into
  100.   * a reusable geo point object
  101.   *
  102.   * @param string $strFilename File name
  103.   * @return GeoPoint
  104.   * @throws UnexpectedValueException, Exception
  105.   */
  106. public static function constructFromImageFile($strFilename)
  107. {
  108. if (file_exists($strFilename))
  109. {
  110. $arrInfos = exif_read_data($strFilename, "EXIF");
  111.  
  112. if (is_array($arrInfos["GPSLatitude"]) && is_array($arrInfos["GPSLongitude"]))
  113. {
  114. $dblLat = self::exifGeoCoordinateToDecimal($arrInfos["GPSLatitudeRef"], $arrInfos["GPSLatitude"]);
  115. $dblLon = self::exifGeoCoordinateToDecimal($arrInfos["GPSLongitudeRef"], $arrInfos["GPSLongitude"]);
  116.  
  117. return new self($dblLon, $dblLat);
  118. }
  119. else throw new UnexpectedValueException("Exchangeable image information (EXIF) without GPS data");
  120. }
  121. else throw new Exception("File not found");
  122. }
  123. }
  124.  
  125. echo GeoPoint::constructFromImageFile("img_0013.jpg");

Was ist das nur für ein Gerät - dieses iPhone 3G? Man sollte nicht immer über Microsoft meckern, sondern auch mal den Apfelmenschen die Standards um die Ohren hauen.

Ich wunderte mich schon stark, als ich beim Browsen auf einmal 11 Fehler von der iPhone Safari Entwicklerkonsole gemeldet bekam. Schließlich handelte es sich um eines meiner Projekte, welches ich auf Bedacht auf Standards entwickelt habe. Zum Glück konnte mich ein Blick auf das fehler- und warnungsfreie Ergebnis des w3-Validators beruhigen. Leider brachte es auch die Erkenntnis: XHTML 1.1 ist für diese "Konsole" ein absolutes Fremdwort.

Zum Glück stürzt der Safari so konseqent ab, dass man sich darüber kaum ärgern kann. So knallt es bei diversen Autocervollständigungen, wenn man es sich erlaubt, bei Tippfehlern Backspace zu drücken.

Mal sehen, ob sich die Stabilität mit Firmwareupdates verbessert... Stand 2.0.2

Kategorien