#include <wrapper.hpp>
template <typename T> uint8_t* _imp_copy_image(const clip::image& img, const size_t pixel_size = sizeof(T)) {
const clip::image_spec& spec = img.spec();
uint8_t* rgba = new uint8_t[spec.width * spec.height * 4];
for (unsigned long y = 0; y < spec.height; ++y) {
const char* p = img.data() + (y * spec.bytes_per_row);
for (unsigned long x = 0; x < spec.width; ++x, p += pixel_size) {
uint8_t* rgba_pixel = rgba + (y * spec.width + x) * 4;
T pixel = 0;
std::memcpy(&pixel, p, pixel_size);
rgba_pixel[0] = (uint8_t)((pixel & spec.red_mask) >> spec.red_shift);
rgba_pixel[1] = (uint8_t)((pixel & spec.green_mask) >> spec.green_shift);
rgba_pixel[2] = (uint8_t)((pixel & spec.blue_mask) >> spec.blue_shift);
if (spec.alpha_mask) {
rgba_pixel[3] = (uint8_t)((pixel & spec.alpha_mask) >> spec.alpha_shift);
} else {
rgba_pixel[3] = 255;
}
}
}
return rgba;
}
uint8_t* copy_image(const clip::image& img) {
switch (img.spec().bits_per_pixel) {
case 8: return _imp_copy_image<uint8_t>(img);
case 16: return _imp_copy_image<uint16_t>(img);
case 24: return _imp_copy_image<uint32_t>(img, 3);
case 32: return _imp_copy_image<uint32_t>(img);
case 64: return _imp_copy_image<uint64_t>(img);
default: return nullptr;
}
}
extern "C" TaggedClipperData clipper_get_tagged_data() {
clip::lock l;
if (!l.locked()) return { ClipperDataTagEmpty, {} };
{
clip::image img;
if (l.get_image(img)) {
uint8_t* rgba = copy_image(img);
if (rgba) {
ClipperData data;
data.image.rgba = rgba;
data.image.width = img.spec().width;
data.image.height = img.spec().height;
return { ClipperDataTagImage, data };
} else {
return { ClipperDataTagEmpty, {} };
}
}
}
{
size_t text_length = l.get_data_length(clip::text_format());
if (text_length > 0) {
ClipperData data;
char* text = new char[text_length];
l.get_data(clip::text_format(), text, text_length);
data.text.text = text;
data.text.length = text_length;
if (text[text_length - 1] == '\0') {
if (text_length == 1) {
delete[] text;
return { ClipperDataTagEmpty, {} };
} else {
data.text.length -= 1;
}
}
return { ClipperDataTagText, data };
}
}
return { ClipperDataTagEmpty, {} };
}
extern "C" ClipperSetClipboardResult clipper_set_tagged_data(TaggedClipperData tagged) {
clip::lock l;
if (!l.locked()) return ClipperSetClipboardResultLocked;
if (!l.clear()) return ClipperSetClipboardResultGenericFailure;
bool ok = false;
switch (tagged.tag) {
case ClipperDataTagEmpty: {
return ClipperSetClipboardResultOk;
}
case ClipperDataTagText: {
ok = l.set_data(clip::text_format(), tagged.data.text.text, tagged.data.text.length);
break;
}
case ClipperDataTagImage: {
clip::image_spec spec;
spec.width = tagged.data.image.width;
spec.height = tagged.data.image.height;
spec.bits_per_pixel = 32;
spec.bytes_per_row = spec.width * 4;
spec.red_mask = 0x000000FF;
spec.green_mask = 0x0000FF00;
spec.blue_mask = 0x00FF0000;
spec.alpha_mask = 0xFF000000;
spec.red_shift = 0;
spec.green_shift = 8;
spec.blue_shift = 16;
spec.alpha_shift = 24;
clip::image img(static_cast<const void*>(tagged.data.image.rgba), spec);
ok = l.set_image(img);
break;
}
}
return ok ? ClipperSetClipboardResultOk : ClipperSetClipboardResultGenericFailure;
}
extern "C" void clipper_free_tagged_data(TaggedClipperData tagged) {
if (tagged.tag == ClipperDataTagText) {
delete[] tagged.data.text.text;
} else if (tagged.tag == ClipperDataTagImage) {
delete[] tagged.data.image.rgba;
}
}