Skip to content

Commit

Permalink
[win] Move BitmapInfo to its own file (clip_win_bmp)
Browse files Browse the repository at this point in the history
  • Loading branch information
dacap committed Apr 11, 2024
1 parent 6bf6fbd commit 86e13a4
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 162 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
2 changes: 2 additions & 0 deletions clip_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#define CLIP_COMMON_H_INCLUDED
#pragma once

#include "clip.h"

namespace clip {
namespace details {

Expand Down
165 changes: 4 additions & 161 deletions clip_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -14,20 +16,6 @@
#include <string>
#include <vector>

#include <windows.h>

#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 {
Expand All @@ -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; shift<sizeof(unsigned long)*8; ++shift)
if (mask & (1 << shift))
return shift;
return shift;
}

class Hglobal {
public:
Hglobal() : m_handle(nullptr) {
Expand Down Expand Up @@ -74,143 +54,6 @@ class Hglobal {
HGLOBAL m_handle;
};

#if CLIP_ENABLE_IMAGE

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() {
// Use DIBV5 only for 32 bpp uncompressed bitmaps and when all
// masks are valid.
if (IsClipboardFormatAvailable(CF_DIBV5)) {
b5 = (BITMAPV5HEADER*)GetClipboardData(CF_DIBV5);
if (b5 &&
b5->bV5BitCount == 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<shifts+4; ++shift, ++mask) {
if (*mask)
*shift = get_shift_from_mask(*mask);
}
}

};

#endif // CLIP_ENABLE_IMAGE

}

lock::impl::impl(void* hwnd) : m_locked(false) {
Expand Down Expand Up @@ -539,7 +382,7 @@ bool lock::impl::get_image(image& output_img) const {
}
}

BitmapInfo bi;
win::BitmapInfo bi;
if (!bi.is_valid()) {
// There is no image at all in the clipboard, no need to report
// this as an error, just return false.
Expand Down Expand Up @@ -635,7 +478,7 @@ bool lock::impl::get_image_spec(image_spec& spec) const {
}
}

BitmapInfo bi;
win::BitmapInfo bi;
if (!bi.is_valid())
return false;
bi.fill_spec(spec);
Expand Down
26 changes: 26 additions & 0 deletions clip_win.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Clip Library
// Copyright (c) 2024 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#ifndef CLIP_WIN_H_INCLUDED
#define CLIP_WIN_H_INCLUDED
#pragma once

#include <windows.h>

#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
142 changes: 142 additions & 0 deletions clip_win_bmp.cpp
Original file line number Diff line number Diff line change
@@ -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; shift<sizeof(unsigned long)*8; ++shift)
if (mask & (1 << shift))
return shift;
return shift;
}

} // anonymous namespace

BitmapInfo::BitmapInfo() {
// Use DIBV5 only for 32 bpp uncompressed bitmaps and when all
// masks are valid.
if (IsClipboardFormatAvailable(CF_DIBV5)) {
b5 = (BITMAPV5HEADER*)GetClipboardData(CF_DIBV5);
if (b5 &&
b5->bV5BitCount == 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<shifts+4; ++shift, ++mask) {
if (*mask)
*shift = get_shift_from_mask(*mask);
}
}

} // namespace win
} // namespace clip
Loading

0 comments on commit 86e13a4

Please sign in to comment.