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