1 /*
2 Copyright (c) 2013 Andrey Penechko
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license the "Software" to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 module anchovy.graphics.bitmap;
30 
31 import std.file;
32 import std..string : toStringz;
33 
34 import derelict.freeimage.freeimage;
35 
36 import anchovy.core.types;
37 public import anchovy.utils.signal;
38 
39 @trusted:
40 
41 enum ImageFormat : int
42 {
43 	png = FIF_PNG,
44 	jpeg = FIF_JPEG,
45 	gif = FIF_GIF,
46 	bmp = FIF_BMP,
47 
48 }
49 
50 Bitmap createBitmapFromFile(string filename)
51 {
52 	auto bitmap = new Bitmap(4);
53 
54 	// Automatically detects the format
55 	FREE_IMAGE_FORMAT formato = FreeImage_GetFileType(toStringz(filename),0);
56 	FIBITMAP* fiimage = FreeImage_Load(formato, toStringz(filename), 0);
57 
58 	if (fiimage is null) throw new Exception("Image loading failed");
59 
60 	FIBITMAP* temp = fiimage;
61 	FreeImage_FlipVertical(temp);
62 	fiimage = FreeImage_ConvertTo32Bits(temp);
63 
64 	FreeImage_Unload(temp);
65 
66 	bitmap.size.x = FreeImage_GetWidth(fiimage);
67 	bitmap.size.y = FreeImage_GetHeight(fiimage);
68 
69 	ubyte* bits = FreeImage_GetBits(fiimage);
70 
71 	bitmap.data = new ubyte[](bitmap.size.x*bitmap.size.y*4);
72 
73 	foreach(i; 0 .. bitmap.size.x * bitmap.size.y)//Converts from BGRA to RGBA
74 	{
75 		bitmap.data[i*4+0] = bits[i*4+2];
76 		bitmap.data[i*4+1] = bits[i*4+1];
77 		bitmap.data[i*4+2] = bits[i*4+0];
78 		bitmap.data[i*4+3] = bits[i*4+3];
79 	}
80 
81 	FreeImage_Unload(fiimage);
82 
83 	return bitmap;
84 }
85 
86 void saveBitmapToFile(Bitmap bitmap, string filename, ImageFormat format)
87 {
88 	FIBITMAP* fibitmap = FreeImage_ConvertFromRawBits(bitmap.data.ptr, cast(int)bitmap.size.x, cast(int)bitmap.size.y,
89 		cast(int)bitmap.size.x, bitmap.byteDepth * 8, 0xFF, 0xFF00, 0xFF0000, true);
90 
91 	FreeImage_Save(format, fibitmap, toStringz(filename), 0);
92 }
93 
94 class Bitmap
95 {
96 	uvec2 size;
97 	ubyte byteDepth;
98 	ubyte[]	data;
99 
100 	Signal!() dataChanged;
101 
102 	this(in uint w, in uint h, in ubyte byteDepth)
103 	{
104 		this.size.x = w;
105 		this.size.y = h;
106 		this.byteDepth = byteDepth;
107 		data = new ubyte[w*h*byteDepth];
108 	}
109 
110 	this(in ubyte byteDepth)
111 	{
112 		this.byteDepth = byteDepth;
113 	}
114 
115 
116 	void putSubRect(in uvec2 dest, in Rect source, in Bitmap sourceBitmap)
117 	{
118 		assert(false, "putSubRect is not yet implemented");
119 
120 		//dataChanged.emit();
121 	}
122 
123 	void putCustomSubRect(uvec2 dest, in Rect source, ubyte[] sourceData, in ubyte sDataByteDepth, in uint sDataWidth, in uint sDataHeight)
124 	in
125 	{
126 		assert(sourceData.length == sDataByteDepth * sDataWidth * sDataHeight);
127 		assert(byteDepth == sDataByteDepth, "Byte depth is not equal");
128 	}
129 	body
130 	{
131 		for (uint x = 0; x < source.width; ++x)
132 		{
133 			for (uint y = 0; y < source.height; ++y)
134 			{
135 				data[(y+dest.y)*size.x + x + dest.x] = sourceData[(y+source.y)*sDataWidth + x + source.x];
136 			}
137 		}
138 
139 		dataChanged.emit();
140 	}
141 
142 	void putCustomRect(uvec2 dest, in ubyte* sourceData, in ubyte sDataByteDepth, in uint sDataWidth, in uint sDataHeight)
143 	in
144 	{
145 		assert(byteDepth == sDataByteDepth, "Byte depth is not equal");
146 	}
147 	body
148 	{
149 		for (uint x = 0; x < sDataWidth; ++x)
150 		{
151 			for (uint y = 0; y < sDataHeight; ++y)
152 			{
153 				data[(y+dest.y)*size.x + x + dest.x] = sourceData[(y)*sDataWidth + x];
154 			}
155 		}
156 
157 		dataChanged.emit();
158 	}
159 }