1 /** 2 * SDL_Image support. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.graphics.sdl2image; 15 16 import ae.utils.graphics.color; 17 import ae.utils.graphics.image; 18 19 import derelict.sdl2.sdl; 20 import derelict.sdl2.image; 21 22 import std.exception; 23 import std.string : toStringz, format; 24 static import std.string; 25 26 static this() 27 { 28 DerelictSDL2.load(); 29 DerelictSDL2Image.load(); 30 31 IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG); 32 } 33 34 auto loadImage(string path, ref Image!RGBX target = *new Image!RGBX) 35 { 36 auto surface = IMG_Load(toStringz(path)); 37 enforce(surface, "Failed to load image " ~ path); 38 scope(exit) SDL_FreeSurface(surface); 39 target.size(surface.w, surface.h); 40 41 if (surface.format.palette) 42 { 43 switch (surface.format.BitsPerPixel) 44 { 45 case 1: depalettize!1(cast(ubyte*)surface.pixels, cast(RGBX*)target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 46 case 2: depalettize!2(cast(ubyte*)surface.pixels, cast(RGBX*)target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 47 case 4: depalettize!4(cast(ubyte*)surface.pixels, cast(RGBX*)target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 48 case 8: depalettize!8(cast(ubyte*)surface.pixels, cast(RGBX*)target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 49 default: 50 enforce(false, format("Don't know how to depalettize image with %d bits per pixel", surface.format.BitsPerPixel)); 51 } 52 } 53 else 54 rgbTransform(cast(ubyte*)surface.pixels, cast(RGBX*)target.pixels.ptr, surface.format, surface.w, surface.h, surface.pitch); 55 56 return target; 57 } 58 59 private: 60 61 void depalettize(int BITS)(ubyte* src, RGBX* dst, SDL_Palette *palette, uint w, uint h, int pitch) 62 { 63 static assert(BITS <= 8); 64 65 auto ncolors = palette.ncolors; 66 foreach (y; 0..h) 67 { 68 auto p = src; 69 foreach (x; 0..w) 70 { 71 ubyte c; 72 static if (BITS == 8) 73 c = *p++; 74 else 75 c = p[x / (8/BITS)] & (((1<<BITS)-1) << (x % (8/BITS))); 76 77 if (c >= ncolors) 78 throw new Exception("Color index exceeds number of colors in palette"); 79 *dst++ = cast(RGBX)(palette.colors[c]); 80 } 81 src += pitch; 82 } 83 } 84 85 void rgbTransform(ubyte* src, RGBX* dst, SDL_PixelFormat *format, uint w, uint h, int pitch) 86 { 87 auto bpp = format.BitsPerPixel; 88 enforce(bpp%8 == 0 && bpp >= 8 && bpp <= 32, std..string.format("Don't know how to process unpalettized image with %d bits per pixel", bpp)); 89 90 if (bpp == 32 91 && format.Rmask == 0x00_00_00_FF && format.Rshift== 0 92 && format.Gmask == 0x00_00_FF_00 && format.Rshift== 8 93 && format.Bmask == 0x00_FF_00_00 && format.Rshift==16) 94 { 95 // Everything is already in our desired format. 96 foreach (y; 0..h) 97 { 98 auto p = cast(RGBX*)src; 99 dst[0..w] = p[0..w]; 100 src += pitch; 101 dst += w; 102 } 103 } 104 else 105 { 106 // Use SDL_GetRGB for whatever weird formats. 107 auto Bpp = format.BytesPerPixel; 108 foreach (y; 0..h) 109 { 110 auto p = src; 111 foreach (x; 0..w) 112 { 113 RGBX c; 114 SDL_GetRGB(*cast(uint*)p, format, &c.r, &c.g, &c.b); 115 *dst++ = c; 116 p += Bpp; 117 } 118 src += pitch; 119 } 120 } 121 }