1 /** 2 * Copyright: Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved 3 * Authors: $(Gabriel Gheorghe) 4 * License: $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007) 5 * Source: $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/image/io.d) 6 * Documentation: 7 * Coverage: 8 * 9 * TODO: 10 * - move in resource manager 11 **/ 12 module liberty.image.io; 13 14 import liberty.logger.impl; 15 import liberty.image.format; 16 import liberty.image.impl; 17 import liberty.io.manager; 18 import liberty.graphics.texture.impl; 19 20 /** 21 * Singleton class used for loading image files. 22 * It's a manager class so it implements $(D ManagerBody). 23 **/ 24 final abstract class ImageIO { 25 /** 26 * 27 **/ 28 static Image loadImage(string path) { 29 import std.array : split; 30 31 // Check extension 32 string[] splitArray = path.split("."); 33 immutable extension = splitArray[$ - 1]; 34 switch (extension) { 35 case "bmp", "BMP": 36 return loadBMPFile(path); 37 case "png", "PNG": 38 return loadPNGFile(path); 39 default: 40 Logger.error( 41 "File format not supported for image data: " ~ extension, 42 typeof(this).stringof 43 ); 44 } 45 46 assert(0, "Unreachable"); 47 } 48 49 /** 50 * 51 **/ 52 static BMPImage createImage(BMPHeader header, ubyte[] pixelData) { 53 return new BMPImage(header, pixelData); 54 } 55 56 private static BMPImage loadBMPFile(string resourcePath) { 57 char[] buf; 58 59 // Read bmp file and put its content into a buffer 60 if (!IOManager.readFileToBuffer(resourcePath, buf, "rb")) 61 Logger.error("Cannot read " ~ resourcePath ~ " file.", typeof(this).stringof); 62 63 // Check if it is really a bmp image 64 if (!isBMPFormat(buf[0x00..0x02])) 65 Logger.error("Not *.bmp file.", typeof(this).stringof); 66 67 BMPHeader header; 68 ubyte[] pixelData; 69 70 // Fill bmp header 71 header.dataPosition = *cast(uint*)&buf[0x0A]; 72 header.size = *cast(uint*)&buf[0x22]; 73 header.width = *cast(uint*)&buf[0x12]; 74 header.height = *cast(uint*)&buf[0x16]; 75 76 if (header.size == 0) 77 header.size = header.width * header.height * 4; 78 79 if (header.dataPosition == 0) 80 header.dataPosition = IMPLICIT_BMP_HEADER_DATA_POSITION; 81 82 // Fill bmp pixel data 83 pixelData = cast(ubyte[])buf[header.dataPosition..buf.length]; 84 85 // Create the image in memory and return it 86 return createImage(header, pixelData); 87 } 88 89 private static PNGImage loadPNGFile(string resourcePath) { 90 char[] buf; 91 92 // Read png file and put its content into a buffer 93 if (!IOManager.readFileToBuffer(resourcePath, buf, "rb")) { 94 assert(0, "Operation failed!"); 95 } 96 97 // Check if it is really a png image 98 if (!isPNGFormat(buf[0x00..0x08])) { 99 assert(0, "Not PNG image!"); 100 } 101 102 Logger.todo("static PNGImage loadPNGFile(string resourcePath) {..}", typeof(this).stringof); 103 Logger.error("Previous TODO", typeof(this).stringof); 104 105 return null; 106 } 107 108 private static bool isBMPFormat(in char[2] bytes) { 109 return bytes[0] == 'B' && bytes[1] == 'M'; 110 } 111 112 private static bool isPNGFormat(in char[8] bytes) { 113 return 114 cast(ubyte)bytes[0] == 137 && 115 cast(ubyte)bytes[1] == 80 && 116 cast(ubyte)bytes[2] == 78 && 117 cast(ubyte)bytes[3] == 71 && 118 cast(ubyte)bytes[4] == 13 && 119 cast(ubyte)bytes[5] == 10 && 120 cast(ubyte)bytes[6] == 26 && 121 cast(ubyte)bytes[7] == 10; 122 } 123 }