<?php //------------------------------------------------------------------------------ // map-o-net.com image drawing code // // version 1.2 - 2007-05-31 // // by Hourann Bosci <http://hourann.com> // with thanks to John Prevost and Anders Kaseorg for bug reports, // Thiadmer Riemersma for the Hilbert-drawing algorithm used here, // and Randall Munroe of xkcd.com for developing the map! // // This code may be redistributed and/or modified under the terms of // the GNU General Public License, version 2. For details, visit // http://www.gnu.org/copyleft/gpl.html // //------------------------------------------------------------------------------ // // Randall's map drawing is 672 pixels wide by (672 + big last row = 680) high // with 16 columns and 16 rows. // // Horizontal line y pixel values: 106, 144, 191, 236, 276, 318, 359, 402, // 449, 486, 527, 569, 613, 654, 700, 738, 780 // // The top left corner of the map is at pixel position (34, 104) // //------------------------------------------------------------------------------ $heightSlash8 = array( 42, 47, 46, 40, 42, 41, 43, 47, 37, 41, 42, 44, 41, 46, 38, 42 ); $widthSlash8 = 42; $widthSlash16 = $widthSlash8 / 16; // The Hilbert curve, represented by a recursive set of directions. // See hilbert() below, and http://www.compuphase.com/hilbert.htm $levelDirections = array( 'LEFT' => array( 'UP', 'RIGHT', 'LEFT', 'DOWN', 'LEFT', 'LEFT', 'DOWN' ), 'RIGHT' => array( 'DOWN', 'LEFT', 'RIGHT', 'UP', 'RIGHT', 'RIGHT', 'UP' ), 'UP' => array( 'LEFT', 'DOWN', 'UP', 'RIGHT', 'UP', 'UP', 'RIGHT' ), 'DOWN' => array( 'RIGHT', 'UP', 'DOWN', 'LEFT', 'DOWN', 'DOWN', 'LEFT' ) ); //------------------------------------------------------------------------------ // Initialisation: read in the address to plot if ( isset( $_GET['i'] ) && $_GET['i'] != "" ) { $ip = $_GET['i']; if ( !isset( $_GET['t'] ) || $_GET['t'] == "" || strlen( $_GET['t'] ) > 100 ) { // No valid label - just use the IP itself $label = $_GET['i']; } else { // The label provided is valid! $label = $_GET['t']; } } else { die( "You haven't provided any input!" ); } //------------------------------------------------------------------------------ // Break the IP into octets and check for validity $octets = explode( ".", $ip ); if ( count( $octets ) != 4 ) { die( "That IP address doesn't seem to be valid! Hit Back and try again." ); } foreach ( $octets as $number ) { if ( !ctype_digit( $number ) || $number > 255 ) { die( "That IP address doesn't seem to be valid! Hit Back and try again." ); } } //------------------------------------------------------------------------------ // Step through the Hilbert curve // Global variables (yeah, I know) will keep track of how far we've travelled // and our current position $currentValue = 0; $rowNum = 0; $posX = 34; $posY = 104; // This script is only concerned with the first two octets -- anything // smaller would be a change of less than two pixels. $targetValue = 256 * $octets[0] + $octets[1]; // Recursion starts ... now. hilbert( 256 ); //------------------------------------------------------------------------------ // JPEG-drawing time! $posX = round( $posX ); $posY = round( $posY ); $textPosX = $posX + 5; $textPosY = $posY + 11; $map = imagecreatefromjpeg( 'map_of_the_internet.jpg' ); // To give "area of certainty" / error bounds $errorColour = imagecolorallocate( $map, 218, 218, 255 ); imageellipse( $map, $posX, $posY, 20, 20, $errorColour ); // Find out how big our text is before we work with it. $sizeOfText = imageftbbox ( 9, 0, 'DejaVuSans.ttf', $label ); $rect1 = $textPosX - 1; $rect2 = $posY; $rect3 = $textPosX + $sizeOfText[2] + 1; $rect4 = $posY + 13; // Switch text position if it's too far to the right. if ( $textPosX + $sizeOfText[4] > 700 ) { $textPosX = $posX - $sizeOfText[4] - 5; $rect1 = $textPosX - 1; $rect3 = $posX - 4; } // Draw a background for the label ... $white = imagecolorallocate( $map, 255, 255, 255 ); imagefilledrectangle( $map, $rect1, $rect2, $rect3, $rect4, $white ); // ... then the text itself ... $textColour = imagecolorallocate( $map, 96, 0, 0 ); imagefttext( $map, 9, 0, $textPosX, $textPosY, $textColour, 'DejaVuSans.ttf', $label ); // ... and the location dot. $dotColour = imagecolorallocate( $map, 204, 0, 0 ); imagefilledellipse( $map, $posX, $posY, 4, 4, $dotColour ); // For "homing beacon" effect. imageellipse( $map, $posX, $posY, 8, 8, $dotColour ); // Finally, send our work off to the browser. header("Content-type: image/jpeg"); header('Content-Disposition: inline; filename="map_of_the_internet_' . $ip . '.jpg"'); imagejpeg( $map ); imagedestroy( $map ); exit; //------------------------------------------------------------------------------ // Step one unit in the given direction. // This function updates the global tracking variables so there's a // running tally of our current position, and uses that to determine // how many pixels to move at each step. function move( $direction ) { global $heightSlash8, $widthSlash16, $rowNum; global $currentValue, $targetValue; global $posX, $posY; if ( $currentValue == $targetValue ) { // We're already at our target (which was probably 0) return true; } // Increment our "how many steps?" counter ... $currentValue ++; // ... and figure out where we're moving. if ( $direction == 'UP' ) { $rowNum --; // Up means subtract previous row height $posY = $posY - $heightSlash8[ floor( $rowNum / 16 ) ] / 16; } elseif ( $direction == 'DOWN' ) { $rowNum ++; // Down means add current row height $posY = $posY + $heightSlash8[ floor( $rowNum / 16 ) ] / 16; } elseif ( $direction == 'LEFT' ) { $posX = $posX - $widthSlash16; } elseif ( $direction == 'RIGHT' ) { $posX = $posX + $widthSlash16; } // Have we hit the target? if ( $currentValue == $targetValue ) { return true; } return false; } // Recursively step through the Hilbert curve of the given level // by starting with the given direction. // Each cycle has four recursive calls to hilbert() // the first three of which are followed calls to move() // ... so for the first six, loop through the array of // directions with both functions, and make the last call // to hilbert() separately. // If $level == 1 we need to omit the calls to hilbert() // and stop recursing. function hilbert( $level, $direction='UP' ) { global $levelDirections; // At the top of this script, the Hilbert curve is // defined by sets of directions, each pair of which // is used to call hilbert() and move() again. $dirs = $levelDirections[ $direction ]; for ( $i = 0; $i < 6; $i += 2 ) { if ( $level != 1 ) { $hbResult = hilbert( $level-1, $dirs[ $i ] ); if ( $hbResult ) { return $hbResult; } } $moveResult = move( $dirs[ $i+1 ] ); if ( $moveResult ) { // A non-false return from either function means // we've found our target, so we can break out // of the recursion. return $moveResult; } } if ( $level != 1 ) { $hbResult = hilbert( $level-1, $dirs[ 6 ] ); if ( $hbResult ) { return $hbResult; } } return false; } ?>