diff --git a/project/msvc/grafx2-win32.vcxproj b/project/msvc/grafx2-win32.vcxproj index e3e6039d..fd4d3604 100644 --- a/project/msvc/grafx2-win32.vcxproj +++ b/project/msvc/grafx2-win32.vcxproj @@ -141,6 +141,7 @@ + diff --git a/project/msvc/grafx2-win32.vcxproj.filters b/project/msvc/grafx2-win32.vcxproj.filters index 2f125ea8..8c013acb 100644 --- a/project/msvc/grafx2-win32.vcxproj.filters +++ b/project/msvc/grafx2-win32.vcxproj.filters @@ -359,6 +359,9 @@ Fichiers d%27en-tête + + Fichiers d%27en-tête + diff --git a/project/msvc/grafx2.vcxproj b/project/msvc/grafx2.vcxproj index 36f357aa..1b580d42 100644 --- a/project/msvc/grafx2.vcxproj +++ b/project/msvc/grafx2.vcxproj @@ -89,6 +89,7 @@ + diff --git a/project/msvc/grafx2.vcxproj.filters b/project/msvc/grafx2.vcxproj.filters index 9b47bc23..0fe3804d 100644 --- a/project/msvc/grafx2.vcxproj.filters +++ b/project/msvc/grafx2.vcxproj.filters @@ -186,6 +186,9 @@ Fichiers d%27en-tête + + Fichiers d%27en-tête + diff --git a/src/bitcount.h b/src/bitcount.h new file mode 100644 index 00000000..b1236fb0 --- /dev/null +++ b/src/bitcount.h @@ -0,0 +1,83 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2018 Thomas Bernard + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 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; version 2 + of the License. + + Grafx2 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 Grafx2; if not, see +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file bitcount.h +/// helper functions (or macros) to count bits in machine words +////////////////////////////////////////////////////////////////////////////// + +#ifndef BITCOUNT_H__ +#define BITCOINT_H__ + +#if defined(__GNUC__) && __GNUC__ > 2 +/* use GCC built in's */ +#define count_set_bits __builtin_popcount +#define count_trailing_zeros __builtin_ctz +#else + +/** + * Count the number of bit sets "Popcount" + * + * Based on Wikipedia article for Hamming_weight, it's optimized + * for cases when zeroes are more frequent. + */ +static int count_set_bits(unsigned int value) +{ + int count; + + for (count = 0; value != 0; count++) + value &= value-1; + return count; +} + +#if defined(_MSC_VER) + +#include +// beware : the MSVC __popcnt intrinsic is not compatible with all CPU's +// _BitScanForward() is available on all architectures. + +static int count_trailing_zeros(unsigned int value) +{ + unsigned long count; + + if (_BitScanForward(&count, value)) + return count; + else + return -1; +} +#else +/** + * Count the number of low order zero's before the first bit set + */ +static int count_trailing_zeros(unsigned int value) +{ + int count; + + if (value == 0) + return -1; + for (count = 0; (value & 1) == 0; value >>= 1) + count++; + return count; +} +#endif +#endif + +#endif \ No newline at end of file diff --git a/src/loadsave.c b/src/loadsave.c index 498277f9..55c94d0b 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -72,6 +72,8 @@ #include "filesel.h" #include "unicode.h" #include "fileformats.h" +#include "bitcount.h" + #if defined(USE_SDL) || defined(USE_SDL2) // -- SDL_Image ------------------------------------------------------------- @@ -1293,11 +1295,9 @@ static void Load_ClipBoard_Image(T_IO_Context * context) bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression, bmi->bmiHeader.biSizeImage, bmi->bmiHeader.biClrUsed); - if (bmi->bmiHeader.biCompression != BI_RGB) - GFX2_Log(GFX2_INFO, "Unsupported DIB compression %u\n", bmi->bmiHeader.biCompression); - else if (width > 9999 || height > 9999) + if (width > 9999 || height > 9999) GFX2_Log(GFX2_INFO, "Image too big : %lux%lu\n", width, height); - else + else if (bmi->bmiHeader.biCompression == BI_RGB) { unsigned i, color_count; const byte * pixels; @@ -1362,6 +1362,64 @@ static void Load_ClipBoard_Image(T_IO_Context * context) File_error = 1; } } + else if (bmi->bmiHeader.biCompression == BI_BITFIELDS) + { + dword r_mask = *((const dword *)&bmi->bmiColors[0]); + int r_bits = count_set_bits(r_mask); + int r_shift = count_trailing_zeros(r_mask); + dword g_mask = *((const dword *)&bmi->bmiColors[1]); + int g_bits = count_set_bits(g_mask); + int g_shift = count_trailing_zeros(g_mask); + dword b_mask = *((const dword *)&bmi->bmiColors[2]); + int b_bits = count_set_bits(b_mask); + int b_shift = count_trailing_zeros(b_mask); + const byte * pixels = (const byte *)&bmi->bmiColors[3]; + unsigned int bytes_per_pixel = (bmi->bmiHeader.biBitCount + 7) >> 3; + int bytes_per_line = (bmi->bmiHeader.biWidth * bytes_per_pixel + 3) & ~3; + unsigned int x, y; + + GFX2_Log(GFX2_DEBUG, "RGB%d%d%d, masks : %08x %08x %08x\n", r_bits, g_bits, b_bits, r_mask, g_mask, b_mask); + + File_error = 0; // have to be set before calling Pre_load() + Pre_load(context, width, height, bmi->bmiHeader.biSizeImage, FORMAT_CLIPBOARD, PIXEL_SIMPLE, bmi->bmiHeader.biBitCount); + + for (y = 0; y < height; y++) + { + const byte * ptr; + if (bmi->bmiHeader.biHeight > 0) + ptr = pixels + (height - y - 1) * bytes_per_line; + else + ptr = pixels + y * bytes_per_line; + for (x = 0; x < width; x++) + { + dword rgb, r, g, b; + switch (bytes_per_pixel) + { + case 1: + rgb = *ptr; + break; + case 2: + rgb = *((const word *)ptr); + break; + case 3: + rgb = ((dword)ptr[2] << 16) | ((dword)ptr[1] << 8) | (dword)ptr[0]; + break; + default: + rgb = *((const dword *)ptr); + } + r = (rgb & r_mask) >> r_shift; + r = (r << (8 - r_bits)) | (r >> (2 * r_bits - 8)); + g = (rgb & g_mask) >> g_shift; + g = (g << (8 - g_bits)) | (g >> (2 * g_bits - 8)); + b = (rgb & b_mask) >> b_shift; + b = (b << (8 - b_bits)) | (b >> (2 * b_bits - 8)); + Set_pixel_24b(context, x, y, r, g, b); + ptr += bytes_per_pixel; + } + } + } + else + GFX2_Log(GFX2_INFO, "Unsupported DIB compression %u\n", bmi->bmiHeader.biCompression); GlobalUnlock(clipboard); } } diff --git a/src/oldies.c b/src/oldies.c index 73582e63..c3671a84 100644 --- a/src/oldies.c +++ b/src/oldies.c @@ -39,6 +39,7 @@ #include "windows.h" #include "layers.h" #include "graph.h" +#include "bitcount.h" // I don't have round() in MSVC++ 2010 (_MSC_VER=1600) #if defined(_MSC_VER) @@ -47,40 +48,6 @@ #endif #endif -#if defined(__GNUC__) && __GNUC__ > 2 -/* use GCC built in's */ -#define count_set_bits __builtin_popcount -#define count_trailing_zeros __builtin_ctz -#else -/** - * Count the number of bit sets "Popcount" - * - * Based on Wikipedia article for Hamming_weight, it's optimized - * for cases when zeroes are more frequent. - */ -static int count_set_bits(unsigned int value) -{ - int count; - - for (count = 0; value != 0; count++) - value &= value-1; - return count; -} - -/** - * Count the number of low order zero's before the first bit set - */ -static int count_trailing_zeros(unsigned int value) -{ - int count; - - if (value == 0) - return -1; - for (count = 0; (value & 1) == 0; value >>= 1) - count++; - return count; -} -#endif static const struct { enum IMAGE_MODES mode;