# HG changeset patch # User Wolfgang Lieff <> # Date 1523032983 -3600 # Node ID 1618f87e1ae8a6aa0a7fa22890ffd353ab961f55 # Parent fa71e9331b534c4b70b22add9fba882f4e0361f7 Additional loader for DDS file format diff -r fa71e9331b53 -r 1618f87e1ae8 doc/docbook/GuideReferenceSupportedFormats.xml --- a/doc/docbook/GuideReferenceSupportedFormats.xml Tue Apr 03 13:08:34 2018 +0100 +++ b/doc/docbook/GuideReferenceSupportedFormats.xml Fri Apr 06 17:43:03 2018 +0100 @@ -1,7 +1,7 @@
Supported File Formats - 3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported. + 3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DDS, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported. Refer to diff -r fa71e9331b53 -r 1618f87e1ae8 src/Makefile.am --- a/src/Makefile.am Tue Apr 03 13:08:34 2018 +0100 +++ b/src/Makefile.am Fri Apr 06 17:43:03 2018 +0100 @@ -179,6 +179,8 @@ image_load_jpeg.h\ image_load_tiff.c\ image_load_tiff.h\ + image_load_dds.c\ + image_load_dds.h\ image_load_ffmpegthumbnailer.c\ image_load_ffmpegthumbnailer.h\ image-overlay.c \ diff -r fa71e9331b53 -r 1618f87e1ae8 src/editors.c --- a/src/editors.c Tue Apr 03 13:08:34 2018 +0100 +++ b/src/editors.c Fri Apr 06 17:43:03 2018 +0100 @@ -119,6 +119,7 @@ {"image/svg+xml", ".svg"}, {"image/svg+xml-compressed", ".svg"}, {"image/tiff", ".tiff;.tif;.mef"}, + {"image/vnd-ms.dds", ".dds"}, {"image/x-adobe-dng", ".dng"}, {"image/x-bmp", ".bmp"}, {"image/x-canon-crw", ".crw"}, diff -r fa71e9331b53 -r 1618f87e1ae8 src/filefilter.c --- a/src/filefilter.c Tue Apr 03 13:08:34 2018 +0100 +++ b/src/filefilter.c Fri Apr 06 17:43:03 2018 +0100 @@ -288,6 +288,9 @@ filter_add_if_missing("mkv", "Matroska video file", ".mkv;.webm", FORMAT_CLASS_VIDEO, FALSE, FALSE, FALSE); filter_add_if_missing("wmv", "Windows Media Video file", ".wmv;.asf", FORMAT_CLASS_VIDEO, FALSE, FALSE, FALSE); filter_add_if_missing("flv", "Flash Video file", ".flv", FORMAT_CLASS_VIDEO, FALSE, FALSE, FALSE); + + /* other supported formats */ + filter_add_if_missing("dds", "DirectDraw Surface", ".dds", FORMAT_CLASS_IMAGE, FALSE, FALSE, TRUE); } GList *filter_to_list(const gchar *extensions) diff -r fa71e9331b53 -r 1618f87e1ae8 src/image-load.c --- a/src/image-load.c Tue Apr 03 13:08:34 2018 +0100 +++ b/src/image-load.c Fri Apr 06 17:43:03 2018 +0100 @@ -24,6 +24,7 @@ #include "image_load_gdk.h" #include "image_load_jpeg.h" #include "image_load_tiff.h" +#include "image_load_dds.h" #include "image_load_ffmpegthumbnailer.h" #include "exif.h" @@ -636,6 +637,12 @@ } else #endif + if (il->bytes_total >= 3 && il->mapped_file[0] == 0x44 && il->mapped_file[1] == 0x44 && il->mapped_file[2] == 0x53) + { + DEBUG_1("Using dds loader"); + image_loader_backend_set_dds(&il->backend); + } + else image_loader_backend_set_default(&il->backend); il->loader = il->backend.loader_new(image_loader_area_updated_cb, image_loader_size_cb, image_loader_area_prepared_cb, il); diff -r fa71e9331b53 -r 1618f87e1ae8 src/image_load_dds.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/image_load_dds.c Fri Apr 06 17:43:03 2018 +0100 @@ -0,0 +1,613 @@ +/* + * Copyright (C) 2018 The Geeqie Team + * + * Author: Wolfgang Lieff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + * Derived from dds_reader written by: + * Copyright (c) 2015 Kenji Sasaki + * Released under the MIT license. + * https://github.com/npedotnet/DDSReader/blob/master/LICENSE + + */ + +#include "main.h" + +#include "image-load.h" +#include "image_load_dds.h" + +typedef struct _ImageLoaderDDS ImageLoaderDDS; +struct _ImageLoaderDDS { + ImageLoaderBackendCbAreaUpdated area_updated_cb; + ImageLoaderBackendCbSize size_cb; + ImageLoaderBackendCbAreaPrepared area_prepared_cb; + gpointer data; + GdkPixbuf *pixbuf; + guint requested_width; + guint requested_height; + gboolean abort; +}; + +static void free_buffer(guchar *pixels, gpointer data) +{ + g_free(pixels); +} + +int ddsGetHeight(unsigned const char * buffer) { + return (buffer[12] & 0xFF) | (buffer[13] & 0xFF) << 8 | (buffer[14] & 0xFF) << 16 | (buffer[15] & 0xFF) << 24; +} + +int ddsGetWidth(unsigned const char * buffer) { + return (buffer[16] & 0xFF) | (buffer[17] & 0xFF) << 8 | (buffer[18] & 0xFF) << 16 | (buffer[19] & 0xFF) << 24; +} + +int ddsGetMipmap(unsigned const char * buffer) { + return (buffer[28] & 0xFF) | (buffer[29] & 0xFF) << 8 | (buffer[30] & 0xFF) << 16 | (buffer[31] & 0xFF) << 24; +} + +int ddsGetPixelFormatFlags(unsigned const char * buffer) { + return (buffer[80] & 0xFF) | (buffer[81] & 0xFF) << 8 | (buffer[82] & 0xFF) << 16 | (buffer[83] & 0xFF) << 24; +} + +int ddsGetFourCC(unsigned const char * buffer) { + return (buffer[84] & 0xFF) << 24 | (buffer[85] & 0xFF) << 16 | (buffer[86] & 0xFF) << 8 | (buffer[87] & 0xFF); +} + +int ddsGetBitCount(unsigned const char * buffer) { + return (buffer[88] & 0xFF) | (buffer[89] & 0xFF) << 8 | (buffer[90] & 0xFF) << 16 | (buffer[91] & 0xFF) << 24; +} + +int ddsGetRedMask(unsigned const char * buffer) { + return (buffer[92] & 0xFF) | (buffer[93] & 0xFF) << 8 | (buffer[94] & 0xFF) << 16 | (buffer[95] & 0xFF) << 24; +} + +int ddsGetGreenMask(unsigned const char * buffer) { + return (buffer[96] & 0xFF) | (buffer[97] & 0xFF) << 8 | (buffer[98] & 0xFF) << 16 | (buffer[99] & 0xFF) << 24; +} + +int ddsGetBlueMask(unsigned const char * buffer) { + return (buffer[100] & 0xFF) | (buffer[101] & 0xFF) << 8 | (buffer[102] & 0xFF) << 16 | (buffer[103] & 0xFF) << 24; +} + +int ddsGetAlphaMask(unsigned const char * buffer) { + return (buffer[104] & 0xFF) | (buffer[105] & 0xFF) << 8 | (buffer[106] & 0xFF) << 16 | (buffer[107] & 0xFF) << 24; +} + +// Image Type +#define DXT1 (0x44585431) +#define DXT2 (0x44585432) +#define DXT3 (0x44585433) +#define DXT4 (0x44585434) +#define DXT5 (0x44585435) +#define A1R5G5B5 ((1 << 16) | 2) +#define X1R5G5B5 ((2 << 16) | 2) +#define A4R4G4B4 ((3 << 16) | 2) +#define X4R4G4B4 ((4 << 16) | 2) +#define R5G6B5 ((5 << 16) | 2) +#define R8G8B8 ((1 << 16) | 3) +#define A8B8G8R8 ((1 << 16) | 4) +#define X8B8G8R8 ((2 << 16) | 4) +#define A8R8G8B8 ((3 << 16) | 4) +#define X8R8G8B8 ((4 << 16) | 4) + +// RGBA Masks +static const int A1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x8000 }; +static const int X1R5G5B5_MASKS[] = { 0x7C00, 0x03E0, 0x001F, 0x0000 }; +static const int A4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0xF000 }; +static const int X4R4G4B4_MASKS[] = { 0x0F00, 0x00F0, 0x000F, 0x0000 }; +static const int R5G6B5_MASKS[] = { 0xF800, 0x07E0, 0x001F, 0x0000 }; +static const int R8G8B8_MASKS[] = { 0xFF0000, 0x00FF00, 0x0000FF, 0x000000 }; +static const int A8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }; +static const int X8B8G8R8_MASKS[] = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 }; +static const int A8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 }; +static const int X8R8G8B8_MASKS[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }; + +// BIT4 = 17 * index; +static const int BIT5[] = { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 }; +static const int BIT6[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255 }; + +static int ddsGetType(const unsigned char *buffer) { + int type = 0; + int flags = ddsGetPixelFormatFlags(buffer); + if ((flags & 0x04) != 0) { + // DXT + type = ddsGetFourCC(buffer); + } + else if ((flags & 0x40) != 0) { + // RGB + int bitCount = ddsGetBitCount(buffer); + int redMask = ddsGetRedMask(buffer); + int greenMask = ddsGetGreenMask(buffer); + int blueMask = ddsGetBlueMask(buffer); + int alphaMask = ((flags & 0x01) != 0) ? ddsGetAlphaMask(buffer) : 0; // 0x01 alpha + if (bitCount == 16) { + if (redMask == A1R5G5B5_MASKS[0] && greenMask == A1R5G5B5_MASKS[1] && blueMask == A1R5G5B5_MASKS[2] && alphaMask == A1R5G5B5_MASKS[3]) { + // A1R5G5B5 + type = A1R5G5B5; + } + else if (redMask == X1R5G5B5_MASKS[0] && greenMask == X1R5G5B5_MASKS[1] && blueMask == X1R5G5B5_MASKS[2] && alphaMask == X1R5G5B5_MASKS[3]) { + // X1R5G5B5 + type = X1R5G5B5; + } + else if (redMask == A4R4G4B4_MASKS[0] && greenMask == A4R4G4B4_MASKS[1] && blueMask == A4R4G4B4_MASKS[2] && alphaMask == A4R4G4B4_MASKS[3]) { + // A4R4G4B4 + type = A4R4G4B4; + } + else if (redMask == X4R4G4B4_MASKS[0] && greenMask == X4R4G4B4_MASKS[1] && blueMask == X4R4G4B4_MASKS[2] && alphaMask == X4R4G4B4_MASKS[3]) { + // X4R4G4B4 + type = X4R4G4B4; + } + else if (redMask == R5G6B5_MASKS[0] && greenMask == R5G6B5_MASKS[1] && blueMask == R5G6B5_MASKS[2] && alphaMask == R5G6B5_MASKS[3]) { + // R5G6B5 + type = R5G6B5; + } + else { + // Unsupported 16bit RGB image + } + } + else if (bitCount == 24) { + if (redMask == R8G8B8_MASKS[0] && greenMask == R8G8B8_MASKS[1] && blueMask == R8G8B8_MASKS[2] && alphaMask == R8G8B8_MASKS[3]) { + // R8G8B8 + type = R8G8B8; + } + else { + // Unsupported 24bit RGB image + } + } + else if (bitCount == 32) { + if (redMask == A8B8G8R8_MASKS[0] && greenMask == A8B8G8R8_MASKS[1] && blueMask == A8B8G8R8_MASKS[2] && alphaMask == A8B8G8R8_MASKS[3]) { + // A8B8G8R8 + type = A8B8G8R8; + } + else if (redMask == X8B8G8R8_MASKS[0] && greenMask == X8B8G8R8_MASKS[1] && blueMask == X8B8G8R8_MASKS[2] && alphaMask == X8B8G8R8_MASKS[3]) { + // X8B8G8R8 + type = X8B8G8R8; + } + else if (redMask == A8R8G8B8_MASKS[0] && greenMask == A8R8G8B8_MASKS[1] && blueMask == A8R8G8B8_MASKS[2] && alphaMask == A8R8G8B8_MASKS[3]) { + // A8R8G8B8 + type = A8R8G8B8; + } + else if (redMask == X8R8G8B8_MASKS[0] && greenMask == X8R8G8B8_MASKS[1] && blueMask == X8R8G8B8_MASKS[2] && alphaMask == X8R8G8B8_MASKS[3]) { + // X8R8G8B8 + type = X8R8G8B8; + } + else { + // Unsupported 32bit RGB image + } + } + } + else { + // YUV or LUMINANCE image + } + return type; +} + +int ddsGetDXTColor2_1(int c0, int c1, int a) { + // 2*c0/3 + c1/3 + int r = (2 * BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 3; + int g = (2 * BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 3; + int b = (2 * BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 3; + return (a << 24) | (r << 0) | (g << 8) | (b << 16); +} + +int ddsGetDXTColor1_1(int c0, int c1, int a) { + // (c0+c1) / 2 + int r = (BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 2; + int g = (BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 2; + int b = (BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 2; + return (a << 24) | (r << 0) | (g << 8) | (b << 16); +} + +int ddsGetDXTColor1(int c, int a) { + int r = BIT5[(c & 0xFC00) >> 11]; + int g = BIT6[(c & 0x07E0) >> 5]; + int b = BIT5[(c & 0x001F)]; + return (a << 24) | (r << 0) | (g << 8) | (b << 16); +} + +int ddsGetDXTColor(int c0, int c1, int a, int t) { + switch (t) { + case 0: return ddsGetDXTColor1(c0, a); + case 1: return ddsGetDXTColor1(c1, a); + case 2: return (c0 > c1) ? ddsGetDXTColor2_1(c0, c1, a) : ddsGetDXTColor1_1(c0, c1, a); + case 3: return (c0 > c1) ? ddsGetDXTColor2_1(c1, c0, a) : 0; + } + return 0; +} + +guchar *ddsDecodeDXT1(int width, int height, const unsigned char *buffer) { + int *pixels = g_try_malloc(4 * width*height); + int index = 128; + int w = (width + 3) / 4; + int h = (height + 3) / 4; + for (int i = 0; i= height) break; + int t0 = (buffer[index] & 0x03); + int t1 = (buffer[index] & 0x0C) >> 2; + int t2 = (buffer[index] & 0x30) >> 4; + int t3 = (buffer[index++] & 0xC0) >> 6; + pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, 0xFF, t0); + if (4 * j + 1 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, 0xFF, t1); + if (4 * j + 2 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, 0xFF, t2); + if (4 * j + 3 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, 0xFF, t3); + } + } + } + return (guchar *) pixels; +} + +guchar *ddsDecodeDXT3(int width, int height, const unsigned char *buffer) { + int *pixels = g_try_malloc(4 * width*height); + int index = 128; + int w = (width + 3) / 4; + int h = (height + 3) / 4; + int alphaTable[16]; + for (int i = 0; i> 4); + alphaTable[4 * k + 1] = 17 * (a0 & 0x0F); + alphaTable[4 * k + 2] = 17 * ((a1 & 0xF0) >> 4); + alphaTable[4 * k + 3] = 17 * (a1 & 0x0F); + } + int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + for (int k = 0; k<4; k++) { + if (4 * i + k >= height) break; + int t0 = (buffer[index] & 0x03); + int t1 = (buffer[index] & 0x0C) >> 2; + int t2 = (buffer[index] & 0x30) >> 4; + int t3 = (buffer[index++] & 0xC0) >> 6; + pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 0], t0); + if (4 * j + 1 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 1], t1); + if (4 * j + 2 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 2], t2); + if (4 * j + 3 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, alphaTable[4 * k + 3], t3); + } + } + } + return (guchar *) pixels; +} + +guchar *ddsDecodeDXT2(int width, int height, const unsigned char *buffer) { + return ddsDecodeDXT3(width, height, buffer); +} + +int ddsGetDXT5Alpha(int a0, int a1, int t) { + if (a0 > a1) switch (t) { + case 0: return a0; + case 1: return a1; + case 2: return (6 * a0 + a1) / 7; + case 3: return (5 * a0 + 2 * a1) / 7; + case 4: return (4 * a0 + 3 * a1) / 7; + case 5: return (3 * a0 + 4 * a1) / 7; + case 6: return (2 * a0 + 5 * a1) / 7; + case 7: return (a0 + 6 * a1) / 7; + } + else switch (t) { + case 0: return a0; + case 1: return a1; + case 2: return (4 * a0 + a1) / 5; + case 3: return (3 * a0 + 2 * a1) / 5; + case 4: return (2 * a0 + 3 * a1) / 5; + case 5: return (a0 + 4 * a1) / 5; + case 6: return 0; + case 7: return 255; + } + return 0; +} + +guchar *ddsDecodeDXT5(int width, int height, const unsigned char *buffer) { + int *pixels = g_try_malloc(4 * width*height); + int index = 128; + int w = (width + 3) / 4; + int h = (height + 3) / 4; + int alphaTable[16]; + for (int i = 0; i> 3) & 0x07; + alphaTable[2] = (b0 >> 6) & 0x07; + alphaTable[3] = (b0 >> 9) & 0x07; + alphaTable[4] = (b0 >> 12) & 0x07; + alphaTable[5] = (b0 >> 15) & 0x07; + alphaTable[6] = (b0 >> 18) & 0x07; + alphaTable[7] = (b0 >> 21) & 0x07; + alphaTable[8] = b1 & 0x07; + alphaTable[9] = (b1 >> 3) & 0x07; + alphaTable[10] = (b1 >> 6) & 0x07; + alphaTable[11] = (b1 >> 9) & 0x07; + alphaTable[12] = (b1 >> 12) & 0x07; + alphaTable[13] = (b1 >> 15) & 0x07; + alphaTable[14] = (b1 >> 18) & 0x07; + alphaTable[15] = (b1 >> 21) & 0x07; + int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8; index += 2; + for (int k = 0; k<4; k++) { + if (4 * i + k >= height) break; + int t0 = (buffer[index] & 0x03); + int t1 = (buffer[index] & 0x0C) >> 2; + int t2 = (buffer[index] & 0x30) >> 4; + int t3 = (buffer[index++] & 0xC0) >> 6; + pixels[4 * width*i + 4 * j + width*k + 0] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 0]), t0); + if (4 * j + 1 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 1] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 1]), t1); + if (4 * j + 2 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 2] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 2]), t2); + if (4 * j + 3 >= width) continue; + pixels[4 * width*i + 4 * j + width*k + 3] = ddsGetDXTColor(c0, c1, ddsGetDXT5Alpha(a0, a1, alphaTable[4 * k + 3]), t3); + } + } + } + return (guchar *) pixels; +} + +guchar *ddsDecodeDXT4(int width, int height, const unsigned char *buffer) { + return ddsDecodeDXT5(width, height, buffer); +} + +guchar *ddsReadA1R5G5B5(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4*width*height); + for (int i = 0; i> 10]; + int g = BIT5[(rgba & A1R5G5B5_MASKS[1]) >> 5]; + int b = BIT5[(rgba & A1R5G5B5_MASKS[2])]; + int a = 255 * ((rgba & A1R5G5B5_MASKS[3]) >> 15); + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadX1R5G5B5(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i> 10]; + int g = BIT5[(rgba & X1R5G5B5_MASKS[1]) >> 5]; + int b = BIT5[(rgba & X1R5G5B5_MASKS[2])]; + int a = 255; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadA4R4G4B4(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i> 8); + int g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4); + int b = 17 * ((rgba & A4R4G4B4_MASKS[2])); + int a = 17 * ((rgba & A4R4G4B4_MASKS[3]) >> 12); + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadX4R4G4B4(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i> 8); + int g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4); + int b = 17 * ((rgba & A4R4G4B4_MASKS[2])); + int a = 255; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadR5G6B5(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; i> 11)]; + int g = BIT6[((rgba & R5G6B5_MASKS[1]) >> 5)]; + int b = BIT5[((rgba & R5G6B5_MASKS[2]))]; + int a = 255; + pixels[i] = (a << 24) | (r << 0) | (g << 8) | (b << 16); + } + return (guchar *) pixels; +} + +guchar *ddsReadR8G8B8(int width, int height, const unsigned char *buffer) { + int index = 128; + int *pixels = g_try_malloc(4 * width*height); + for (int i = 0; ipixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, width, height, rowstride, free_buffer, NULL); + ld->area_updated_cb(loader, 0, 0, width, height, ld->data); + return TRUE; + } +} + +static gpointer image_loader_dds_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data) +{ + ImageLoaderDDS *loader = g_new0(ImageLoaderDDS, 1); + loader->area_updated_cb = area_updated_cb; + loader->size_cb = size_cb; + loader->area_prepared_cb = area_prepared_cb; + loader->data = data; + return (gpointer) loader; +} + +static void image_loader_dds_set_size(gpointer loader, int width, int height) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + ld->requested_width = width; + ld->requested_height = height; +} + +static GdkPixbuf* image_loader_dds_get_pixbuf(gpointer loader) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + return ld->pixbuf; +} + +static gchar* image_loader_dds_get_format_name(gpointer loader) +{ + return g_strdup("dds"); +} +static gchar** image_loader_dds_get_format_mime_types(gpointer loader) +{ + static gchar *mime[] = {"image/vnd-ms.dds", NULL}; + return g_strdupv(mime); +} + +static gboolean image_loader_dds_close(gpointer loader, GError **error) +{ + return TRUE; +} + +static void image_loader_dds_abort(gpointer loader) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + ld->abort = TRUE; +} + +static void image_loader_dds_free(gpointer loader) +{ + ImageLoaderDDS *ld = (ImageLoaderDDS *) loader; + if (ld->pixbuf) g_object_unref(ld->pixbuf); + g_free(ld); +} + +void image_loader_backend_set_dds(ImageLoaderBackend *funcs) +{ + funcs->loader_new = image_loader_dds_new; + funcs->set_size = image_loader_dds_set_size; + funcs->load = image_loader_dds_load; + funcs->write = NULL; + funcs->get_pixbuf = image_loader_dds_get_pixbuf; + funcs->close = image_loader_dds_close; + funcs->abort = image_loader_dds_abort; + funcs->free = image_loader_dds_free; + funcs->get_format_name = image_loader_dds_get_format_name; + funcs->get_format_mime_types = image_loader_dds_get_format_mime_types; +} + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff -r fa71e9331b53 -r 1618f87e1ae8 src/image_load_dds.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/image_load_dds.h Fri Apr 06 17:43:03 2018 +0100 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Geeqie Team + * + * Author: Wolfgang Lieff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef IMAGE_LOAD_DDS_H +#define IMAGE_LOAD_DDS_H + +void image_loader_backend_set_dds(ImageLoaderBackend *funcs); + +#endif + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff -r fa71e9331b53 -r 1618f87e1ae8 web/help/GuideReferenceSupportedFormats.html --- a/web/help/GuideReferenceSupportedFormats.html Tue Apr 03 13:08:34 2018 +0100 +++ b/web/help/GuideReferenceSupportedFormats.html Fri Apr 06 17:43:03 2018 +0100 @@ -458,7 +458,7 @@
  • The Geeqie User Manual
  • Reference
  • -

    3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported.

    +

    3FR, ANI, APM, ARW, BMP, CR2, CRW, CUR, DDS, DNG, ERF, GIF, ICNS, ICO, JPE/JPEG/JPG, JPS, KDC, MEF, MPO, MOS, MRW, NEF, ORF, PEF, PTX, PBM/PGM/PNM/PPM, PNG, QIF/QTIF (QuickTime Image Format), RAF, RAW, RW2, SR2, SRF, SVG/SVGZ, TGA/TARGA, TIF/TIFF, WMF, XBM, XPM. Animated GIFs are supported.

    Refer to Additional pixbuf loaders