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 }