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 25 static this() 26 { 27 DerelictSDL2.load(); 28 DerelictSDL2Image.load(); 29 30 IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG); 31 } 32 33 auto loadImage(string path, ref Image!RGBX target = *new Image!RGBX) 34 { 35 auto surface = IMG_Load(toStringz(path)); 36 enforce(surface, "Failed to load image " ~ path); 37 scope(exit) SDL_FreeSurface(surface); 38 target.size(surface.w, surface.h); 39 40 if (surface.format.palette) 41 { 42 switch (surface.format.BitsPerPixel) 43 { 44 case 1: depalettize!1(cast(ubyte*)surface.pixels, target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 45 case 2: depalettize!2(cast(ubyte*)surface.pixels, target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 46 case 4: depalettize!4(cast(ubyte*)surface.pixels, target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 47 case 8: depalettize!8(cast(ubyte*)surface.pixels, target.pixels.ptr, surface.format.palette, surface.w, surface.h, surface.pitch); break; 48 default: 49 enforce(false, format("Don't know how to depalettize image with %d bits per pixel", surface.format.BitsPerPixel)); 50 } 51 } 52 else 53 rgbTransform(cast(ubyte*)surface.pixels, target.pixels.ptr, surface.format, surface.w, surface.h, surface.pitch); 54 55 return target; 56 } 57 58 private: 59 60 void depalettize(int BITS)(ubyte* src, RGBX* dst, SDL_Palette *palette, uint w, uint h, int pitch) 61 { 62 static assert(BITS <= 8); 63 64 auto ncolors = palette.ncolors; 65 foreach (y; 0..h) 66 { 67 auto p = src; 68 foreach (x; 0..w) 69 { 70 ubyte c; 71 static if (BITS == 8) 72 c = *p++; 73 else 74 c = p[x / (8/BITS)] & (((1<<BITS)-1) << (x % (8/BITS))); 75 76 if (c >= ncolors) 77 throw new Exception("Color index exceeds number of colors in palette"); 78 *dst++ = cast(RGBX)(palette.colors[c]); 79 } 80 src += pitch; 81 } 82 } 83 84 void rgbTransform(ubyte* src, RGBX* dst, SDL_PixelFormat *format, uint w, uint h, int pitch) 85 { 86 auto bpp = format.BitsPerPixel; 87 enforce(bpp%8 == 0 && bpp >= 8 && bpp <= 32, format("Don't know how to process unpalettized image with %d bits per pixel", bpp)); 88 89 if (bpp == 32 90 && format.Rmask == 0x00_00_00_FF && format.Rshift== 0 91 && format.Gmask == 0x00_00_FF_00 && format.Rshift== 8 92 && format.Bmask == 0x00_FF_00_00 && format.Rshift==16) 93 { 94 // Everything is already in our desired format. 95 foreach (y; 0..h) 96 { 97 auto p = cast(RGBX*)src; 98 dst[0..w] = p[0..w]; 99 src += pitch; 100 dst += w; 101 } 102 } 103 else 104 { 105 // Use SDL_GetRGB for whatever weird formats. 106 auto Bpp = format.BytesPerPixel; 107 foreach (y; 0..h) 108 { 109 auto p = src; 110 foreach (x; 0..w) 111 { 112 RGBX c; 113 SDL_GetRGB(*cast(uint*)p, format, &c.r, &c.g, &c.b); 114 *dst++ = c; 115 p += Bpp; 116 } 117 src += pitch; 118 } 119 } 120 }