Index: simutrans/trunk/dataobj/height_map_loader.cc
===================================================================
--- simutrans/trunk/dataobj/height_map_loader.cc	(revision 7847)
+++ simutrans/trunk/dataobj/height_map_loader.cc	(working copy)
@@ -7,6 +7,7 @@
 #include "environment.h"
 #include "height_map_loader.h"
 #include "../simio.h"
+#include "../utils/imgloader.h"
 
 
 height_map_loader_t::height_map_loader_t(bool new_format):
@@ -18,225 +19,31 @@
 // read height data from bmp or ppm files
 bool height_map_loader_t::get_height_data_from_file( const char *filename, sint8 grundwasser, sint8 *&hfield, sint16 &ww, sint16 &hh, bool update_only_values )
 {
-	if (FILE* const file = fopen(filename, "rb")) {
-		char id[3];
-		// parsing the header of this mixed file format is nottrivial ...
-		id[0] = fgetc(file);
-		id[1] = fgetc(file);
-		id[2] = 0;
-		if(strcmp(id, "P6")) {
-			if(strcmp(id, "BM")) {
-				fclose(file);
-				dbg->error("height_map_loader_t::load_heightfield()","Heightfield has wrong image type %s instead P6/BM", id);
-				return false;
-			}
-			// bitmap format
-			fseek( file, 10, SEEK_SET );
-			uint32 data_offset;
-			sint32 w, h, format, table;
-			sint16 bit_depth;
-#ifdef SIM_BIG_ENDIAN
-			uint32 l;
-			uint16 s;
-			fread( &l, 4, 1, file );
-			data_offset = endian(l);
-			fseek( file, 18, SEEK_SET );
-			fread( &l, 4, 1, file );
-			w = endian(l);
-			fread( &l, 4, 1, file );
-			h = endian(l);
-			fseek( file, 28, SEEK_SET );
-			fread( &s, 2, 1, file );
-			bit_depth = endian(s);
-			fread( &l, 4, 1, file );
-			format = endian(l);
-			fseek( file, 46, SEEK_SET );
-			fread( &l, 4, 1, file );
-			table = endian(l);
-#else
-			fread( &data_offset, 4, 1, file );
-			fseek( file, 18, SEEK_SET );
-			fread( &w, 4, 1, file );
-			fread( &h, 4, 1, file );
-			fseek( file, 28, SEEK_SET );
-			fread( &bit_depth, 2, 1, file );
-			fread( &format, 4, 1, file );
-			fseek( file, 46, SEEK_SET );
-			fread( &table, 4, 1, file );
-#endif
-			if((bit_depth!=8  &&  bit_depth!=24)  ||  format>1) {
-				if(!update_only_values) {
-					dbg->fatal("height_map_loader_t::get_height_data_from_file()","Can only use 8Bit (RLE or normal) or 24 bit bitmaps!");
-				}
-				fclose( file );
-				return false;
-			}
+	sint32 w, h;//, format, table;
+	img_loader *l=new img_loader();
+	if (l->load_image(filename)!=IMGR_OK) {
+        delete l;
+        return false;
+	}
+	w=l->get_width();
+	h=l->get_height();
+	ww=w;
+	hh=h;
+	if (update_only_values) {
+        return true;
+	}
 
-			// skip parsing body
-			if(update_only_values) {
-				ww = w;
-				hh = abs(h);
-				return true;
-			}
+	RGBA *img=(RGBA *)l->get_bits();
+	hfield = new sint8[w*h];
+	memset( hfield, grundwasser, w*h );
 
-			// now read the data and convert them on the fly
-			hfield = new sint8[w*h];
-			memset( hfield, grundwasser, w*h );
-			if(bit_depth==8) {
-				// convert color tables to height levels
-				if(table==0) {
-					table = 256;
-				}
-				sint8 h_table[256];
-				fseek( file, 54, SEEK_SET );
-				for( int i=0;  i<table;  i++  ) {
-					int B = fgetc(file);
-					int G = fgetc(file);
-					int R = fgetc(file);
-					fgetc(file);	// dummy
-					h_table[i] = height_map_loader_t::rgb_to_height(R, G, B);
-				}
-				// now read the data
-				fseek( file, data_offset, SEEK_SET );
-				if(format==0) {
-					// uncompressed (usually mirrored, if h>0)
-					bool mirror = (h<0);
-					h = abs(h);
-					for(  sint32 y=0;  y<h;  y++  ) {
-						sint32 offset = mirror ? y*w : (h-y-1)*w;
-						for(  sint32 x=0;  x<w;  x++  ) {
-							hfield[x+offset] = h_table[fgetc(file)];
-						}
-						// skip line offset
-						if(w&1) {
-							fgetc(file);
-						}
-					}
-				}
-				else {
-					// compressed RLE (reverse y, since mirrored)
-					sint32 x=0, y=h-1;
-					while (!feof(file)) {
-						uint8 Count= fgetc(file);
-						uint8 ColorIndex = fgetc(file);
-
-						if (Count > 0) {
-							for( sint32 k = 0;  k < Count;  k++, x++  ) {
-								hfield[x+(y*w)] = h_table[ColorIndex];
-							}
-						} else if (Count == 0) {
-							sint32 Flag = ColorIndex;
-							if (Flag == 0) {
-								// goto next line
-								x = 0;
-								y--;
-							}
-							else if (Flag == 1) {
-								// end of bitmap
-								break;
-							}
-							else if (Flag == 2) {
-								// skip with cursor
-								x += (uint8)fgetc(file);
-								y -= (uint8)fgetc(file);
-							}
-							else {
-								// uncompressed run
-								Count = Flag;
-								for( sint32 k = 0;  k < Count;  k++, x++  ) {
-									hfield[x+y*w] = h_table[(uint8)fgetc(file)];
-								}
-								if (ftell(file) & 1) {	// alway even offset in file
-									fseek(file, 1, SEEK_CUR);
-								}
-							}
-						}
-					}
-				}
-			}
-			else {
-				// uncompressed 24 bits
-				bool mirror = (h<0);
-				h = abs(h);
-				for(  sint32 y=0;  y<h;  y++  ) {
-					sint32 offset = mirror ? y*w : (h-y-1)*w;
-					for(  sint32 x=0;  x<w;  x++  ) {
-						int B = fgetc(file);
-						int G = fgetc(file);
-						int R = fgetc(file);
-						hfield[x+offset] = height_map_loader_t::rgb_to_height(R, G, B);
-					}
-					fseek( file, (4-((w*3)&3))&3, SEEK_CUR );	// skip superfluos bytes at the end of each scanline
-				}
-			}
-			// success ...
-			fclose(file);
-			ww = w;
-			hh = h;
-			return true;
-		}
-		else {
-			// ppm format
-			char buf[255];
-			char *c = id+2;
-			sint32 param[3]={0,0,0};
-			for(int index=0;  index<3;  ) {
-				// the format is "P6[whitespace]width[whitespace]height[[whitespace bitdepth]]newline]
-				// however, Photoshop is the first program, that uses space for the first whitespace ...
-				// so we cater for Photoshop too
-				while(*c  &&  *c<=32) {
-					c++;
-				}
-				// usually, after P6 there comes a comment with the maker
-				// but comments can be anywhere
-				if(*c==0) {
-					read_line(buf, sizeof(buf), file);
-					c = buf;
-					continue;
-				}
-				param[index++] = atoi(c);
-				while(*c>='0'  &&  *c<='9') {
-					c++;
-				}
-			}
-			// now the data
-			sint32 w = param[0];
-			sint32 h = param[1];
-			if(param[2]!=255) {
-				fclose(file);
-				if(!update_only_values) {
-					dbg->fatal("height_map_loader_t::load_heightfield()","Heightfield has wrong color depth %d", param[2] );
-				}
-				return false;
-			}
-
-			// report only values
-			if(update_only_values) {
-				fclose(file);
-				ww = w;
-				hh = h;
-				return true;
-			}
-
-			// ok, now read them in
-			hfield = new sint8[w*h];
-			memset( hfield, grundwasser, w*h );
-
-			for(sint16 y=0; y<h; y++) {
-				for(sint16 x=0; x<w; x++) {
-					int R = fgetc(file);
-					int G = fgetc(file);
-					int B = fgetc(file);
-					hfield[x+(y*w)] = height_map_loader_t::rgb_to_height(R, G, B);
-				}
-			}
-
-			// success ...
-			fclose(file);
-			ww = w;
-			hh = h;
-			return true;
-		}
+	for (int y=0;y<h;y++) {
+        for (int x=0;x<w;x++) {
+            int location=y*w+x;
+            hfield[location]=height_map_loader_t::rgb_to_height(img[location].Red,img[location].Green,img[location].Blue);
+        }
 	}
-	return false;
+	delete l;
+            
+	return true;
 }
Index: simutrans/trunk/dataobj/scenario.cc
===================================================================
--- simutrans/trunk/dataobj/scenario.cc	(revision 7847)
+++ simutrans/trunk/dataobj/scenario.cc	(working copy)
@@ -922,3 +922,10 @@
 	}
 	return true;
 }
+
+plainstring scenario_t::get_scenario_path() {
+    if (scenario_path==NULL) {
+        return "";
+    }
+    return scenario_path;
+}
Index: simutrans/trunk/dataobj/scenario.h
===================================================================
--- simutrans/trunk/dataobj/scenario.h	(revision 7847)
+++ simutrans/trunk/dataobj/scenario.h	(working copy)
@@ -408,6 +408,11 @@
 	 */
 	const char* is_schedule_allowed(const player_t* player, const schedule_t* schedule);
 
+    /**
+     * Returns the path to the Scenario
+     * @return The path to the Scenario
+     */
+    plainstring get_scenario_path();
 
 	/// @return debug dump of forbidden tools
 	const char* get_forbidden_text();
Index: simutrans/trunk/gui/components/gui_flowtext.cc
===================================================================
--- simutrans/trunk/gui/components/gui_flowtext.cc	(revision 7847)
+++ simutrans/trunk/gui/components/gui_flowtext.cc	(working copy)
@@ -6,7 +6,11 @@
 #include "../../dataobj/translator.h"
 #include "../../utils/simstring.h"
 #include "../gui_theme.h"
+#include "../../display/simimg.h"
 
+#include "../../simdebug.h"
+
+#include "gui_flowtext_image.h"
 #include "gui_flowtext.h"
 
 gui_flowtext_t::gui_flowtext_t()
@@ -25,6 +29,7 @@
 	// purge all old texts
 	nodes.clear();
 	links.clear();
+	images.clear();
 
 	// Hajo: danger here, longest word in text
 	// must not exceed 511 chars!
@@ -89,6 +94,30 @@
 			else if (word[0] == 'h' && word[1] == '1') {
 				att = endtag ? ATT_H1_END : ATT_H1_START;
 			}
+			else if (word[0] == 'i'&& word[1] == 'm' && word[2] == 'g') {
+				if (!endtag) {
+                    att=ATT_IMG_START;
+                    char *start=word+4;
+                    start = const_cast<char*>( strstart(start, "src"));
+                    if (start) {
+                        while (*start=='"'||*start==' '||*start=='='||*start=='\'') start++;
+                        char *end=start;
+                        while (*end && *end!= '"' && *end != '\'') end++;
+                        *end=0;
+                        param=start;
+                        if (param[0]!=0) {
+                            // Load in Image and Store Image ID for displaying
+                            gui_flowtext_image_t img=gui_flowtext_image_t(param);
+							image_id ret=img.get_image_id();
+							images.append(ret);
+                        }
+                    } else {
+                        param="";
+                    }
+				} else {
+				    att=ATT_IMG_END;
+				}
+			}
 			else if (word[0] == 'i') {
 				att = endtag ? ATT_IT_END : ATT_IT_START;
 			}
@@ -239,6 +268,7 @@
 	const int width = size.w;
 
 	slist_tpl<hyperlink_t>::iterator link = links.begin();
+	slist_tpl<image_t>::iterator image=images.begin();
 
 	int xpos         = 0;
 	int ypos         = 0;
@@ -247,6 +277,8 @@
 	bool double_it   = false;
 	bool link_it     = false;	// true, if currently underlining for a link
 	int extra_pixel  = 0;		// extra pixel before next line
+	int extra_pixels = 0;       // extra pixels for image display
+	int extra_x_pixels=0;       // extra pixels in x dimension for image display
 	int last_link_x  = 0;		// at this position ye need to continue underline drawing
 	int max_width    = width;
 	int text_width   = width;
@@ -276,8 +308,22 @@
 						}
 						extra_pixel = 1;
 					}
-					xpos = 0;
-					last_link_x = 0;
+
+					if ((extra_x_pixels+nxpos)>max_width) {
+						ypos+=extra_pixels;
+						extra_pixels=0;
+						extra_x_pixels=0;
+					}
+					if (extra_pixels>0) {
+						xpos=extra_x_pixels;
+						nxpos+=extra_x_pixels;
+						extra_pixels-= LINESPACE+extra_pixel;
+					} else {
+						xpos = 0;
+						extra_pixels = 0;
+					}
+					last_link_x = extra_x_pixels;
+
 					ypos += LINESPACE+extra_pixel;
 					extra_pixel = 0;
 				}
@@ -312,7 +358,9 @@
 					}
 					extra_pixel = 1;
 				}
-				ypos += LINESPACE+extra_pixel;
+				ypos += LINESPACE+extra_pixel+extra_pixels;
+				extra_x_pixels=0;
+				extra_pixels=0;
 				last_link_x = 0;
 				extra_pixel = 0;
 				break;
@@ -344,15 +392,52 @@
 			case ATT_H1_END:
 				double_it = false;
 				if(doit) {
-					display_fillbox_wh_clip(offset.x + 1, offset.y + ypos + LINESPACE,   xpos, 1, color,        false);
-					display_fillbox_wh_clip(offset.x,     offset.y + ypos + LINESPACE-1, xpos, 1, double_color, false);
+					display_fillbox_wh_clip(offset.x + 1 + extra_x_pixels, offset.y + ypos + LINESPACE,   xpos - extra_x_pixels, 1, color,        false);
+					display_fillbox_wh_clip(offset.x + extra_x_pixels,     offset.y + ypos + LINESPACE-1, xpos - extra_x_pixels, 1, double_color, false);
 				}
 				xpos = 0;
 				extra_pixel = 0;
 				ypos += LINESPACE+2;
+				if (extra_pixels>0) {
+					xpos=extra_x_pixels;
+					extra_pixels-= LINESPACE+extra_pixel;
+				} else {
+					xpos = 0;
+					extra_pixels = 0;
+				}
 				color = SYSCOL_TEXT;
 				break;
 
+            case ATT_IMG_START:
+                if (image!=images.end()) {
+
+					//display image
+					KOORD_VAL xoff,yoff,xw,yw;
+					display_get_base_image_offset(image->id,&xoff,&yoff,&xw,&yw);
+					if ((xpos+xw>max_width)&&(xpos!=0)) {
+						// New Line if image is too large to fit on line (unless already at new line)
+						xpos=0;
+						ypos+=LINESPACE+extra_pixel+extra_pixels;
+						extra_pixel=0;
+						extra_pixels=0;
+						extra_x_pixels=0;
+					}
+					if (doit) {
+						display_base_img(image->id,offset.x+xpos,offset.y+ypos-yoff,0,0,0);
+					}
+					xpos+=xw;
+					//ypos+=yw-LINESPACE;
+					if (extra_pixels<yw-LINESPACE) {
+						extra_pixels=yw-LINESPACE;	// Set extra pixels for new line based on height of image.
+					}
+					extra_x_pixels=xpos;
+
+					++image;
+				}
+				break;
+			case ATT_IMG_END:
+				break;
+
 			case ATT_EM_START:
 				color = SYSCOL_TEXT_HIGHLIGHT;
 				break;
Index: simutrans/trunk/gui/components/gui_flowtext.h
===================================================================
--- simutrans/trunk/gui/components/gui_flowtext.h	(revision 7847)
+++ simutrans/trunk/gui/components/gui_flowtext.h	(working copy)
@@ -55,6 +55,7 @@
 		ATT_EM_START,     ATT_EM_END,
 		ATT_IT_START,     ATT_IT_END,
 		ATT_STRONG_START, ATT_STRONG_END,
+		ATT_IMG_START,    ATT_IMG_END,
 		ATT_UNKNOWN
 	};
 
@@ -79,8 +80,19 @@
 		std::string  param;
 	};
 
+	/**
+	 * Image position container
+	 * @author Hayden Read
+	 */
+    struct image_t
+    {
+        image_t(const image_id id_):id(id_) {}
+        image_id id;
+    };
+
 	slist_tpl<node_t>      nodes;
 	slist_tpl<hyperlink_t> links;
+	slist_tpl<image_t>     images;
 	char title[128];
 };
 
Index: simutrans/trunk/gui/components/gui_flowtext_image.cc
===================================================================
--- simutrans/trunk/gui/components/gui_flowtext_image.cc	(nonexistent)
+++ simutrans/trunk/gui/components/gui_flowtext_image.cc	(working copy)
@@ -0,0 +1,140 @@
+#include "gui_flowtext_image.h"
+
+#include "../../besch/bild_besch.h"
+#include "../../dataobj/environment.h"
+#include "../../simworld.h"
+#include "../../dataobj/scenario.h"
+#include "../../utils/imgloader.h"
+//#include "../../utils/dr_rdpng.h"
+#include "../../simdebug.h"
+
+gui_flowtext_image_t::gui_flowtext_image_t() {
+	_image_name="";
+	_image_id=0;
+}
+
+image_id gui_flowtext_image_t::get_image_id() {
+	return _image_id;
+}
+
+std::string gui_flowtext_image_t::get_image_name() {
+	return _image_name;
+}
+
+hashtable_tpl<const char *,image_id,stringhash_t> *gui_flowtext_image_t::_images=NULL;
+
+gui_flowtext_image_t::gui_flowtext_image_t(std::string filePath) {
+	// Initialize Image list if it has not already been done.
+	if (_images==NULL) {
+		_images=new hashtable_tpl<const char *,image_id,stringhash_t>();
+	}
+	_image_name=filePath;
+
+	// Check if image is already loaded
+	_image_id=_images->get(filePath.c_str());
+	if (_image_id>0) {
+		return;
+	}
+
+	// First Search for image in Scenario Path, then PAK path, the base path
+	scenario_t *scenario=world()->get_scenario();
+	std::string spath=scenario->get_scenario_path().c_str();
+
+	std::string path= env_t::program_dir+spath+filePath;
+	FILE *fp=fopen(path.c_str(),"rb");
+
+	if (fp==NULL) {
+		path= env_t::program_dir+env_t::objfilename + filePath;
+		fp=fopen(path.c_str(),"rb");
+		if (fp==NULL) {
+			path= env_t::program_dir+filePath;
+			fp=fopen(path.c_str(),"rb");
+			if (fp==NULL) {
+				// file not found
+				_image_id=0;
+				return;
+			}
+		}
+	}
+
+	fclose(fp);
+	dbg->message("gui_flow_text_image_t()","Loading File %s",path.c_str());
+	img_loader c=img_loader();
+	c.load_image(path.c_str());
+	dbg->message("gui_flow_text_image_t()","Loaded File %s",path.c_str());
+	/*if ((filePath.substr(filePath.length()-3,3)=="png")||(filePath.substr(filePath.length()-3,3)=="PNG")) {
+		// Load PNG Instead
+		unsigned char **block=new unsigned char * [1];
+		block[0]=(unsigned char *)malloc(1);
+		uint32 width=0;
+		uint32 height=0;
+		uint32 base_img_size=1;
+		load_block(block,&width,&height,path.c_str(),base_img_size);
+		c.set_bits(block[0],width,0-height,0x000000FF,0x0000FF00,0x00FF0000);
+	} else {
+		// Load BMP
+		c.load(path.c_str());
+	}*/
+	uint a = 0x00000000;
+	uint r = 0x00007C00;
+	uint g = 0x000003E0;
+	uint bl = 0x0000001F;
+	uint size=c.get_width()*c.get_height()+2;
+	uint16 *buffer=new uint16 [size];
+	size=size*2;
+	c.get_bits((void*)buffer,size,r,g,bl,a,false);
+	//PIXVAL pixel=0;
+	//PIXVAL prevPixel=0;
+	//PIXVAL count=0;
+	size_t len=0;
+	// Create a buffer to store all required PIXVAL data
+	PIXVAL *pixBuffer=new PIXVAL [(c.get_width()+2)*c.get_height()*3];
+	bool first=true;
+	for (uint32 i=0;i<(c.get_width()*c.get_height());i++) {
+		if (i%c.get_width()==0) {
+			if (first) {
+				first=false;
+			} else {
+				// Add end of line 0 terminator
+				pixBuffer[len]=0;
+				len++;
+			}
+			// Add 0 Transparent pixels
+			pixBuffer[len]=0;
+			len++;
+			// Add image width pixels
+			pixBuffer[len]=c.get_width();
+			len++;
+		}
+		// Add the pixel data
+		pixBuffer[len]=buffer[i];
+		len++;
+	}
+	// Add a 0 at the end of the data
+	pixBuffer[len]=0;
+	len++;
+
+	// Not sure how to correctly allocate data for bild_t, other than that in has a set of data + buffer of PIXVAL items
+	bild_t *b=(bild_t *)malloc(sizeof(PIXVAL)*len+128);
+	// Set image data
+	b->x=0;
+	b->y=0;
+	b->w=c.get_width();
+	b->h=c.get_height();
+	b->zoomable=0;
+	b->len=len;
+	for (uint32 i=0;i<len;i++) {
+		b->data[i]=pixBuffer[i];
+	}
+	// delete the temporary pixBuffer
+	delete pixBuffer;
+	// register the image
+	register_image(b);
+	// Store the image number for later retrieval
+	_image_id=b->bild_nr;
+	char * name=new char [_image_name.length()+1];
+	strcpy(name,_image_name.c_str());
+	// Store the image details in case it is accessed later
+	_images->put(name,_image_id);
+}
+
Index: simutrans/trunk/gui/components/gui_flowtext_image.h
===================================================================
--- simutrans/trunk/gui/components/gui_flowtext_image.h	(nonexistent)
+++ simutrans/trunk/gui/components/gui_flowtext_image.h	(working copy)
@@ -0,0 +1,22 @@
+#ifndef GUI_COMPONENTS_FLOWTEXT_IMAGE_H
+#define GUI_COMPONENTS_FLOWTEXT_IMAGE_H
+
+#include <string>
+#include "../../display/simimg.h"
+#include "../../tpl/hashtable_tpl.h"
+#include "../../tpl/stringhashtable_tpl.h"
+
+class gui_flowtext_image_t {
+public:
+	gui_flowtext_image_t(std::string filePath);
+	gui_flowtext_image_t();
+
+	image_id get_image_id();
+	std::string get_image_name();
+private:
+	image_id	_image_id;
+	std::string	_image_name;
+	static hashtable_tpl<const char *,image_id,stringhash_t> *_images;
+};
+
+#endif
Index: simutrans/trunk/Makefile
===================================================================
--- simutrans/trunk/Makefile	(revision 7847)
+++ simutrans/trunk/Makefile	(working copy)
@@ -255,6 +255,7 @@
 SOURCES += gui/components/gui_obj_view_t.cc
 SOURCES += gui/components/gui_fixedwidth_textarea.cc
 SOURCES += gui/components/gui_flowtext.cc
+SOURCES += gui/components/gui_flowtext_image.cc
 SOURCES += gui/components/gui_image.cc
 SOURCES += gui/components/gui_image_list.cc
 SOURCES += gui/components/gui_komponente.cc
@@ -435,6 +436,8 @@
 SOURCES += unicode.cc
 SOURCES += utils/cbuffer_t.cc
 SOURCES += utils/csv.cc
+SOURCES += utils/dr_rdpng.cc
+SOURCES += utils/imgloader.cc
 SOURCES += utils/log.cc
 SOURCES += utils/searchfolder.cc
 SOURCES += utils/sha1.cc
@@ -603,6 +606,7 @@
   include OSX/osx.mk
 endif
 
+LIBS += -lpng
 
 .PHONY: makeobj
 
Index: simutrans/trunk/utils/imgloader.cc
===================================================================
--- simutrans/trunk/utils/imgloader.cc	(nonexistent)
+++ simutrans/trunk/utils/imgloader.cc	(working copy)
@@ -0,0 +1,902 @@
+#include "imgloader.h"
+#include "dr_rdpng.h"
+#include <iostream>
+#include <fstream>
+#include "../simio.h"
+#include "../simdebug.h"
+#include <string.h>
+
+img_loader::img_loader(const char *filename):m_bitmap_data(0),m_bitmap_size(0),m_greyscale(0) {
+    dispose();
+    if (filename!=NULL) {
+        load_image(filename);
+    }
+}
+
+img_loader::~img_loader() {
+    dispose();
+}
+
+void img_loader::dispose(void) {
+    if (m_bitmap_data) {
+        delete[] m_bitmap_data;
+        m_bitmap_data=NULL;
+    }
+    memset(&m_bitmap_file_header,0,sizeof(m_bitmap_file_header));
+    memset(&m_bitmap_header,0,sizeof(m_bitmap_header));
+}
+
+ImgResult img_loader::load_image(const char * filename) {
+    if (filename==NULL) {
+        return IMGR_NULL;
+    }
+    std::ifstream file(filename, std::ios::binary | std::ios::in);
+
+    if (file.bad()) {
+        return IMGR_FILE_DOES_NOT_EXIST;
+    }
+
+    if (!file.is_open()) {
+        return IMGR_UNABLE_TO_OPEN;
+    }
+
+    dispose();
+    char signature[3]={0,0,0};
+    file.read(signature,2);
+    if (strcmp(signature,"BM")==0) {
+        file.close();
+        return this->load_bmp(filename);
+    } else if ((signature[0]=='P')&&(signature[1]>='1')&&(signature[1]<='6')) {
+        file.close();
+        return this->load_pxm(filename);
+    } else if (strcmp(signature,"‰P")==0) {
+        file.read(signature,2);
+        if (strcmp(signature,"NG")==0) {
+            file.close();
+            return this->load_png(filename);
+        } else {
+            file.close();
+            return IMGR_UNSUPPORTED_FORMAT;
+        }
+    }
+    file.close();
+    return IMGR_UNSUPPORTED_FORMAT;
+}
+
+void * img_loader::get_bits()
+{
+	return (void*)m_bitmap_data;
+}
+
+ImgResult img_loader::get_bits(void * buffer, uint32 & buffer_size, uint32 red_mask, uint32 green_mask, uint32 blue_mask, uint32 alpha_mask, bool include_padding)
+{
+	ImgResult result = IMGR_OK;
+	uint32 BitCountRed = color::bit_count_by_mask(red_mask);
+	uint32 BitCountGreen = color::bit_count_by_mask(green_mask);
+	uint32 BitCountBlue = color::bit_count_by_mask(blue_mask);
+	uint32 BitCountAlpha = color::bit_count_by_mask(alpha_mask);
+
+	unsigned int BitCount = (BitCountRed + BitCountGreen + BitCountBlue + BitCountAlpha + 7) & ~7;
+
+	if (BitCount > 32) {
+		return IMGR_INVALID_FORMAT;
+	}
+
+	unsigned int w = get_width();
+	unsigned int dataBytesPerLine = (w * BitCount + 7) / 8;
+	unsigned int LineWidth = (dataBytesPerLine + 3) & ~3;
+
+	if (buffer_size == 0 || buffer == 0) {
+		buffer_size = (get_width() * get_height() * BitCount) / 8 + sizeof(unsigned int);
+		return IMGR_OK;
+	}
+
+	uint8* BufferPtr = (uint8*)buffer;
+
+	uint32 BitPosRed = color::bit_position_by_mask(red_mask);
+	uint32 BitPosGreen = color::bit_position_by_mask(green_mask);
+	uint32 BitPosBlue = color::bit_position_by_mask(blue_mask);
+	uint32 BitPosAlpha = color::bit_position_by_mask(alpha_mask);
+
+	unsigned int j = 0;
+
+	for (uint32 i = 0; i < (uint32)m_bitmap_size; i++) {
+		*(uint32*)BufferPtr =
+			(color::convert(m_bitmap_data[i].Blue, 8, BitCountBlue) << BitPosBlue) |
+			(color::convert(m_bitmap_data[i].Green, 8, BitCountGreen) << BitPosGreen) |
+			(color::convert(m_bitmap_data[i].Red, 8, BitCountRed) << BitPosRed) |
+			(color::convert(m_bitmap_data[i].Alpha, 8, BitCountAlpha) << BitPosAlpha);
+
+		if (include_padding) {
+			j++;
+			if (j >= w) {
+				for (uint32 k = 0; k < LineWidth - dataBytesPerLine; k++) {
+					BufferPtr += (BitCount >> 3);
+				}
+				j = 0;
+			}
+
+		}
+
+		BufferPtr += (BitCount >> 3);
+	}
+
+	buffer_size -= sizeof(uint32);
+
+	return result;
+}
+
+ImgResult img_loader::load_bmp(const char *filename) {
+    std::ifstream file(filename, std::ios::binary | std::ios::in);
+
+    if (file.bad()) {
+        return IMGR_FILE_DOES_NOT_EXIST;
+    }
+
+    if (file.is_open() == false) {
+        return IMGR_UNABLE_TO_OPEN;
+    }
+    dispose();
+
+    file.read((char*) &m_bitmap_file_header, sizeof(BITMAP_FILEHEADER_SIZE));
+    if (m_bitmap_file_header.Signature!=BITMAP_SIGNATURE) {
+        return IMGR_INVALID_FORMAT;
+    }
+
+    file.read((char*) &m_bitmap_header,sizeof(BITMAP_HEADER));
+
+    // Load Color Table
+    file.seekg(BITMAP_FILEHEADER_SIZE+m_bitmap_header.HeaderSize,std::ios::beg);
+
+    uint32 color_table_size=0;
+    if (m_bitmap_header.BitCount==1) {
+        color_table_size=2;
+    } else if (m_bitmap_header.BitCount==4) {
+        color_table_size=16;
+    } else if (m_bitmap_header.BitCount==8) {
+        color_table_size=256;
+    }
+
+    // Always allocate full sized color table
+    BGRA* color_table = new BGRA[color_table_size];
+
+    file.read((char *)color_table,sizeof(BGRA)*m_bitmap_header.ClrUsed);
+    m_bitmap_size=get_width()*get_height();
+    m_bitmap_data=new RGBA[m_bitmap_size];
+
+    uint32 line_width=((get_width()*get_bit_count()/8)+3)&~3;
+    uint8* line=new uint8[line_width];
+
+    file.seekg(m_bitmap_file_header.BitsOffset,std::ios::beg);
+
+    sint32 index=0;
+
+    ImgResult result=IMGR_OK;
+
+    if (m_bitmap_header.Compression==0) {
+        for (uint32 y=0;y<get_height();y++) {
+            file.read((char *)line,line_width);
+
+            uint8 * line_ptr=line;
+
+            for (uint32 x=0;x<get_width();x++) {
+                if (m_bitmap_header.BitCount==1) {
+                    uint32 Color=*((uint8*)line_ptr);
+                    for (int k=0;k<8;k++) {
+                        m_bitmap_data[index].Red=color_table[Color&0x80?1:0].Red;
+                        m_bitmap_data[index].Green=color_table[Color&0x80?1:0].Green;
+                        m_bitmap_data[index].Blue=color_table[Color&0x80?1:0].Blue;
+                        m_bitmap_data[index].Alpha=color_table[Color&0x80?1:0].Alpha;
+                        index++;
+                        Color<<=1;
+                    }
+                    line_ptr++;
+                    x+=7;
+                } else if (m_bitmap_header.BitCount==4) {
+                    uint32 Color=*((uint8*)line_ptr);
+                    m_bitmap_data[index].Red=color_table[(Color>>4)&0x0f].Red;
+                    m_bitmap_data[index].Green=color_table[(Color>>4)&0x0f].Green;
+                    m_bitmap_data[index].Blue=color_table[(Color>>4)&0x0f].Blue;
+                    m_bitmap_data[index].Alpha=color_table[(Color>>4)&0x0f].Alpha;
+                    index++;
+                    m_bitmap_data[index].Red=color_table[Color & 0x0f].Red;
+                    m_bitmap_data[index].Green=color_table[Color & 0x0f].Green;
+                    m_bitmap_data[index].Blue=color_table[Color & 0x0f].Blue;
+                    m_bitmap_data[index].Alpha=color_table[Color & 0x0f].Alpha;
+                    index++;
+                    line_ptr++;
+                    x++;
+                } else if (m_bitmap_header.BitCount==8) {
+                    uint32 Color=*((uint8*)line_ptr);
+                    m_bitmap_data[index].Red=color_table[Color].Red;
+                    m_bitmap_data[index].Green=color_table[Color].Green;
+                    m_bitmap_data[index].Blue=color_table[Color].Blue;
+                    m_bitmap_data[index].Alpha=color_table[Color].Alpha;
+                    index++;
+                    line_ptr++;
+                } else if (m_bitmap_header.BitCount==16) {
+                    uint32 Color = *((uint16*) line_ptr);
+                    m_bitmap_data[index].Red=((Color >> 10) & 0x1f) << 3;
+                    m_bitmap_data[index].Green=((Color >> 5) & 0x1f) << 3;
+                    m_bitmap_data[index].Blue=(Color & 0x1f) << 3;
+                    m_bitmap_data[index].Alpha=255;
+                    index++;
+                    line_ptr+=2;
+                } else if (m_bitmap_header.BitCount==24) {
+                    uint32 Color=*((uint32*)line_ptr);
+                    m_bitmap_data[index].Red=(Color>>16)&0xff;
+                    m_bitmap_data[index].Green=(Color>>8)&0xff;
+                    m_bitmap_data[index].Blue=Color&0xff;
+                    m_bitmap_data[index].Alpha=255;
+                    index++;
+                    line_ptr+=3;
+                } else if (m_bitmap_header.BitCount==32) {
+                    uint32 Color=*((uint32*)line_ptr);
+                    m_bitmap_data[index].Alpha=(Color>>24)&0xff;
+                    m_bitmap_data[index].Red=(Color>>16)&0xff;
+                    m_bitmap_data[index].Green=(Color>>8)&0xff;
+                    m_bitmap_data[index].Blue=Color&0xff;
+                    index++;
+                    line_ptr+=4;
+                }
+            }
+        }
+    } else if (m_bitmap_header.Compression==1) {
+        // RLE Compression
+        uint8 Count=0;
+        uint8 color_index=0;
+        int x=0,y=0;
+        while (file.eof()==false) {
+            file.read((char *)&Count,sizeof(uint8));
+            file.read((char *)&color_index,sizeof(uint8));
+
+            if (Count>0) {
+                index=x+y*get_width();
+                for (int k=0;k<Count;k++) {
+                    m_bitmap_data[index+k].Red=color_table[color_index].Red;
+                    m_bitmap_data[index+k].Green=color_table[color_index].Green;
+                    m_bitmap_data[index+k].Blue=color_table[color_index].Blue;
+                    m_bitmap_data[index+k].Alpha=color_table[color_index].Alpha;
+                }
+                x+=Count;
+            } else if (Count==0) {
+                int flag=color_index;
+                if (flag==0) {
+                    x=0;
+                    y++;
+                } else if (flag==1) {
+                    break;
+                } else if (flag==2) {
+                    char rx=file.get();
+                    char ry=file.get();
+                    x+=rx;
+                    y+=ry;
+                } else {
+                    Count=flag;
+                    index=x+y*get_width();
+                    for (int k=0;k<Count;k++) {
+                        color_index=file.get();
+                        m_bitmap_data[index+k].Red=color_table[color_index].Red;
+                        m_bitmap_data[index+k].Green=color_table[color_index].Green;
+                        m_bitmap_data[index+k].Blue=color_table[color_index].Blue;
+                        m_bitmap_data[index+k].Alpha=color_table[color_index].Alpha;
+                    }
+                    x+=Count;
+                    // Attention: Current Microsoft STL implementation seems to be buggy, tellg() always returns 0.
+                    if (file.tellg()&1) {
+                        file.seekg(1,std::ios::cur);
+                    }
+                }
+            }
+        }
+    } else if (m_bitmap_header.Compression==2) {
+        // RLE 4 - unsupported
+        result=IMGR_UNSUPPORTED_FORMAT;
+    } else if (m_bitmap_header.Compression==3) {
+        // BITFIELDS
+        // We assumes that mask of each color component can be in any order
+        uint32 bit_count_red = color::bit_count_by_mask(m_bitmap_header.RedMask);
+        uint32 bit_count_green = color::bit_count_by_mask(m_bitmap_header.GreenMask);
+        uint32 bit_count_blue = color::bit_count_by_mask(m_bitmap_header.BlueMask);
+        uint32 bit_count_alpha = color::bit_count_by_mask(m_bitmap_header.AlphaMask);
+
+        for (uint32 y=0;y<get_height();y++) {
+            file.read((char *)line,line_width);
+            uint8* line_ptr=line;
+
+            for (unsigned int x=0;x<get_width();x++) {
+                uint32 Color=0;
+                if (m_bitmap_header.BitCount==16) {
+                    Color=*((uint16*)line_ptr);
+                    line_ptr+=2;
+                } else if (m_bitmap_header.BitCount==32) {
+                    Color=*((uint32*)line_ptr);
+                    line_ptr+=4;
+                } else {
+                    // Other bitcounts are unsupported
+                    result=IMGR_UNSUPPORTED_FORMAT;
+                }
+                m_bitmap_data[index].Red=color::convert(color::component_by_mask(Color,m_bitmap_header.RedMask),bit_count_red,8);
+                m_bitmap_data[index].Green=color::convert(color::component_by_mask(Color,m_bitmap_header.GreenMask),bit_count_green,8);
+                m_bitmap_data[index].Blue=color::convert(color::component_by_mask(Color,m_bitmap_header.BlueMask),bit_count_blue,8);
+                m_bitmap_data[index].Alpha=color::convert(color::component_by_mask(Color,m_bitmap_header.AlphaMask),bit_count_alpha,8);
+                index++;
+            }
+        }
+    }
+    delete color_table;
+    delete line;
+    file.close();
+    if (m_bitmap_header.Height>0){
+        // Bitmaps are inverted by default, uninvert the bitmap
+        for (int yi=0;yi<m_bitmap_header.Height/2;yi++) {
+            for (int xi=0;xi<m_bitmap_header.Width;xi++) {
+                int ui=yi*m_bitmap_header.Width+xi;
+                int vi=(m_bitmap_header.Height-yi-1)*m_bitmap_header.Width+xi;
+                RGBA val=m_bitmap_data[ui];
+                m_bitmap_data[ui]=m_bitmap_data[vi];
+                m_bitmap_data[vi]=val;
+            }
+        }
+    }
+    return result;
+}
+
+bool img_loader::get_bits_with_palette(void* Buffer, uint32 &Size, uint32 BitCount, BGRA* &Palette, uint32 &PaletteSize, bool OptimalPalette, bool IncludePadding) {
+	bool Result = false;
+
+	if (BitCount > 16) {
+		return false;
+	}
+
+	unsigned int w = get_width();
+	unsigned int dataBytesPerLine = (w * BitCount + 7) / 8;
+	unsigned int LineWidth = (dataBytesPerLine + 3) & ~3;
+
+	if (Size == 0 || Buffer == 0) {
+		Size = (LineWidth * get_height() * BitCount) / 8;
+		return true;
+	}
+
+
+	if (OptimalPalette) {
+		PaletteSize = 0;
+		// Not implemented
+	} else {
+		if (BitCount == 1) {
+			PaletteSize = 2;
+			// Not implemented: Who need that?
+		} else if (BitCount == 4) { // 2:2:1
+			PaletteSize = 16;
+			Palette = new BGRA[PaletteSize];
+			for (int r = 0; r < 4; r++) {
+				for (int g = 0; g < 2; g++) {
+					for (int b = 0; b < 2; b++) {
+						Palette[r | g << 2 | b << 3].Red = r ? (r << 6) | 0x3f : 0;
+						Palette[r | g << 2 | b << 3].Green = g ? (g << 7) | 0x7f : 0;
+						Palette[r | g << 2 | b << 3].Blue = b ? (b << 7) | 0x7f : 0;
+						Palette[r | g << 2 | b << 3].Alpha = 0xff;
+					}
+				}
+			}
+		} else if (BitCount == 8) { // 3:3:2
+			PaletteSize = 256;
+			Palette = new BGRA[PaletteSize];
+			for (int r = 0; r < 8; r++) {
+				for (int g = 0; g < 8; g++) {
+					for (int b = 0; b < 4; b++) {
+						Palette[r | g << 3 | b << 6].Red = r ? (r << 5) | 0x1f : 0;
+						Palette[r | g << 3 | b << 6].Green = g ? (g << 5) | 0x1f : 0;
+						Palette[r | g << 3 | b << 6].Blue = b ? (b << 6) | 0x3f : 0;
+						Palette[r | g << 3 | b << 6].Alpha = 0xff;
+					}
+				}
+			}
+		} else if (BitCount == 16) { // 5:5:5
+			// Not implemented
+		}
+	}
+
+	unsigned int j = 0;
+	uint8* BufferPtr = (uint8*) Buffer;
+
+	for (uint32 i = 0; i < (uint32)m_bitmap_size; i++) {
+		if (BitCount == 1) {
+			// Not implemented: Who needs that?
+		} else if (BitCount == 4) {
+			*BufferPtr = ((m_bitmap_data[i].Red >> 6) | (m_bitmap_data[i].Green >> 7) << 2 | (m_bitmap_data[i].Blue >> 7) << 3) << 4;
+			i++;
+			*BufferPtr |= (m_bitmap_data[i].Red >> 6) | (m_bitmap_data[i].Green >> 7) << 2 | (m_bitmap_data[i].Blue >> 7) << 3;
+		} else if (BitCount == 8) {
+			*BufferPtr = (m_bitmap_data[i].Red >> 5) | (m_bitmap_data[i].Green >> 5) << 3 | (m_bitmap_data[i].Blue >> 5) << 6;
+		} else if (BitCount == 16) {
+			// Not implemented
+		}
+
+		if (IncludePadding) {
+			j++;
+			if (j >= w) {
+				for (unsigned int k = 0; k < (LineWidth - dataBytesPerLine); k++) {
+					BufferPtr += BitCount / 8;
+				}
+				j = 0;
+			}
+		}
+
+		BufferPtr++;
+	}
+
+	Result = true;
+
+	return Result;
+}
+
+bool img_loader::save_BMP(char * filename,uint32 BitCount) {
+    bool result=true;
+    std::ofstream file(filename, std::ios::out | std::ios::binary);
+
+    if (file.is_open()==false) {
+        return false;
+    }
+    BITMAP_FILEHEADER bfh;
+    BITMAP_HEADER bh;
+    memset(&bfh,0,sizeof(bfh));
+    memset(&bh,0,sizeof(bh));
+
+    bfh.Signature=BITMAP_SIGNATURE;
+    bfh.BitsOffset=BITMAP_FILEHEADER_SIZE+sizeof(BITMAP_HEADER);
+    bfh.Size=(get_width()*get_height()*BitCount)/8+bfh.BitsOffset;
+
+    bh.HeaderSize=sizeof(BITMAP_HEADER);
+    bh.BitCount=BitCount;
+
+    if (BitCount==32) {
+        bh.Compression=3;
+        bh.AlphaMask    = 0xff000000;
+        bh.RedMask      = 0x00ff0000;
+        bh.GreenMask    = 0x0000ff00;
+        bh.BlueMask     = 0x000000ff;
+    } else if (BitCount==16) {
+        bh.Compression=3;
+        bh.AlphaMask    = 0x00000000;
+        bh.RedMask      = 0x0000001f;
+        bh.GreenMask    = 0x000007E0;
+        bh.BlueMask     = 0x0000F800;
+    } else {
+        bh.Compression=0;
+    }
+
+    unsigned int line_width=(get_width()+3)&~3;
+
+    bh.Planes=1;
+    bh.Height=get_height();
+    bh.Width=get_width();
+    bh.SizeImage=(line_width*BitCount*get_height())/8;
+    bh.PelsPerMeterX=3780;
+    bh.PelsPerMeterY=3780;
+
+    if (BitCount==32) {
+        file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER));
+        file.write((char*) &bh, sizeof(BITMAP_HEADER));
+        file.write((char*) m_bitmap_data, bh.SizeImage);
+    } else if (BitCount==16) {
+        uint8* Bitmap = new uint8[bh.SizeImage];
+        BGRA *Palette = 0;
+        uint32 PaletteSize = 0;
+
+        if (get_bits_with_palette(Bitmap, bh.SizeImage, BitCount, Palette, PaletteSize)) {
+            bfh.BitsOffset += PaletteSize * sizeof(BGRA);
+            file.write((char*) &bfh, BITMAP_FILEHEADER_SIZE);
+            file.write((char*) &bh, sizeof(BITMAP_HEADER));
+            file.write((char*) Palette, PaletteSize * sizeof(BGRA));
+            file.write((char*) Bitmap, bh.SizeImage);
+        }
+        delete [] Bitmap;
+        delete [] Palette;
+    } else {
+        uint32 RedMask = 0;
+        uint32 GreenMask = 0;
+        uint32 BlueMask = 0;
+        uint32 AlphaMask = 0;
+
+        if (BitCount == 16) {
+            RedMask     = 0x0000F800;
+            GreenMask   = 0x000007E0;
+            BlueMask    = 0x0000001F;
+            AlphaMask   = 0x00000000;
+        } else if (BitCount==24) {
+            RedMask = 0x00FF0000;
+            GreenMask = 0x0000FF00;
+            BlueMask = 0x000000FF;
+        } else {
+            result=false;
+        }
+        if (result) {
+            if (get_bits(NULL, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) {
+                uint8* Bitmap = new uint8[bh.SizeImage];
+                if (get_bits(Bitmap, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) {
+					file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER));
+					file.write((char*) &bh, sizeof(BITMAP_HEADER));
+					file.write((char*) Bitmap, bh.SizeImage);
+				}
+				delete [] Bitmap;
+            }
+        }
+    }
+    file.close();
+    return result;
+}
+
+bool img_loader::save_PNG(char * filename)
+{
+	return (bool)write_png(filename, (uint8*)m_bitmap_data, get_width(), get_height(), get_bit_count());
+
+}
+
+bool img_loader::save_PXM(char * filename, int level)
+{
+	FILE *f=fopen(filename,"wb");
+	if (f==NULL) {
+        return false;
+	}
+	fprintf(f,"P%d\n#Simutrans PxM Writer\n%d\n%d\n",level,get_width(),get_height());
+	if (level!=1&&level!=4) {
+        fprintf(f,"255\n");
+	}
+	if (level<=6) {
+        for (uint32 y=0;y<get_height();y++) {
+            for (uint32 x=0;x<get_width();x++) {
+                uint32 location=y*get_width()+x;
+                if (level==1) {
+                    int v=m_bitmap_data[location].Red+m_bitmap_data[location].Green+m_bitmap_data[location].Blue;
+                    if (v>384) {
+                        fprintf(f,"1 ");
+                    } else {
+                        fprintf(f,"0 ");
+                    }
+                } else if (level==2) {
+                    int v=(m_bitmap_data[location].Red+m_bitmap_data[location].Green+m_bitmap_data[location].Blue)/3;
+                    if (v>255) {
+                        v=255;
+                    }
+                    fprintf(f,"%d ",v);
+                } else if (level==3) {
+                    fprintf(f,"%d %d %d\t",m_bitmap_data[location].Red,m_bitmap_data[location].Green,m_bitmap_data[location].Blue);
+                } else if (level==4) {
+                    uint8 val=0;
+                    for (int x2=0;x2<8;x2++) {
+                        val=val<<1;
+                        int v=m_bitmap_data[location+x2].Red+m_bitmap_data[location+x2].Green+m_bitmap_data[location+x2].Blue;
+                        if (v>384) {
+                            val+=1;
+                        }
+
+                    }
+                    fputc(val,f);
+                    x+=7;
+                } else if (level==5) {
+                    int v=(m_bitmap_data[location].Red+m_bitmap_data[location].Green+m_bitmap_data[location].Blue)/3;
+                    if (v>255) {
+                        v=255;
+                    }
+                    fputc(v,f);
+                } else if (level==6) {
+                    fputc(m_bitmap_data[location].Red,f);
+                    fputc(m_bitmap_data[location].Green,f);
+                    fputc(m_bitmap_data[location].Blue,f);
+                }
+            }
+            if (level<4) {
+                fprintf(f,"\n");
+            }
+        }
+	}
+	return false;
+}
+
+bool img_loader::is_greyscale(void)
+{
+	return m_greyscale;
+}
+
+ImgResult img_loader::load_png(const char *filename) {
+    unsigned char **block=new unsigned char * [1];
+    block[0]=(unsigned char *)malloc(1);
+    uint32 width=0;
+    uint32 height=0;
+    uint32 base_img_size=1;
+    if (!load_block(block,&width,&height,filename,base_img_size)) {
+        return IMGR_UNKNOWN_ERROR;
+    }
+    this->set_bits(block[0],width,height,0x0000FF00,0x00FF0000,0xFF000000,0x000000FF);
+    return IMGR_OK;
+}
+
+uint32 img_loader::read_next_number_pxm(std::ifstream& file) {
+    char c=file.get();
+    while ((c<'0')||(c>'9')) {
+        // If there is a # then the line is a comment - read to end of line
+        if (c=='#') {
+            while (c!='\n') {
+                c=file.get();
+                if (file.fail()) {
+                    return -1;
+                }
+            }
+            if (file.fail()) {
+                return -1;
+            }
+        }
+        // get next character
+        c=file.get();
+    }
+    uint32 ret_val=0;
+    while ((c>='0')&&(c<='9')) {
+        ret_val*=10;
+        ret_val+=(c-'0');
+        if (file.fail()) {
+            return ret_val;
+        }
+        c=file.get();
+    }
+    file.unget();
+    return ret_val;
+}
+
+inline sint32 img_loader::standardize_number_pxm(sint32 val, sint32 maxval) {
+    if (maxval==255) {
+        return val;
+    } else if (maxval<255) {
+        return val*255/maxval;
+    } else {
+        int dif=maxval/256;
+        int ret=val/dif;
+        if (ret>255) {
+            return 255;
+        }
+        return ret;
+    }
+}
+
+ImgResult img_loader::load_pxm(const char* filename) {
+    std::ifstream file(filename, std::ios::binary | std::ios::in);
+    char signature[3]={0,0,0};
+    file.read(signature,2);
+    // convert second character of signature to level
+    uint8 level=signature[1]-'0';
+    if ((level<1)||(level>6)) {
+        // should never get here, as the value is checked before entering the function.
+        return IMGR_INVALID_FORMAT;
+    }
+
+    //char buffer[256];
+    bool binary_data=(level>=4);
+
+    // Read in the width and height of the image
+    int width=read_next_number_pxm(file);
+    int height=read_next_number_pxm(file);
+
+    // If width or height are negative an error has occured.
+    if ((width<0)||(height<0)) {
+        return IMGR_INVALID_FORMAT;
+    }
+
+    int maxval=1;
+    // If image is not Black and White read in the max value (can be up to 65535)
+    if ((level!=1)&&(level!=4)) {
+        maxval=read_next_number_pxm(file);
+    }
+    // Read in and check that we have a whitespace character
+    char c=file.get();
+    if ((c!=' ')&&(c!='\t')&&(c!='\n')&&(c!='\r')) {
+        return IMGR_INVALID_FORMAT;
+    }
+    m_bitmap_header.Width=width;
+    m_bitmap_header.Height=height;
+    m_bitmap_header.BitCount=32;
+    m_bitmap_header.Compression=3;
+    m_bitmap_size=width*height;
+
+    // Alocate space for bitmap data
+    m_bitmap_data=new RGBA[m_bitmap_size];
+
+    if (binary_data) {
+        // Read in Binary Data
+        if (level==4) {
+            // Black and white image encoded to individual bits, padded to a full byte for each line
+            int line_len=(width+7)/8;
+            char *buffer=new char [line_len];
+            for (int y=0;y<height;y++) {
+                file.read(buffer,line_len);
+                int x1=0;
+                for (int x=0;x<line_len;x++) {
+                    int location=y*width+x1;
+                    for (int i=7;i>=0;i--) {
+                        if (x1<width) {
+                            // Black and white so options are 255 or 0
+                            if ((buffer[x]&(1<<i))==1) {
+                                m_bitmap_data[location].Red=255;
+                                m_bitmap_data[location].Green=255;
+                                m_bitmap_data[location].Blue=255;
+                            } else {
+                                m_bitmap_data[location].Red=0;
+                                m_bitmap_data[location].Green=0;
+                                m_bitmap_data[location].Blue=0;
+                            }
+                            m_bitmap_data[location].Alpha=0;
+                            x1++;
+                        }
+                    }
+                }
+            }
+        } else {
+            // Read in a color or greyscale image
+            for (int y=0;y<height;y++) {
+                for (int x=0;x<width;x++) {
+                    int r=file.get();
+                    int g=0;
+                    int b=0;
+                    if (maxval>255) {
+                        r*=256;
+                        r+=file.get();
+                    }
+                    r=standardize_number_pxm(r,maxval);
+                    if (level==5) {
+                        // If greyscale green and blue are the same value as red
+                        g=r;
+                        b=r;
+                    } else {
+                        // If color, read in green and blue values
+                        g=file.get();
+                        if (maxval>255) {
+                            g*=256;
+                            g+=file.get();
+                        }
+                        b=file.get();
+                        if (maxval>255) {
+                            b*=256;
+                            b+=file.get();
+                        }
+                        g=standardize_number_pxm(g,maxval);
+                        b=standardize_number_pxm(b,maxval);
+                    }
+                    int location=y*width+x;
+                    m_bitmap_data[location].Red=r;
+                    m_bitmap_data[location].Green=g;
+                    m_bitmap_data[location].Blue=b;
+                    m_bitmap_data[location].Alpha=0;
+                }
+            }
+        }
+    } else {
+        // Read in ASCII Data
+        for (int y=0;y<height;y++) {
+            for (int x=0;x<width;x++) {
+                int location=y*width+x;
+                if (level==3) {
+                    // If color, read in Red, Green and Blue
+                    int R=standardize_number_pxm(read_next_number_pxm(file),maxval);
+                    int G=standardize_number_pxm(read_next_number_pxm(file),maxval);
+                    int B=standardize_number_pxm(read_next_number_pxm(file),maxval);
+                    m_bitmap_data[location].Red=R;
+                    m_bitmap_data[location].Green=G;
+                    m_bitmap_data[location].Blue=B;
+                    m_bitmap_data[location].Alpha=0;
+                } else {
+                    // Otherwise Red Green and Blue are the same value, so only read in 1 value
+                    int R=standardize_number_pxm(read_next_number_pxm(file),maxval);
+                    m_bitmap_data[location].Red=R;
+                    m_bitmap_data[location].Green=R;
+                    m_bitmap_data[location].Blue=R;
+                    m_bitmap_data[location].Alpha=0;
+                }
+            }
+        }
+    }
+    return IMGR_OK;
+}
+
+bool img_loader::set_bits(void *buffer, uint32 width, uint32 height, uint32 red_mask, uint32 green_mask, uint32 blue_mask,uint32 alpha_mask) {
+    if (buffer==NULL) {
+        return false;
+    }
+
+    uint8 * buffer_ptr=(uint8*)buffer;
+
+    dispose();
+
+    m_bitmap_header.Width=width;
+    m_bitmap_header.Height=height;
+    m_bitmap_header.BitCount=32;
+    m_bitmap_header.Compression=3;
+
+    m_bitmap_size=get_width()*get_height();
+    m_bitmap_data=new RGBA[m_bitmap_size];
+
+    unsigned int bit_count = (color::bit_count_by_mask(red_mask | green_mask | blue_mask | alpha_mask) + 7) & ~7;
+
+    uint32 bit_count_red = color::bit_count_by_mask(red_mask);
+    uint32 bit_count_green = color::bit_count_by_mask(green_mask);
+    uint32 bit_count_blue = color::bit_count_by_mask(blue_mask);
+    uint32 bit_count_alpha = color::bit_count_by_mask(alpha_mask);
+
+    for (uint32 i=0;i<(uint32)m_bitmap_size;i++) {
+        uint32 color=0;
+        if (bit_count<=8) {
+            color=*((uint8*)buffer_ptr);
+            buffer_ptr++;
+        } else if (bit_count<=16) {
+            color=*((uint16*)buffer_ptr);
+            buffer_ptr+=2;
+        } else if (bit_count<=24) {
+            color=*((uint32*)buffer_ptr);
+            buffer_ptr+=3;
+        } else if (bit_count<=32) {
+            color=*((uint32*)buffer_ptr);
+            buffer_ptr+=4;
+        } else {
+            // Unsupported
+            buffer_ptr++;
+        }
+        m_bitmap_data[i].Alpha=color::convert(color::component_by_mask(color,alpha_mask),bit_count_alpha,8);
+        m_bitmap_data[i].Red=color::convert(color::component_by_mask(color,red_mask),bit_count_red,8);
+        m_bitmap_data[i].Green=color::convert(color::component_by_mask(color,green_mask),bit_count_green,8);
+        m_bitmap_data[i].Blue=color::convert(color::component_by_mask(color,blue_mask),bit_count_blue,8);
+    }
+    return true;
+}
+
+uint32 img_loader::get_width(void) {
+    if (abs(m_bitmap_header.Width) > 8192) {
+        m_bitmap_header.Width=8192;
+    }
+    return m_bitmap_header.Width<0?-m_bitmap_header.Width:m_bitmap_header.Width;
+}
+
+uint32 img_loader::get_height(void) {
+    if (abs(m_bitmap_header.Height) > 8192) {
+        m_bitmap_header.Height=8192;
+    }
+    return m_bitmap_header.Height<0?-m_bitmap_header.Height:m_bitmap_header.Height;
+}
+
+inline uint32 img_loader::get_bit_count() {
+    return m_bitmap_header.BitCount;
+}
+
+
+
+inline uint32 img_loader::color::bit_count_by_mask(uint32 mask) {
+    uint32 bit_count=0;
+    while (mask) {
+        mask&=mask-1;
+        bit_count++;
+    }
+    return bit_count;
+}
+
+
+inline uint32 img_loader::color::bit_position_by_mask(uint32 mask) {
+    return bit_count_by_mask((mask & (~mask + 1)) - 1);
+}
+
+inline uint32 img_loader::color::component_by_mask(uint32 color, uint32 mask) {
+    uint32 component=color&mask;
+    return component>>bit_position_by_mask(mask);
+}
+
+inline uint32 img_loader::color::bit_count_to_mask(uint32 bit_count) {
+    return (bit_count == 32)?0xFFFFFFFF:(1<<bit_count)-1;
+}
+
+uint32 img_loader::color::convert(uint32 color,uint32 from_bit_count,uint32 to_bit_count) {
+    if (to_bit_count<from_bit_count) {
+        color >>= (from_bit_count-to_bit_count);
+    } else {
+        color <<= (to_bit_count-from_bit_count);
+        if (color>0) {
+            color|=bit_count_to_mask(to_bit_count-from_bit_count);
+        }
+    }
+    return color;
+}
Index: simutrans/trunk/utils/imgloader.h
===================================================================
--- simutrans/trunk/utils/imgloader.h	(nonexistent)
+++ simutrans/trunk/utils/imgloader.h	(working copy)
@@ -0,0 +1,213 @@
+#include "../simtypes.h"
+#ifndef IMGLOADER_H
+#define IMGLOADER_H
+
+/**
+ * \enum ImgResult
+ * ImgResult is for storing return values from the various functions in the img_loader class
+ */
+enum ImgResult {
+    IMGR_OK,                    /// Image Successfully Loaded
+    IMGR_NULL,                  /// NULL value passed
+    IMGR_FILE_DOES_NOT_EXIST,   /// File refered to does not exist
+    IMGR_UNABLE_TO_OPEN,        /// File refered to exists but is not able to be opened
+    IMGR_UNSUPPORTED_FORMAT,    /// File refered to exists but is in an unsupported format
+    IMGR_INVALID_FORMAT,        /// File refered to exists and indicates it is a supported format, but is not
+    IMGR_UNKNOWN_ERROR          /// An unknown error occured...
+};
+
+#ifndef __LITTLE_ENDIAN__
+	#ifndef __BIG_ENDIAN__
+		#define __LITTLE_ENDIAN__
+	#endif
+#endif
+
+#ifdef __LITTLE_ENDIAN__
+	#define BITMAP_SIGNATURE 0x4d42
+#else
+	#define BITMAP_SIGNATURE 0x424d
+#endif
+
+#pragma pack(push, 1)
+typedef struct _BITMAP_FILEHEADER {
+    uint16 Signature;
+    uint32 Size;
+    uint32 Reserved;
+    uint32 BitsOffset;
+} BITMAP_FILEHEADER;
+
+const int BITMAP_FILEHEADER_SIZE=14;
+
+typedef struct _BITMAP_HEADER {
+    uint32 HeaderSize;
+	sint32 Width;
+	sint32 Height;
+	uint16 Planes;
+	uint16 BitCount;
+	uint32 Compression;
+	uint32 SizeImage;
+	sint32 PelsPerMeterX;
+	sint32 PelsPerMeterY;
+	uint32 ClrUsed;
+	uint32 ClrImportant;
+	uint32 RedMask;
+	uint32 GreenMask;
+	uint32 BlueMask;
+	uint32 AlphaMask;
+	uint32 CsType;
+	uint32 Endpoints[9]; // see http://msdn2.microsoft.com/en-us/library/ms536569.aspx
+	uint32 GammaRed;
+	uint32 GammaGreen;
+	uint32 GammaBlue;
+} BITMAP_HEADER;
+
+typedef struct _RGBA {
+	uint8 Red;
+	uint8 Green;
+	uint8 Blue;
+	uint8 Alpha;
+} RGBA;
+
+typedef struct _BGRA {
+	uint8 Blue;
+	uint8 Green;
+	uint8 Red;
+	uint8 Alpha;
+} BGRA;
+
+#pragma pack(pop)
+
+/**
+ * \class img_loader
+ * The img_loader class is for the loading of images. It currently supports most BMP & PBM formats, and all PNG formats.
+ */
+class img_loader {
+    public:
+        /**
+         * img_loader constructor
+         * @param filename is an optional filename parameter to load an image.
+         */
+        img_loader(const char *filename=NULL);
+        ~img_loader();
+        /**
+         * load_image
+         * @param filename is the name/path to the file to load.
+         * @return Returns an ImgResult enum indicating the result of the attempt to load the file.
+         */
+        ImgResult load_image(const char *filename);
+        /**
+         * get_bits
+         * @return returns a void * array pointing to the ARGB buffer of this image.
+         */
+        void * get_bits();
+        /**
+         * get_bits
+         * @param buffer is a buffer for the image to be loaded into.
+         * @param buffer_size is the size of the buffer passed in
+         * @param red_mask is the mask that should be used for the red bits
+         * @param green_mask is the mask that should be used for the green bits
+         * @param blue_mask is the mask that should be used for the blue bits
+         * @param alpha_mask is an option mask that should be used for the alpha bits (defaults to 0)
+         * @param include_padding is an option to include padding on the image (defaults to false)
+         * @return Returns an ImgResult enum indicating the result of the attempt to load the file.
+         * Get Bits returns the image data in the format requested
+         */
+        ImgResult get_bits(void *buffer, uint32 &buffer_size, uint32 red_mask, uint32 green_mask,uint32 blue_mask,uint32 alpha_mask=0,bool include_padding=false);
+
+        /**
+         * set_bits
+         * @param buffer is a buffer to load the bits from
+         * @param width is the width of the image
+         * @param height is the height of the image
+         * @param red_mask is the mask that should be used for the red bits
+         * @param green_mask is the mask that should be used for the green bits
+         * @param blue_mask is the mask that should be used for the blue bits
+         * @param alpha_mask is an option mask that should be used for the alpha bits (defaults to 0)
+         * @return returns true on success, false of failure
+         * Set Bits sets the data from the format specified
+         */
+        bool set_bits(void *buffer, uint32 width, uint32 height, uint32 red_mask, uint32 green_mask, uint32 blue_mask,uint32 alpha_mask=0);
+
+        /**
+         * dispose
+         * Disposes of current Bitmap Data
+         */
+        void dispose(void);
+
+        /**
+         * save_BMP
+         * @param filename is the name to save the file as
+         * @param BitCount to save as, defaults to 32
+         * @return true on success, false on failure
+         * Saves the image as a BMP file
+         */
+        bool save_BMP(char * filename, uint32 BitCount=32);
+
+        /**
+         * save_PNG
+         * @param filename is the name to save the file as
+		 * @return true on success, false on failure
+         * Saves the image as a PNG file
+         */
+        bool save_PNG(char * filename);
+
+        /**
+         * save_PBM
+         * @param filename is the name to save the file as
+         * @param level is the type of PBM to save as (defaults to P6)
+		 * @return true on success, false on failure
+         * Saves the image as a PBM file
+         */
+        bool save_PXM(char * filename,int level=6);
+
+        /**
+         * is_greyscale
+         * @return Returns true if the image is Greyscale, false otherwise
+         * Returns true if the image is greyscale
+         */
+        bool is_greyscale(void);
+
+        /**
+         * get_width
+         * @return returns the width of the image
+         * Returns the width of the image - where no image is loaded, it will return 0
+         */
+        uint32 get_width(void);
+
+        /**
+         * get_height
+         * @return returns the height of the image
+         * Returns the height of the image - where no image is loaded, it will return 0
+         */
+        uint32 get_height(void);
+
+        /**
+         * get_bit_count
+         * @return returns the bit_count of the image
+         * Returns the bit_count of the image - where no image is loaded, it will return 0
+         */
+        uint32 get_bit_count(void);
+
+        class color {
+        public:
+            static uint32 bit_count_by_mask(uint32 mask);
+            static uint32 bit_position_by_mask(uint32 mask);
+            static uint32 component_by_mask(uint32 color, uint32 mask);
+            static uint32 bit_count_to_mask(uint32 bit_count);
+            static uint32 convert(uint32 color, uint32 from_bit_count, uint32 to_bit_count);
+        };
+	private:
+        ImgResult load_bmp(const char *filename);
+        ImgResult load_png(const char *filename);
+        ImgResult load_pxm(const char *filename);
+        uint32 read_next_number_pxm(std::ifstream& file);
+        sint32 standardize_number_pxm(sint32 val, sint32 maxval);
+        bool get_bits_with_palette(void* Buffer, uint32 &Size, uint32 BitCount, BGRA* &Palette, uint32 &PaletteSize, bool OptimalPalette=false, bool IncludePadding=true);
+        BITMAP_FILEHEADER m_bitmap_file_header;
+        BITMAP_HEADER m_bitmap_header;
+        RGBA *m_bitmap_data;
+        sint32 m_bitmap_size;
+        sint8 m_greyscale;
+
+};
+#endif
