1 module converter; 2 3 //import imageformats; 4 5 import PixelPerfectEngine.graphics.bitmap; 6 import PixelPerfectEngine.extbmp.extbmp; 7 import PixelPerfectEngine.system.exc; 8 import PixelPerfectEngine.system.etc; 9 import PixelPerfectEngine.map.mapload; 10 11 import derelict.freeimage.freeimage; 12 //import derelict.freeimage.functions; 13 import derelict.freeimage.types; 14 15 import std.stdio; 16 import std.path; 17 import std.bitmanip; 18 import std.conv; 19 20 /*Bitmap32Bit import32BitBitmapFromFile(string filename){ 21 22 FREE_IMAGE_FORMAT format; 23 switch(filename[filename.length-3..filename.length]){ 24 case "png": format = FIF_PNG; break; 25 case "tga": format = FIF_TARGA; break; 26 case "bmp": format = FIF_BMP; break; 27 default: break; 28 } 29 30 const char* fn = std.string.toStringz(filename); 31 FIBITMAP* source = FreeImage_Load(format, fn); 32 int iX = FreeImage_GetWidth(source), iY = FreeImage_GetHeight(source); 33 Bitmap32Bit result = new Bitmap32Bit(iX,iY); 34 switch(FreeImage_GetBPP(source)){ 35 case 32: 36 for(int y; y < iY; y++){ 37 for(int x; x < iX; x++){ 38 RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c); 39 result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,c.rgbReserved); 40 //writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,','); 41 } 42 } 43 break; 44 default: 45 for(int y; y < iY; y++){ 46 for(int x; x < iX; x++){ 47 RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c); 48 result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,255); 49 //writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,','); 50 } 51 } 52 break; 53 } 54 55 return result; 56 }*/ 57 58 enum NumberingStyle{ 59 DECIMAL = 0, 60 OCTAL = 1, 61 HEXADECIMAL = 2, 62 CHAR = 3, 63 WCHAR = 4 64 } 65 66 class ImportData{ 67 string[] ID; 68 string bitdepth, format; 69 int x, y, IDpos; 70 ushort paletteOffset; 71 NamingConvention nc; 72 this(string[] ID, string bitdepth, int x, int y, ushort paletteOffset){ 73 this.ID = ID; 74 this.bitdepth = bitdepth; 75 this.x = x; 76 this.y = y; 77 this.paletteOffset = paletteOffset; 78 //this.numOfDigits = numOfDigits; 79 } 80 this(NamingConvention nc, string bitdepth, int x, int y, ushort paletteOffset){ 81 this.nc = nc; 82 this.bitdepth = bitdepth; 83 this.x = x; 84 this.y = y; 85 this.paletteOffset = paletteOffset; 86 //this.numOfDigits = numOfDigits; 87 } 88 string getNextID(){ 89 if(nc is null){ 90 string result = ID[IDpos]; 91 IDpos++; 92 return result; 93 }else{ 94 string result = nc.wordA; 95 switch(nc.incrStyle){ 96 case NumberingStyle.OCTAL: result ~= intToOct(IDpos+nc.startingPoint,nc.format); break; 97 case NumberingStyle.HEXADECIMAL: result ~= intToHex(IDpos+nc.startingPoint,nc.format); break; 98 default: result ~= to!string(IDpos+nc.startingPoint); break; 99 } 100 IDpos++; 101 result ~= nc.wordB; 102 return result; 103 } 104 } 105 bool isMulti(){ 106 if(x > 0 && y > 0) return true; 107 return false; 108 } 109 110 } 111 112 class NamingConvention{ 113 string wordA, wordB; 114 NumberingStyle incrStyle; 115 int startingPoint, format; 116 this(string wordA, string wordB, NumberingStyle incrStyle, int startingPoint, int format){ 117 this.wordA = wordA; 118 this.wordB = wordB; 119 this.incrStyle = incrStyle; 120 this.startingPoint = startingPoint; 121 this.format = format; 122 } 123 } 124 125 public class BitmapInfo{ 126 int width, height; 127 public this(){ 128 129 } 130 } 131 132 public BitmapInfo getBitmapInfo(string path){ 133 import std..string; 134 FREE_IMAGE_FORMAT format; 135 switch(extension(path)){ 136 case ".png": format = FIF_PNG; break; 137 case ".tga": format = FIF_TARGA; break; 138 case ".bmp": format = FIF_BMP; break; 139 default: break; 140 } 141 const char* fn = std..string.toStringz(path); 142 FIBITMAP* source = FreeImage_Load(format, fn); 143 BitmapInfo bi = new BitmapInfo; 144 bi.width = FreeImage_GetWidth(source); 145 bi.height = FreeImage_GetHeight(source); 146 if(source) 147 FreeImage_Unload(source); 148 return bi; 149 } 150 151 public void importDirectlyToXMP(string path, string palette, ExtendibleBitmap target, ImportData id){ 152 import std..string; 153 FREE_IMAGE_FORMAT format; 154 switch(extension(path)){ 155 case ".png": format = FIF_PNG; break; 156 case ".tga": format = FIF_TARGA; break; 157 case ".bmp": format = FIF_BMP; break; 158 default: break; 159 } 160 const char* fn = std..string.toStringz(path); 161 FIBITMAP* source = FreeImage_Load(format, fn); 162 int iX = FreeImage_GetWidth(source), iY = FreeImage_GetHeight(source); 163 ubyte[] raw; ushort[] raw16; 164 switch(id.bitdepth){ 165 case "1bit": 166 BitArray ba = BitArray(cast(void[])raw, 0); 167 ba.length(iX * iY); 168 for(int y; y < iY; y++){ 169 for(int x; x < iX; x++){ 170 ubyte c; FreeImage_GetPixelIndex(source, x, iY - 1 - y, &c); 171 if(c != 0){ 172 ba[x + (iX * y)] = true; 173 } 174 } 175 } 176 break; 177 case "16bit": 178 for(int y; y < iY; y++){ 179 for(int x; x < iX; x++){ 180 ubyte c; FreeImage_GetPixelIndex(source, x, iY - 1 - y, &c); 181 raw16 ~= to!ushort(id.paletteOffset + c); 182 } 183 } 184 break; 185 default: 186 switch(FreeImage_GetBPP(source)){ 187 case 1,2,4,8: 188 for(int y; y < iY; y++){ 189 for(int x; x < iX; x++){ 190 ubyte c; FreeImage_GetPixelIndex(source, x, iY - 1 - y, &c); 191 raw ~= c; 192 } 193 } 194 break; 195 case 32: 196 for(int y; y < iY; y++){ 197 for(int x; x < iX; x++){ 198 RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c); 199 //result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,c.rgbReserved); 200 //writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,','); 201 raw ~= [c.rgbRed,c.rgbGreen,c.rgbBlue,c.rgbReserved]; 202 } 203 } 204 break; 205 default: 206 for(int y; y < iY; y++){ 207 for(int x; x < iX; x++){ 208 RGBQUAD c; FreeImage_GetPixelColor(source, x, iY - 1 - y, &c); 209 //result.writePixel(x,y,c.rgbRed,c.rgbGreen,c.rgbBlue,255); 210 //writeln(c.rgbRed,',',c.rgbGreen,',',c.rgbBlue,',',c.rgbReserved,','); 211 raw ~= [c.rgbRed,c.rgbGreen,c.rgbBlue,255]; 212 } 213 } 214 break; 215 } 216 break; 217 } 218 if(id.isMulti){ 219 if(iX%id.x > 0 || iY%id.y > 0){ 220 throw new BitmapFormatException("Incorrect sizes for slicing!"); 221 } 222 if(id.bitdepth == "16bit"){ 223 //target.addBitmap(raw16,id.x,id.y,id.bitdepth,id.ID[0]); 224 for(int jY; jY < iY / id.y; jY++){ 225 for(int jX; jX < iX / id.x; jX++){ 226 ushort[] raw2; 227 for(int y; y < id.y; y++){ 228 int from = ((jY * id.y * iX) + (y * iX) + (jX * id.x)), t = from + id.x; 229 raw2 ~= raw16[from..t]; 230 } 231 target.addBitmap(raw2,id.x,id.y,id.bitdepth,id.getNextID(),id.format,palette); 232 //si++; 233 } 234 } 235 }else{ 236 int pitch = 1; 237 if(id.bitdepth == "32bit")pitch = 4; 238 for(int jY; jY < iY / id.y; jY++){ 239 for(int jX; jX < iX / id.x; jX++){ 240 ubyte[] raw2; 241 for(int y; y < id.y; y++){ 242 int from = pitch * ((jY * id.y * iX) + (y * iX) + (jX * id.x)), t = from + (id.x * pitch); 243 raw2~= raw[from..t]; 244 } 245 target.addBitmap(raw2,id.x,id.y,id.bitdepth,id.getNextID(),id.format,palette); 246 //si++; 247 } 248 } 249 250 } 251 }else{ 252 if(id.bitdepth == "16bit"){ 253 target.addBitmap(raw16,iX,iY,id.bitdepth,id.ID[0]); 254 }else{ 255 target.addBitmap(raw,iX,iY,id.bitdepth,id.ID[0],id.format); 256 } 257 } 258 if(source) 259 FreeImage_Unload(source); 260 } 261 262 public void importPaletteDirectlyToXMP(string path, ExtendibleBitmap target, string paletteID, ushort offset = 0){ 263 import std..string; 264 FREE_IMAGE_FORMAT format; 265 switch(extension(path)){ 266 case ".png": format = FIF_PNG; break; 267 case ".tga": format = FIF_TARGA; break; 268 case ".bmp": format = FIF_BMP; break; 269 default: break; 270 } 271 const char* fn = std..string.toStringz(path); 272 FIBITMAP* source = FreeImage_Load(format, fn); 273 uint bitdepth = FreeImage_GetBPP(source); 274 275 ubyte[] palette; 276 switch(bitdepth){ 277 case 4: palette.length = 64; break; 278 case 8: palette.length = 1024; break; 279 default: break; 280 } 281 RGBQUAD* colors = FreeImage_GetPalette(source); 282 //RGBQUAD.sizeof; 283 palette[0] = 0; 284 palette[1] = colors.rgbRed; 285 palette[2] = colors.rgbGreen; 286 palette[3] = colors.rgbBlue; 287 for(int i = 4; i < palette.length; i+=4){ 288 colors++; 289 palette[i] = 255; 290 palette[i + 1] = colors.rgbRed; 291 palette[i + 2] = colors.rgbGreen; 292 palette[i + 3] = colors.rgbBlue; 293 294 } 295 target.addPalette(cast(void[])palette, paletteID); 296 if(source) 297 FreeImage_Unload(source); 298 } 299 300 public Bitmap32Bit getBitmapPreview(ExtendibleBitmap xmp, string ID){ 301 Bitmap32Bit result; 302 switch(xmp.getBitDepth(ID)){ 303 case "32bit": 304 result = new Bitmap32Bit(cast(Color[])xmp.getBitmap(ID),xmp.getXsize(ID),xmp.getYsize(ID)); 305 break; 306 case "16bit": 307 ushort[] raw = xmp.get16bitBitmap(ID); 308 Color[] clut = cast(Color[])xmp.getPalette(xmp.getPaletteMode(ID)); 309 Color[] res2; 310 foreach(c; raw){ 311 res2 ~= clut[c]; 312 } 313 result = new Bitmap32Bit(res2,xmp.getXsize(ID),xmp.getYsize(ID)); 314 break; 315 case "8bit": 316 ubyte[] raw = xmp.get8bitBitmap(ID); 317 Color[] clut = cast(Color[])xmp.getPalette(xmp.getPaletteMode(ID)); 318 Color[] res2; 319 foreach(c; raw){ 320 res2 ~= clut[c]; 321 } 322 result = new Bitmap32Bit(res2,xmp.getXsize(ID),xmp.getYsize(ID)); 323 break; 324 default: break; 325 } 326 return result; 327 } 328 329 public void autoloadFromXMP(string filename, ExtendibleMap map, int layerNum){ 330 ExtendibleBitmap xmpFile = new ExtendibleBitmap(filename); 331 map.addFileToTileSource(layerNum, filename); 332 for(int i ; i < xmpFile.bitmapID.length ; i++){ 333 try{ 334 if(xmpFile.bitmapID[i].length <= 4){ 335 throw new Exception(""); 336 } 337 wchar ID = to!wchar(parseHex(xmpFile.bitmapID[i][0..4])); 338 string descr = xmpFile.bitmapID[i].length > 5 ? xmpFile.bitmapID[i][5..xmpFile.bitmapID[i].length] : ""; 339 map.addTileToTileSource(layerNum, ID, descr, xmpFile.bitmapID[i], filename); 340 }catch(Exception e){ 341 writeln("Bitmap \'"~xmpFile.bitmapID[i]~"\' does not follow the format xxxx\\{description} and will be skipped."); 342 } 343 } 344 } 345 346 enum LookupMethod : uint{ 347 NearestValue = 1, 348 Dithering = 2 349 }