Accueil > Docs > Tiling images for leaflet

Tiling images for leaflet

vendredi 23 novembre 2012, par b_b

Quelques tests

Les différents test sont réalisés à partir de cette image de Deuns sur lestaxinomes.org (3.6Mo 4912x3264 px).

Solution Création des tiles Création du mbtiles Total
togeo + raster2mb 0.17 s / 1.9 Mo 0.79 s + 3.24 s / 1.8 Mo 4.2 s / 1.9 Mo
fil convert 15 s / 5.9 Mo 0.550 s / 5.9 Mo 15.550 s / 5.9 Mo
gdal2tiles 25 s / 25 Mo 0.918 s / 25 Mo 25.918 s / 25 Mo
GSV 47 s / 3.3 Mo
php-tiler 25 min / 28.9 Mo

le script de fil à base de convert

15 secondes, super rapide !

https://bitbucket.org/recifs/tuile/ | http://seenthis.net/messages/102354

GSV

The Python library, PowersOfTwo, (Python Imaging Library required) assists with cutting down large images into square tiles.

http://mike.teczno.com/giant/pan/

En Python, fonctionne bien, 47 s.

gdal2tiles

gdal2tiles.py -p raster -z 0-5 -w none test.jpg

En Python, 25 s. Par contre il faut spécifier les niveau de zoom à la main et le format des tiles générées est en PNG (mais il semble exister des forks qui génèrent du jpeg).

Packager les tuiles dans un mbtiles : 0.918 s

mb-util --image_format=png test test.mbtiles

Une piste pour accélérer les traitements de gdal2tiles.

Autre piste, raster2mb qui permet la même chose pour exporter directement dans un fichier MBTiles (à noter que Tom MacWright semble préférer son script togeo à gdal2tiles dans ce post).

togeo + raster2mb

Convertir le jpeg en tiff avec togeo : 0.79 s

python togeo.py test.jpg

Convertir le tiff en mbtiles avec raster2mb : 3.24 s

python raster2mb.py test.jpg.tif test.mbtiles

Exporter les tuiles du mbtiles dans un répertoire : 0.17 s

mb-util test.mbtiles test

convert tiled pyramid tiff

Convertir le jpeg en tiff tuilé pour l’utiliser dans IIPImage : 9.19s

convert test.jpg -define tiff:tile-geometry=256x256 -compress jpeg 'ptif:test.tif'

php-tiler

Image tiler for online maps such as yandex maps or google maps

https://github.com/bazilio91/php-tiler

Fonctionne bien, mais super lent (environ 25 minutes).

Solution de BigGrizzly

http://seenthis.net/messages/255689

tileMaker

What it does : cuts tiles from images on demand - uses a lot of resources (!) / uses cache dir if available and writable / reads images from directory "images" / delivers "images/black.gif" for off boundary x,y parameters

https://github.com/dfacts/Slippy-Map-On-Canvas/blob/master/tile.php

En PHP, ça risque d’être lent aussi...

OpenTiler

OpenTiler is a desktop application which generates Zoomify tiles and a viewer for supplied images (TIFF, JPEG, BMP, GIF,..). Batch mode is supported (you can choose more files in the first dialog or call the script form the BAT file) and watermarking is possible. https://github.com/moravianlibrary/opentiler

IIPImage

IIPImage is an advanced high-performance feature-rich image server system for web-based streamed viewing and zooming of ultra high-resolution images. It is designed to be fast and bandwidth-efficient with low processor and memory requirements. The system can comfortably handle gigapixel size images as well as advanced image features such as both 8 and 16 bit depths, CIELAB colorimetric images and scientific imagery such as multispectral images. (paquet ubuntu dispo) http://iipimage.sourceforge.net/

leaflet-rastercoords & gdal2tiles-leaflet

Leaflet plugin for plain image map projection to display large images using tiles generated with gdal2tiles-leaflet.

https://commenthol.github.io/leaflet-rastercoords/

The tiles in the example were generated using gdal2tiles-leaflet. Take a look at example/createtiles.sh.

https://github.com/commenthol/gdal2tiles-leaflet

Autres

Le code hugepic.io https://github.com/peterbe/tiler

http://greengaloshes.cc/2007/05/zoomifyimage-ported-to-php/

https://github.com/samsargent/Google-ImageMap-Tile-Generator

https://github.com/stamen/modestmaps-php

http://getsite.org.ua/en/build-site/php-maptiler-simple-map-tiles-generator

Pas en php mais peu servir de critère de recherche : https://github.com/mulka/tiler

Leafletjs image slicing script PHP https://github.com/troglodyte/leafletjs-tiler

Peut être une autre piste dispo dans le cache de google : l’article de présentation / le code

Je colle le code ici pour archive :

<?php
/*
*DISCLAIMER
* 
*THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*	@author: Olivier G. 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
	<head>
		<title>GOOGLE MAPS API - IMAGE VIEWER</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<link rel="shortcut icon" type="image/png" href="favicon.png"/>
		<style type="text/css">
			html, body{
				height: 100%;
				overflow: hidden;
			}
			body{
				height: 96%;
				margin: 10px 10px 10px 10px;
			}
			#map_container{
				width:100%;
				height:90%;
				border-width: 0px;
				background-color:white;
				background-image:url('background_map.jpg');
			}
			#status {
				background-color: #eeeeee;
				padding: 3px 5px 3px 5px;
				opacity: .9;
			}
		</style>
	</head>
	<body>

	<?php if(empty($_FILES['uploaded_file']) && !isset($_GET['imageid']) ){ 
		//Display a basic form to upload an image
	?>
		<form enctype="multipart/form-data" action="<?php echo $_SERVER['SCRIPT_URI']?>" method="POST">
			<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo UPLOAD_FILE_SIZE;?>" />
			Choose a jpg image to upload: <input name="uploaded_file" type="file" /><br />
			<input type="submit" value="Upload File" />
			<p>Tile cutting process can take up to 3mn. Be patient...</p>
			<p>Note: Image size must be under <?php echo UPLOAD_FILE_SIZE/1000000;?>MB and <span style="font-style:italic">(3 * imageWidth * imageWeight)</span> must be under <?php echo FILE_SIZE/1000000;?>MB.</p>
		</form>
	<?php }else{
		if( (!empty($_FILES['uploaded_file'])) && (0 == $_FILES['uploaded_file']['error'])){
			//Process an uploaded image
			$filename = basename($_FILES['uploaded_file']['name']);
			$ext = strtolower(substr($filename, strrpos($filename, '.') + 1));
			//Check if valid image (type, size)
			if (($ext == "jpg") && ($_FILES["uploaded_file"]["type"] == "image/jpeg") && ($_FILES["uploaded_file"]["size"] < UPLOAD_FILE_SIZE)) {
				//Get image dimensions
				list($imageX, $imageY) = getimagesize($_FILES['uploaded_file']['tmp_name']);
				//Check if valid image (size)
				if( (3*$imageX*$imageY) > FILE_SIZE){
					exit('Error: only <span style="font-style:italic">(3 * imageWidth * imageWeight)</span> under '.(FILE_SIZE/1000000).'MB are accepted for upload<br/>Current size:'.intval(((3*$imageX*$imageY)/1000000)).'MB.');
				}
				//Get required nb of tiles along the longest dimension
				$maxTileDim = ceil(max($imageX, $imageY) / TILE_SIZE);
				//Get max zoom level (aka zoom level with pixel dimensions containing the whole image)
				$maxZoomLevel = 0;
				do{
					++$maxZoomLevel;
				}while(pow(2, $maxZoomLevel) < $maxTileDim);
				$nbMaxZoomLevelTiles = pow(2, $maxZoomLevel);
				$imageRatioMaxTileX = round(ceil($imageX / TILE_SIZE) / $nbMaxZoomLevelTiles, 2);
				$imageRatioMaxTileY = round(ceil($imageY / TILE_SIZE) / $nbMaxZoomLevelTiles, 2);
				//Create a new dir to store tiles for current image
				do{
					$imageId = $maxZoomLevel.FIELD_SPARATOR.$imageRatioMaxTileX.FIELD_SPARATOR.$imageRatioMaxTileY.FIELD_SPARATOR.rand(0, 99999);
					$imageTileDir = TILE_DIR.$imageId;
				}while(file_exists($imageTileDir));
				mkdir($imageTileDir, 0705);
				
				if(FALSE === ($rawImage = imagecreatefromjpeg($_FILES['uploaded_file']['tmp_name']))){
					exit('GD function imagecreatefromjpeg failed! line 102');
				};
				//Loop through zoom levels to produce tiles
				for($zoom = 0; $zoom <= $maxZoomLevel; ++$zoom){
					if($zoom != $maxZoomLevel){
						//Resize raw image before cutting
						$scale = pow(2, $maxZoomLevel - $zoom);
						$newImageX = floor($imageX / $scale);
						$newImageY = floor($imageY / $scale);
						$srcImage = imagecreatetruecolor($newImageX, $newImageY);
						if(FALSE ===imagecopyresampled($srcImage, $rawImage, 0, 0, 0, 0, $newImageX, $newImageY, $imageX, $imageY)){
							exit('GD function imagecopyresampled failed!');
						}
						//Add a frame
						imagerectangle($srcImage, 0, 0, $newImageX-1, $newImageY-1, imagecolorallocate($srcImage, 255, 255, 255));
					}else{
						//At max zoom level, use not resized image
						$srcImage = $rawImage;
						imagerectangle($srcImage, 0, 0, $imageX-1, $imageY-1, imagecolorallocate($srcImage, 255, 255, 255));
					}
					$zoomNbTiles = pow(2, $zoom);
					//Get bottom right tile coordinates
					$maxTileX = ceil($zoomNbTiles * $imageRatioMaxTileX);
					$maxTileY = ceil($zoomNbTiles * $imageRatioMaxTileY);
					//Loop through tiles to cut
					for($X=0; $X < $maxTileX; ++$X){
						for($Y=0; $Y < $maxTileY; ++$Y){
							$dstImage = imagecreatetruecolor(TILE_SIZE, TILE_SIZE);
							if(FALSE === imagecopy($dstImage, $srcImage, 0, 0, $X*TILE_SIZE, $Y*TILE_SIZE,  TILE_SIZE, TILE_SIZE)){
								exit('GD function imagecopy failed!');
							}
							//Save tiles on FS
							if(FALSE === imagejpeg($dstImage, $imageTileDir.'/'.$zoom.'_'.$X.'_'.$Y.'.jpg', 85)){
								exit('GD function imagejpeg failed! line 135');
							}
							imagedestroy($dstImage);
							unset($dstImage);
						}
					}
					imagedestroy($srcImage);
					unset($srcImage);
					//$rawImage clean up is in the last iteration
				}
			} else {
				exit('Error: only .jpg images under '.UPLOAD_FILE_SIZE.'B are accepted for upload.
<div id="map_container"></div> <p>Direct access to this page: <a href="<?php echo $_SERVER['SCRIPT_URI'].'?imageid='.$imageId;?>" alt=""><?php echo $_SERVER['SCRIPT_URI'].'?imageid='.$imageId;?></a>. This link will stay valid until 3.00 AM (Paris time).</p> <div id="status"> Status:  <span id="log"> <img alt="progess bar" src="progress_bar.gif" width="150" height="16"/></span> <img src="corner_topleft.png" id="G_ANCHOR_TOP_LEFT" alt="" width="15" height="15"/> <img src="corner_topright.png" id="G_ANCHOR_TOP_RIGHT" alt="" width="15" height="15"/> <img src="corner_bottomleft.png" id="G_ANCHOR_BOTTOM_LEFT" alt="" width="15" height="15"/> <img src="corner_bottomright.png" id="G_ANCHOR_BOTTOM_RIGHT" alt="" width="15" height="15"/> <script type="text/javascript" src="http://www.google.com/jsapi?autoload=%7B%22modules%22:%5B%7B%22name%22:%22maps%22,%22version%22:%222.X%22%7D,%7B%22name%22:%22jquery%22,%22version%22:%221.4.2%22%7D%5D%7D&key=ABQIAAAAsqOJguRopHw3Bto4-I7GMxSQMccRtohFE_8geNK2Z4p8fnaRyBQ84vBpRKiImT8nfuL1UgUH5soqYw"></script> <script type="text/javascript"> //<![CDATA[ var googleMap = null; $(function($){//Call when page is loaded $(window).unload(function(){//Code called when page closed if (google.maps.BrowserIsCompatible()){ google.maps.Unload(); } });//unload if (google.maps.BrowserIsCompatible()) { //Create map and add parameters for ads displayed in the search bar googleMap = new google.maps.Map2(document.getElementById("map_container")); googleMap.addControl(new GLargeMapControl3D()); googleMap.enableContinuousZoom(); //googleMap.enableScrollWheelZoom();//KO var sizeZero = new google.maps.Size(0, 0); //We use the jQuery 'each' function to loop through the 4 corners of the map and set the rounded corner. $.each(['G_ANCHOR_TOP_LEFT', 'G_ANCHOR_TOP_RIGHT', 'G_ANCHOR_BOTTOM_LEFT', 'G_ANCHOR_BOTTOM_RIGHT'], function(i, cornerName){ //Little trick: image id = enum GControlAnchor so we can use 'CornerName' twice. var pos = new google.maps.ControlPosition(eval(cornerName), sizeZero); var target = $("#" + cornerName).get(0); pos.apply(target); googleMap.getContainer().appendChild(target); });//each //Add the status bar pos = new google.maps.ControlPosition(G_ANCHOR_TOP_LEFT, new google.maps.Size(75, 10)); pos.apply($("#status").get(0)); googleMap.getContainer().appendChild($("#status").get(0)); googleMap.setCenter(new google.maps.LatLng(0, 0), 0); var copyrightCollection = new google.maps.CopyrightCollection('©2010'); var latLngBounds = new google.maps.LatLngBounds(new google.maps.LatLng(-90,-180), new google.maps.LatLng(90,180)); var copyright = new google.maps.Copyright( Math.round(Math.random()*100),//random id latLngBounds, 0, 'GMapify'); copyrightCollection.addCopyright(copyright); //Tile layer is constrained by zoom level var tileLayerImage = new google.maps.TileLayer(copyrightCollection, 0, <?php echo $maxZoomLevel;?>); tileLayerImage.getTileUrl = function(a,b){ var imageRatioMaxTileX = <? echo $imageRatioMaxTileX; ?>; var imageRatioMaxTileY = <? echo $imageRatioMaxTileY; ?>; var nbTiles = Math.pow(2, b); if( (a.x < Math.ceil(imageRatioMaxTileX * nbTiles)) && (a.y < Math.ceil(imageRatioMaxTileY * nbTiles)) ){ return '<? echo $imageTileDir; ?>/'+ b + '_' + a.x + '_' + a.y + '.jpg'; }else{ return 'empty.jpg'; } }; // Create a new map type incorporating the tile layer var mapTypeImage = new google.maps.MapType([tileLayerImage], G_NORMAL_MAP.getProjection(), "Image",{'textColor':'#ffffff'}); googleMap.addMapType(mapTypeImage); //Display image googleMap.setMapType(mapTypeImage); $("#log").html("Image loaded!"); } });//onload //]]> </script> <?php } ?> </body> </html>
Mono Image Viewer