A clock made with QR codes

25. April 2012 Keine Kommentare

While discussing funny widgets for Pebbles with my colleagues, we came up with a clock face made of a qr code.

And now there’s the online version of it: qr-clock.com

Have fun!

Kategoriencommon Tags:

Creating KML Image Overlay from GeoTIFF or tfw file

9. April 2012 Kommentare ausgeschaltet

As stated in my previous post my wife came around with a large map from work.

After compressing the image we wanted to visualize the map within Google Earth. I was quite surprised to see, that there is no small, common tool for that, so I sat down and wrote some (php) code, which I would like to share with you. (Be warned: all the scripts only work for UTM.)

This is, what we will have in the end:

    $image = "~/Desktop/geo-image-overlay.tif";
    $geoData = getGeoTIFF($image);
    $kml = geoTiffToKML($exifData, array("title" => "GeoTIFF", "imgFile" => "~/Desktop/geo-image-overlay.tif"));
    print $kml;

 

<!--?xml version="1.0" encoding="UTF-8"?-->

GeoTIFF

    ~/Desktop/geo-image-overlay.tif

    51.5724
    51.2639
    7.1835
    6.9287

The KML-code can be copied an pasted into Google Earth.

First of all, the geographic reference must be obtained either from the image’s EXIF-Data or from the separate WorldFile, which, by convention has the same name as the original image but it’s own extension (tfw for tif images, jpw for jpg).

The easy way: use GeoTIFF information and read it with exiftool by Phil Harvey.

define("EXIFTOOL_BIN", "/usr/bin/env exiftool");
function getGeoTIFF($file) {
    $data = array();
    $cmd = sprintf(EXIFTOOL_BIN." -GeoTIFF:* -EXIF:* -json '%s'", $file);
    exec($cmd, $data, $val);
    if ($val == 0) {
        $geo = json_decode(implode("\n", $data), true);
        return $geo[0];
    } else {
        return array();
    }
}

It’s a little strange, but part of the relevant “GeoTIFF” information is stored in an images “EXIF” data.

If you don’t use exiftool but if you have a WorldFile for your image, you might as well use zthe following function:

define("UTM_DEFAULT_ZONE", 32);

function tfw2GeoTIFF($file, $zone=UTM_DEFAULT_ZONE) {
    $tfwPath = substr($file, 0, strrpos($file, ".")).".tfw";
    $tifPath = substr($file, 0, strrpos($file, ".")).".tif";

    $tfw = file($tfwPath);
    list($w, $h) = getimagesize($tifPath, $info);

    $data = array();
    $data['SourceFile'] = $tifPath;
    $data['Projection'] = "UTM zone ".$zone;
    $data['ModelTiePoint'] = sprintf("%f %f 0 %f %f 0", $tfw[1], $tfw[2], $tfw[4] + (0), $tfw[5]);
    $data['PixelScale'] = sprintf("%f %f 0", $tfw[0], $tfw[3]);
    $data['ImageHeight'] = $h;
    $data['ImageWidth'] = $w;

    return $data;
}

The main problem is, that the WorldFile doesn’t contain any information about the reference system and units used within the file – you just have to know it. Who on earth defines such a “format”?
I just assumed to get UTM geo information and you have to assume the right zone.
For convenience the function uses the same attribute names as the GeoTIFF spec.

As said, I just assumed UTM data. As KML files have to contain coordinates as WGS84 I searched for a conversion script which I found on stack overflow.
Here is the PHP adaption:

function utm2wgs84($utmZone,$east,$north) {
  // This is the lambda knot value in the reference
  $LngOrigin = deg2rad($utmZone * 6 - 183);

  // The following set of class constants define characteristics of the
  // ellipsoid, as defined my the WGS84 datum.  These values need to be
  // changed if a different dataum is used.

  $FalseNorth = 0.;   // South or North?
  //if (lat < 0.) FalseNorth = 10000000.  // South or North?   //else          FalseNorth = 0.   $Ecc = 0.081819190842622;       // Eccentricity   $EccSq = $Ecc * $Ecc;   $Ecc2Sq = $EccSq / (1. - $EccSq);   $Ecc2 = sqrt($Ecc2Sq);      // Secondary eccentricity   $E1 = ( 1 - sqrt(1-$EccSq) ) / ( 1 + sqrt(1-$EccSq) );   $E12 = $E1 * $E1;   $E13 = $E12 * $E1;   $E14 = $E13 * $E1;   $SemiMajor = 6378137.0;         // Ellipsoidal semi-major axis (Meters)   $FalseEast = 500000.0;          // UTM East bias (Meters)   $ScaleFactor = 0.9996;          // Scale at natural origin   // Calculate the Cassini projection parameters   $M1 = ($north - $FalseNorth) / $ScaleFactor;   $Mu1 = $M1 / ( $SemiMajor * (1 - $EccSq/4.0 - 3.0*$EccSq*$EccSq/64.0 -     5.0*$EccSq*$EccSq*$EccSq/256.0) );   $Phi1 = $Mu1 + (3.0*$E1/2.0 - 27.0*$E13/32.0) * sin(2.0*$Mu1)     + (21.0*$E12/16.0 - 55.0*$E14/32.0)           * sin(4.0*$Mu1)     + (151.0*$E13/96.0)                          * sin(6.0*$Mu1)     + (1097.0*$E14/512.0)                        * sin(8.0*$Mu1);   $sin2phi1 = sin($Phi1) * sin($Phi1);   $Rho1 = ($SemiMajor * (1.0-$EccSq) ) / pow(1.0-$EccSq*$sin2phi1,1.5);   $Nu1 = $SemiMajor / sqrt(1.0-$EccSq*$sin2phi1);   // Compute parameters as defined in the POSC specification.  T, C and D   $T1 = tan($Phi1) * tan($Phi1);   $T12 = $T1 * $T1;   $C1 = $Ecc2Sq * cos($Phi1) * cos($Phi1);   $C12 = $C1 * $C1;   $D  = ($east - $FalseEast) / ($ScaleFactor * $Nu1);   $D2 = $D *  $D;   $D3 = $D2 * $D;   $D4 = $D3 * $D;   $D5 = $D4 * $D;   $D6 = $D5 * $D;   // Compute the Latitude and Longitude and convert to degrees   $lat = $Phi1 - $Nu1*tan($Phi1)/$Rho1 *     ( $D2/2.0 - (5.0 + 3.0*$T1 + 10.0*$C1 - 4.0*$C12 - 9.0*$Ecc2Sq)*$D4/24.0      + (61.0 + 90.0*$T1 + 298.257223563*$C1 + 45.0*$T12 - 252.0*$Ecc2Sq - 3.0*$C12)*$D6/720.0 );   $lat = rad2deg($lat);   $lon = $LngOrigin +     ( $D - (1.0 + 2.0*$T1 + $C1)*$D3/6.0       + (5.0 - 2.0*$C1 + 28.0*$T1 - 3.0*$C12 + 8.0*$Ecc2Sq + 24.0*$T12)*$D5/120.0) / cos($Phi1);   $lon = rad2deg($lon);   // Returns a PC_LatLon object   return array("lat" => $lat, "lon" => $lon);
}

And finally here comes the main function to produce the KML.
(Sorry for the lame tempting mechanism…)

define("KML_TEMPLATE", '<!--?xml version="1.0" encoding="UTF-8"?-->

%s

    %s

    %f
    %f
    %f
    %f

');

function geoTiffToKML($geoTiff, $options = array()) {
    $scale = isset($options['imgScale'])?1/$options['imgScale']:1;
    $file = isset($options['imgFile'])?$options['imgFile']:$geoTiff['SourceFile'];
    $title = isset($options['title'])?$options['title']:"No Name";

    // calculate n, s, w, e

    // projection analysis
    if (substr($geoTiff['Projection'], 0, 8) == "UTM zone") {
        $zone = intval(substr($geoTiff['Projection'], 8));

        list($rot1, $rot2, $u1, $eUTM, $nUTM, $u2) = explode(" ", trim($geoTiff['ModelTiePoint']));
        list($scaleNS, $scaleWE, $u) = explode(" ", trim($geoTiff['PixelScale']));

        $iw = $geoTiff['ImageWidth'];
        $ih = $geoTiff['ImageHeight'];

        $wUTM = abs($scale * $scaleWE * $iw) + $eUTM;
        $sUTM = $nUTM - abs($scale * $scaleNS * $ih);

        $ne = utm2wgs84($zone,$eUTM,$nUTM);
        $n = $ne['lat'];
        $e = $ne['lon'];
        $sw = utm2wgs84($zone,$wUTM,$sUTM);
        $s = $sw['lat'];
        $w = $sw['lon'];

        return sprintf(KML_TEMPLATE, $title, $file, max($n, $s), min($n, $s), max($e, $w), min($e, $w));

    } else {
        die('No support for other projections than UTM');
    }
}
Kategoriencommon Tags:

Converting/scaling large TIFF images from a GIS

9. April 2012 Kommentare ausgeschaltet

My wife works as in a land surveying office. This weekend she brought a compressed TIFF image, which was a rasterized version of a cities GIS data.

In compression mode, the file took about 90MB space, but as the image is 56706 px by 47255 px in 8Bit greyscale, it holds a little less than 2.5 GB of information.

There was no chance opening it in Photoshop, nor was ImageMagick able to create a scaled version.

Finally vips (VIPS – VipsWiki) did the job:

vips im_affinei_all input.tif output.tif vsqbs 0.4 0 0 0.4 0 0

Vips offers different interpolators: nearest, bilinear, bicubic, lbb, nohalo, vsqbs; the latest worked best for our original material.

Kategoriencommon Tags:

DropBox Gallery Demo

15. Juli 2011 Kommentare ausgeschaltet

It’s been a while since I first mentioned my Dropbox Gallery Plugin.

Up to today I did not release it for two major reasons:

  1. You have to get your own dropbox developer key to use the plugin . That’s a barrier for most users.
  2. I did not manage to (and didn’t really try to) optimize memory consumption when the images are cached. Right now you have to reload the page several times, until all images are cached. That’s a real show stopper.

After all I do know, that some people might like to use the plugin nevertheless and perhaps they might even optimize it.

Please drop me a line if you use the Dropbox gallery , enhanced it or even pushed it to github or google code.

dropbox-gallery.tar.gz

If you ant to use the plugin, make sure to configure it and to get a Dropbox API-Key.
It’s recommended to use WP-prettyPhoto along with the dropbox gallery.

Kategoriencoding Tags:

jQuery.printQr: use QR-Codes for your Print-Stylesheet with Google Charts API and jQuery

18. März 2011 Kommentare ausgeschaltet

It’s a common practice to make the URIs of links visible in a print styleheets via CSS:

@media print {
a:after {
content: " (" attr(href) ")";
}
}

Quite often you would not like to type a cryptic url by hand. Here is what you may utilize jQuery.printQr for.

Here is all you have to do:

<script src="jquery.printqr.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
    $('a').printQr();
});
</script>

These lines of code will add QR Codes for all links to the bottom of the page when you print it.
I built a little demo page.

Have fun with it, I’m interested in some feedback.

Kategoriencoding, common, printQr Tags:

Magic Earth: Unsere Welt in 3D

8. März 2011 Kommentare ausgeschaltet

Seit ein paar Tagen ist das Buch “Magic Earth: Unsere Welt in 3D” im Handel erhältlich, in dem auch eine meiner Peru-3D-Aufnahmen abgedruckt ist. Mein Beleg-Exemplar ist auch bei mir angekommen.

Ein wenig schade ist, dass die Bilder über die Doppelseite und damit über den Falz gehen.

Dafür gibt es schöne Fotos und Relief-Karten in 3D rund um den Globus.

Kategorien3D, common Tags:

Image Galleries from DropBox

3. März 2011 1 Kommentar

My previous post gave a little sneak peek to my very first wordpress plugin “Dropbox Gallery”.
Although it is not ready for press right now, I’ll tell you about its features and advantages.

No (manual) upload needed
All you do is drag a file to your Dropbox folder. You should upload an image with a reasonable filesize, so don’t use your 20 megapixel raw image. Thumbnailing is done by dropbox.

Caching, not copying
The images from your Dropbox are cached for faster access. The cache has a configurable lifetime.

Update galleries or individual pictures
On the other hand every new revision of an image is detected and updated. You altered your image in Photoshop? No need to update your image in WordPress.

Choose any folder from your Dropbox account
You may choose any folder to create an image gallery out of its contents. All images of the folder you chose are displayed in your article.

And here is what you get

Kategoriencoding, common Tags:

Connect Photo Galleries from DropBox with your WordPress Blog

22. August 2010 Kommentare ausgeschaltet

Today I wrote a tiny Plug-In to incorporate Dropbox Photo-Folders into a WordPress Blog.

Kategoriencoding, common Tags:

Ein Nachmittag im Zoo in 3D

22. August 2010 Kommentare ausgeschaltet

Der erste Beitrag im Jahr 2010 – hatte fast vergessen, dass ich ein Blog habe…

Anbei einige 3D Fotos aus dem Wuppertaler Zoo.

Kategoriencommon Tags:

Suche mit dem REST-API von pfadis.com

14. Dezember 2009 Kommentare ausgeschaltet

Fortsetzung von “API für pfadis.com

Suche mit Orts- oder Stammesnamen

Nachfolgend ein Beispiel zur Suche mit der pfadis.com API:

http://pfadis.com/app/api/rest/Unit?q= schwerte&short=true

Wie unschwer zu erkennen ist, ist “q” der Suchparameter. Mit “short=true” wird ein übersichtliches Ergebnis ohne weitere Infos zu den gefundenen Stämmen/Bezirken/etc. geliefert:

{
    "result": [
        {
            "id":507,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/507",
            "fullname":"16\/02\/04 | Stamm St. Marien (Schwerte)",
            "type":"Unit"
        }
    ],
    "page":1,
    "rpp":20,
    "total":1,
    "previous_page":null,
    "next_page":null,
    "q":"schwerte"
}

Die Suche hat genau ein Ergebnis geliefert: den Stamm St. Marien Schwerte. Gesucht werden kann nach Stammesnamen und Ortsbezeichnungen.

Suche mit geografischem Bezug

Als Suchparameter “q” eignen sich auch Ortsbezogene Angaben. So können Stämme (bzw, um genau zu sein, Stämme, denen eine Adresse zugeordnet ist) in der Nähe eines bestimmten PLZ-Bereiches gefunden werden:

http://pfadis.com/app/api/rest/Unit?q=58239&dist=10&short=true

Der Parameter “dist” gibt den Radius in Kilometern an, in dem gesucht werden soll.

{
    "result":[
        {
            "id":507,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/507",
            "fullname":"16\/02\/04 | Stamm St. Marien (Schwerte)",
            "type":"Unit",
            "distance":0
        },
        {
            "id":514,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/514",
            "fullname":"16\/01\/21 | Stamm Berghofen (Dortmund-Berghofen)",
            "type":"Unit",
            "distance":5.98
        },
        {
            "id":526,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/526",
            "fullname":"16\/01\/07 | Stamm Dortmund-Soelde (Dortmund-Soelde)",
            "type":"Unit",
            "distance":6.26
        },
        {
            "id":516,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/516",
            "fullname":"16\/01\/19 | Stamm Bonifaten 80 (Dortmund-Lichtendorf\/S\u00f6lderholz)",
            "type":"Unit",
            "distance":6.26
        },
        {
            "id":518,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/518",
            "fullname":"16\/01\/17 | Stamm St. Ewaldi (Dortmund-Aplerbeck)",
            "type":"Unit",
            "distance":6.76
        },
        {
            "id":508,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/508",
            "fullname":"16\/02\/03 | Stamm Hagen-Boele (Hagen-Boele\/Helfe)",
            "type":"Unit",
            "distance":7.3
        },
        {
            "id":509,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/509",
            "fullname":"16\/02\/02 | Stamm St. Bonifatius (Hagen-Hohenlimburg)",
            "type":"Unit",
            "distance":8.24
        },
        {
            "id":522,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/522",
            "fullname":"16\/01\/13 | Stamm Marcel Callo (Dortmund-H\u00f6rde)",
            "type":"Unit",
            "distance":8.35
        },
        {
            "id":498,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/498",
            "fullname":"16\/02\/16 | Stamm Arche (Iserlohn)",
            "type":"Unit",
            "distance":9.06
        },
        {
            "id":506,
            "url":"http:\/\/pfadis.com\/app\/api\/rest\/Unit\/506",
            "fullname":"16\/02\/06 | Stamm St. Elisabeth (Hagen)",
            "type":"Unit",
            "distance":9.59
        }
    ],
    "page":1,
    "rpp":20,
    "total":10,
    "previous_page":null,
    "next_page":null,
    "q":"58239"
}

Der Suchparameter “q” nimmt auch zwei mit Semikolon getrennte Dezimalzahlen entgegen und interpretiert diese dann als geografischen Punkt:

http://pfadis.com/app/api/rest/Unit?q=51.4;7.6&dist=10&short=true

Konkrete Codebeispiele folgen.

Viel Spaß beim Testen – Feedback ist erwünscht.

Kategorienpfadis.com Tags:
mmm