diff --git a/CMakeLists.txt b/CMakeLists.txt index 7602bc9..c95e7d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ if(WIN32) target_sources(clip PRIVATE clip_win.cpp) if(CLIP_ENABLE_IMAGE) - target_sources(clip PRIVATE clip_win_wic.cpp) + target_sources(clip PRIVATE clip_win_bmp.cpp clip_win_wic.cpp) target_link_libraries(clip shlwapi) endif() diff --git a/clip_common.h b/clip_common.h index 9446bd3..61fa992 100644 --- a/clip_common.h +++ b/clip_common.h @@ -8,6 +8,8 @@ #define CLIP_COMMON_H_INCLUDED #pragma once +#include "clip.h" + namespace clip { namespace details { diff --git a/clip_win.cpp b/clip_win.cpp index 661f760..282e084 100644 --- a/clip_win.cpp +++ b/clip_win.cpp @@ -4,6 +4,8 @@ // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. +#include "clip_win.h" + #include "clip.h" #include "clip_common.h" #include "clip_lock_impl.h" @@ -14,20 +16,6 @@ #include #include -#include - -#if CLIP_ENABLE_IMAGE -#include "clip_win_wic.h" -#endif // CLIP_ENABLE_IMAGE - -#ifndef LCS_WINDOWS_COLOR_SPACE -#define LCS_WINDOWS_COLOR_SPACE 'Win ' -#endif - -#ifndef CF_DIBV5 -#define CF_DIBV5 17 -#endif - namespace clip { namespace { @@ -38,14 +26,6 @@ namespace { // value. typedef uint64_t CustomSizeT; -unsigned long get_shift_from_mask(unsigned long mask) { - unsigned long shift = 0; - for (shift=0; shiftbV5BitCount == 32 && - ((b5->bV5Compression == BI_RGB) || - (b5->bV5Compression == BI_BITFIELDS && - b5->bV5RedMask && b5->bV5GreenMask && - b5->bV5BlueMask && b5->bV5AlphaMask))) { - width = b5->bV5Width; - height = b5->bV5Height; - bit_count = b5->bV5BitCount; - compression = b5->bV5Compression; - if (compression == BI_BITFIELDS) { - red_mask = b5->bV5RedMask; - green_mask = b5->bV5GreenMask; - blue_mask = b5->bV5BlueMask; - alpha_mask = b5->bV5AlphaMask; - } - else { - red_mask = 0xff0000; - green_mask = 0xff00; - blue_mask = 0xff; - alpha_mask = 0xff000000; - } - return; - } - } - - if (IsClipboardFormatAvailable(CF_DIB)) - bi = (BITMAPINFO*)GetClipboardData(CF_DIB); - if (!bi) - return; - - width = bi->bmiHeader.biWidth; - height = bi->bmiHeader.biHeight; - bit_count = bi->bmiHeader.biBitCount; - compression = bi->bmiHeader.biCompression; - - if (compression == BI_BITFIELDS) { - red_mask = *((uint32_t*)&bi->bmiColors[0]); - green_mask = *((uint32_t*)&bi->bmiColors[1]); - blue_mask = *((uint32_t*)&bi->bmiColors[2]); - if (bit_count == 32) - alpha_mask = 0xff000000; - } - else if (compression == BI_RGB) { - switch (bit_count) { - case 32: - red_mask = 0xff0000; - green_mask = 0xff00; - blue_mask = 0xff; - alpha_mask = 0xff000000; - break; - case 24: - case 8: // We return 8bpp images as 24bpp - red_mask = 0xff0000; - green_mask = 0xff00; - blue_mask = 0xff; - break; - case 16: - red_mask = 0x7c00; - green_mask = 0x03e0; - blue_mask = 0x001f; - break; - } - } - } - - bool is_valid() const { - return (b5 || bi); - } - - void fill_spec(image_spec& spec) { - spec.width = width; - spec.height = (height >= 0 ? height: -height); - // We convert indexed to 24bpp RGB images to match the OS X behavior - spec.bits_per_pixel = bit_count; - if (spec.bits_per_pixel <= 8) - spec.bits_per_pixel = 24; - spec.bytes_per_row = width*((spec.bits_per_pixel+7)/8); - spec.red_mask = red_mask; - spec.green_mask = green_mask; - spec.blue_mask = blue_mask; - spec.alpha_mask = alpha_mask; - - switch (spec.bits_per_pixel) { - - case 24: { - // We need one extra byte to avoid a crash updating the last - // pixel on last row using: - // - // *((uint32_t*)ptr) = pixel24bpp; - // - ++spec.bytes_per_row; - - // Align each row to 32bpp - int padding = (4-(spec.bytes_per_row&3))&3; - spec.bytes_per_row += padding; - break; - } - - case 16: { - int padding = (4-(spec.bytes_per_row&3))&3; - spec.bytes_per_row += padding; - break; - } - } - - unsigned long* masks = &spec.red_mask; - unsigned long* shifts = &spec.red_shift; - for (unsigned long* shift=shifts, *mask=masks; shift + +#ifndef LCS_WINDOWS_COLOR_SPACE +#define LCS_WINDOWS_COLOR_SPACE 'Win ' +#endif + +#ifndef CF_DIBV5 +#define CF_DIBV5 17 +#endif + +#if CLIP_ENABLE_IMAGE + #include "clip_win_bmp.h" + #include "clip_win_wic.h" +#endif + +#endif // CLIP_WIN_H_INCLUDED diff --git a/clip_win_bmp.cpp b/clip_win_bmp.cpp new file mode 100644 index 0000000..f6916c0 --- /dev/null +++ b/clip_win_bmp.cpp @@ -0,0 +1,142 @@ +// Clip Library +// Copyright (c) 2015-2024 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#include "clip_win_bmp.h" + +#include "clip.h" + +namespace clip { +namespace win { + +namespace { + +unsigned long get_shift_from_mask(unsigned long mask) { + unsigned long shift = 0; + for (shift=0; shiftbV5BitCount == 32 && + ((b5->bV5Compression == BI_RGB) || + (b5->bV5Compression == BI_BITFIELDS && + b5->bV5RedMask && b5->bV5GreenMask && + b5->bV5BlueMask && b5->bV5AlphaMask))) { + width = b5->bV5Width; + height = b5->bV5Height; + bit_count = b5->bV5BitCount; + compression = b5->bV5Compression; + if (compression == BI_BITFIELDS) { + red_mask = b5->bV5RedMask; + green_mask = b5->bV5GreenMask; + blue_mask = b5->bV5BlueMask; + alpha_mask = b5->bV5AlphaMask; + } + else { + red_mask = 0xff0000; + green_mask = 0xff00; + blue_mask = 0xff; + alpha_mask = 0xff000000; + } + return; + } + } + + if (IsClipboardFormatAvailable(CF_DIB)) + bi = (BITMAPINFO*)GetClipboardData(CF_DIB); + if (!bi) + return; + + width = bi->bmiHeader.biWidth; + height = bi->bmiHeader.biHeight; + bit_count = bi->bmiHeader.biBitCount; + compression = bi->bmiHeader.biCompression; + + if (compression == BI_BITFIELDS) { + red_mask = *((uint32_t*)&bi->bmiColors[0]); + green_mask = *((uint32_t*)&bi->bmiColors[1]); + blue_mask = *((uint32_t*)&bi->bmiColors[2]); + if (bit_count == 32) + alpha_mask = 0xff000000; + } + else if (compression == BI_RGB) { + switch (bit_count) { + case 32: + red_mask = 0xff0000; + green_mask = 0xff00; + blue_mask = 0xff; + alpha_mask = 0xff000000; + break; + case 24: + case 8: // We return 8bpp images as 24bpp + red_mask = 0xff0000; + green_mask = 0xff00; + blue_mask = 0xff; + break; + case 16: + red_mask = 0x7c00; + green_mask = 0x03e0; + blue_mask = 0x001f; + break; + } + } +} + +void BitmapInfo::fill_spec(image_spec& spec) { + spec.width = width; + spec.height = (height >= 0 ? height: -height); + // We convert indexed to 24bpp RGB images to match the OS X behavior + spec.bits_per_pixel = bit_count; + if (spec.bits_per_pixel <= 8) + spec.bits_per_pixel = 24; + spec.bytes_per_row = width*((spec.bits_per_pixel+7)/8); + spec.red_mask = red_mask; + spec.green_mask = green_mask; + spec.blue_mask = blue_mask; + spec.alpha_mask = alpha_mask; + + switch (spec.bits_per_pixel) { + + case 24: { + // We need one extra byte to avoid a crash updating the last + // pixel on last row using: + // + // *((uint32_t*)ptr) = pixel24bpp; + // + ++spec.bytes_per_row; + + // Align each row to 32bpp + int padding = (4-(spec.bytes_per_row&3))&3; + spec.bytes_per_row += padding; + break; + } + + case 16: { + int padding = (4-(spec.bytes_per_row&3))&3; + spec.bytes_per_row += padding; + break; + } + } + + unsigned long* masks = &spec.red_mask; + unsigned long* shifts = &spec.red_shift; + for (unsigned long* shift=shifts, *mask=masks; shift + +#include + +namespace clip { + +struct image_spec; + +namespace win { + +struct BitmapInfo { + BITMAPV5HEADER* b5 = nullptr; + BITMAPINFO* bi = nullptr; + int width = 0; + int height = 0; + uint16_t bit_count = 0; + uint32_t compression = 0; + uint32_t red_mask = 0; + uint32_t green_mask = 0; + uint32_t blue_mask = 0; + uint32_t alpha_mask = 0; + + BitmapInfo(); + + bool is_valid() const { + return (b5 || bi); + } + + void fill_spec(image_spec& spec); +}; + +} // namespace win +} // namespace clip + +#endif // CLIP_WIN_BMP_H_INCLUDED diff --git a/clip_win_wic.h b/clip_win_wic.h index 6d0a45a..fd0905a 100644 --- a/clip_win_wic.h +++ b/clip_win_wic.h @@ -8,6 +8,10 @@ #define CLIP_WIN_WIC_H_INCLUDED #pragma once +#if !CLIP_ENABLE_IMAGE + #error This file can be include only when CLIP_ENABLE_IMAGE is defined +#endif + #include #include