Added Windows support
This commit is contained in:
parent
bdb6ed78a9
commit
de6f7bae67
20 changed files with 68 additions and 2926 deletions
21
.vscode/c_cpp_properties.json
vendored
21
.vscode/c_cpp_properties.json
vendored
|
|
@ -13,9 +13,26 @@
|
|||
"compilerPath": "/usr/bin/clang++",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++20",
|
||||
"intelliSenseMode": "linux-clang-x64",
|
||||
"compileCommands": "${workspaceFolder}/Debug/compile_commands.json"
|
||||
"intelliSenseMode": "linux-clang-x64"
|
||||
//"compileCommands": "${workspaceFolder}/compile_commands.json"
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"includePath": [
|
||||
"${default}",
|
||||
"${workspaceRoot}/src/vendor/GLAD",
|
||||
"${workspaceRoot}/src/vendor",
|
||||
"${workspaceRoot}/src/ostd",
|
||||
"${workspaceRoot}/src"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "C:\\msys64\\ucrt64\\bin\\clang++",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++20",
|
||||
"intelliSenseMode": "linux-clang-x64"
|
||||
//"compileCommands": "${workspaceFolder}/compile_commands.json"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#Setup
|
||||
#-----------------------------------------------------------------------------------------
|
||||
set(CMAKE_CXX_COMPILER "clang++")
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(${PROJ_NAME} LANGUAGES C CXX)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
|
|
@ -27,33 +28,18 @@ message("** Building ${PROJ_NAME} ${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}")
|
|||
|
||||
#Sources
|
||||
#-----------------------------------------------------------------------------------------
|
||||
list(APPEND OSTD_VENDOR_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/clip.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/image.cpp
|
||||
)
|
||||
list(APPEND OGFX_VENDOR_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor/GLAD/glad.c
|
||||
)
|
||||
|
||||
list(APPEND INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_LIST_DIR}/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor/GLAD
|
||||
)
|
||||
|
||||
list(APPEND TEST_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/test/main.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/test/TestApp2D.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/test/TestApp3D.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/test/TetrisApp.cpp
|
||||
)
|
||||
list(APPEND OSH_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/osh/commandShell.cpp
|
||||
)
|
||||
list(APPEND OXGE_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/oxge/iso/Engine.cpp
|
||||
)
|
||||
list(APPEND OGFX_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/BitmapFont.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/BlendRenderer.cpp
|
||||
|
|
@ -73,8 +59,8 @@ list(APPEND OGFX_SOURCE_FILES
|
|||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Texture.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Window.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Widgets.cpp
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/DebugTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor/GLAD/glad.c
|
||||
)
|
||||
list(APPEND OSTD_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/BaseObject.cpp
|
||||
|
|
@ -99,24 +85,8 @@ list(APPEND OSTD_SOURCE_FILES
|
|||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/StringEditor.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ostd/Utils.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND OSTD_VENDOR_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/clip_win.cpp
|
||||
)
|
||||
endif (WIN32)
|
||||
if (UNIX)
|
||||
list(APPEND OSTD_VENDOR_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/vendor/clip/clip_x11.cpp
|
||||
)
|
||||
endif (UNIX)
|
||||
|
||||
list(APPEND OSTD_SOURCE_FILES ${OSTD_VENDOR_SOURCES})
|
||||
list(APPEND OGFX_SOURCE_FILES ${OGFX_VENDOR_SOURCES})
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#Targets
|
||||
#-----------------------------------------------------------------------------------------
|
||||
add_library(${OMNIA_STD_LIB} SHARED ${OSTD_SOURCE_FILES})
|
||||
|
|
@ -140,8 +110,6 @@ endif (UNIX)
|
|||
target_link_libraries(${OMNIA_GFX_LIB} PUBLIC sfml-system sfml-window sfml-graphics)
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#Linking Targets
|
||||
#-----------------------------------------------------------------------------------------
|
||||
target_link_libraries(${OMNIA_GFX_LIB} PUBLIC ${OMNIA_STD_LIB})
|
||||
|
|
@ -150,8 +118,6 @@ target_link_libraries(${TEST_TARGET} PUBLIC ${OMNIA_STD_LIB})
|
|||
target_link_libraries(${TEST_TARGET} PUBLIC ${OMNIA_GFX_LIB})
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#BuildNumber Target
|
||||
#-----------------------------------------------------------------------------------------
|
||||
if (WIN32)
|
||||
|
|
@ -174,8 +140,7 @@ add_custom_target(
|
|||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#Install
|
||||
#Finalize
|
||||
#-----------------------------------------------------------------------------------------
|
||||
#TODO: Change TEST_TARGET to last lib built, for release config
|
||||
add_custom_command(TARGET ${TEST_TARGET} POST_BUILD
|
||||
|
|
@ -183,12 +148,6 @@ add_custom_command(TARGET ${TEST_TARGET} POST_BUILD
|
|||
${CMAKE_SOURCE_DIR}/extra/ $<TARGET_FILE_DIR:${TEST_TARGET}>
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set(CMAKE_INSTALL_MESSAGE NEVER)
|
||||
install(TARGETS ${OMNIA_STD_LIB} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Build/bin)
|
||||
install(TARGETS ${OMNIA_GFX_LIB} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Build/bin)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/licences DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/Build)
|
||||
|
||||
add_custom_target(FinalMessage ALL ${CMAKE_COMMAND} -E cmake_echo_color --cyan "[100%] Built ${PROJ_NAME} ${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}")
|
||||
add_dependencies(FinalMessage ${TEST_TARGET})
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
|
|
|||
22
README.md
Normal file
22
README.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# OmniaFramework
|
||||
|
||||
Compile instructions on Windows
|
||||
|
||||
**Step 1:**
|
||||
download MSYS2 from https://www.msys2.org/ and install it
|
||||
|
||||
**Step 2:**
|
||||
run MSYS2, and in the terminal run:
|
||||
```
|
||||
pacman -Syuu
|
||||
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-clang mingw-w64-ucrt-x86_64-gdb mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-sfml mingw-w64-ucrt-x86_64-make
|
||||
```
|
||||
|
||||
**Step 3:**
|
||||
open a UCRT64/MSYS2 command prompt inside the root directory of the project
|
||||
|
||||
**Step 4:**
|
||||
execute this command:
|
||||
```
|
||||
./compile
|
||||
```
|
||||
21
compile
21
compile
|
|
@ -1,14 +1,15 @@
|
|||
#/bin/bash
|
||||
|
||||
rm -r Build
|
||||
rm -r bin
|
||||
#export CXX=/usr/bin/clang++
|
||||
cmake -B bin -S ./
|
||||
cd bin
|
||||
make install
|
||||
cd ..
|
||||
if [ $? -eq 0 ]; then
|
||||
printf "Installing includes...\n"
|
||||
python ./tools/create_includes.py
|
||||
printf "Done!\n"
|
||||
|
||||
if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
|
||||
cmake -B bin -S ./
|
||||
cd bin
|
||||
make
|
||||
cd ..
|
||||
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
|
||||
cmake -B bin -S ./ -G "MinGW Makefiles"
|
||||
cd bin
|
||||
mingw32-make.exe
|
||||
cd ..
|
||||
fi
|
||||
|
|
@ -24,10 +24,10 @@ namespace ostd
|
|||
if (!file.is_open()) return *this;
|
||||
m_buffer = { std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() };
|
||||
|
||||
m_extension = filePath.extension();
|
||||
m_fullPath = filePath;
|
||||
m_fullName = filePath.filename();
|
||||
m_name = filePath.stem();
|
||||
m_extension = filePath.extension().string();
|
||||
m_fullPath = filePath.string();
|
||||
m_fullName = filePath.filename().string();
|
||||
m_name = filePath.stem().string();
|
||||
StringEditor pathEditor(m_fullPath);
|
||||
if (pathEditor.contains('/'))
|
||||
m_directoryPath = pathEditor.substr(0, pathEditor.lastIndexOf('/'));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "Utils.hpp"
|
||||
#include "Defines.hpp"
|
||||
#include <TermColor.hpp>
|
||||
#include <clip/clip.h>
|
||||
//#include <clip/clip.h>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
|
|
@ -682,7 +682,7 @@ namespace ostd
|
|||
return std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now().time_since_epoch()).count() - Utils::s_startTime_ms;
|
||||
}
|
||||
|
||||
bool Utils::setClipboardText(String text)
|
||||
/*bool Utils::setClipboardText(String text)
|
||||
{
|
||||
return clip::set_text(text);
|
||||
}
|
||||
|
|
@ -692,7 +692,7 @@ namespace ostd
|
|||
String text = "";
|
||||
if (!clip::get_text(text)) return "";
|
||||
return text;
|
||||
}
|
||||
}*/
|
||||
|
||||
float Utils::map_value(float input, float input_start, float input_end, float output_start, float output_end)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -150,8 +150,9 @@ namespace ostd
|
|||
static String duplicateChar(unsigned char c, uint16_t count);
|
||||
static void sleep(uint32_t __time, eTimeUnits __unit = eTimeUnits::Milliseconds);
|
||||
static uint64_t getRunningTime_ms(void);
|
||||
static bool setClipboardText(String text);
|
||||
static String getClipboardText(void);
|
||||
//TODO: Doesn't work on Windows
|
||||
//static bool setClipboardText(String text);
|
||||
//static String getClipboardText(void);
|
||||
static float map_value(float input, float input_start, float input_end, float output_start, float output_end);
|
||||
static bool loadFileFromHppResource(String output_file_path, const char* resource_buffer, unsigned int size);
|
||||
static void printByteStream(const ByteStream& data, StreamIndex start, uint8_t line_len, uint16_t n_rows, IOutputHandler& out, int32_t addrHighlight = -1, uint32_t highlightRange = 1, const String& title = "");
|
||||
|
|
|
|||
174
src/vendor/clip/clip.cpp
vendored
174
src/vendor/clip/clip.cpp
vendored
|
|
@ -1,174 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (c) 2015-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "clip.h"
|
||||
#include "clip_lock_impl.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace clip {
|
||||
|
||||
namespace {
|
||||
|
||||
void default_error_handler(ErrorCode code) {
|
||||
static const char* err[] = {
|
||||
"Cannot lock clipboard",
|
||||
"Image format is not supported"
|
||||
};
|
||||
throw std::runtime_error(err[static_cast<int>(code)]);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
error_handler g_error_handler = default_error_handler;
|
||||
|
||||
lock::lock(void* native_window_handle)
|
||||
: p(new impl(native_window_handle)) {
|
||||
}
|
||||
|
||||
lock::~lock() = default;
|
||||
|
||||
bool lock::locked() const {
|
||||
return p->locked();
|
||||
}
|
||||
|
||||
bool lock::clear() {
|
||||
return p->clear();
|
||||
}
|
||||
|
||||
bool lock::is_convertible(format f) const {
|
||||
return p->is_convertible(f);
|
||||
}
|
||||
|
||||
bool lock::set_data(format f, const char* buf, size_t length) {
|
||||
return p->set_data(f, buf, length);
|
||||
}
|
||||
|
||||
bool lock::get_data(format f, char* buf, size_t len) const {
|
||||
return p->get_data(f, buf, len);
|
||||
}
|
||||
|
||||
size_t lock::get_data_length(format f) const {
|
||||
return p->get_data_length(f);
|
||||
}
|
||||
|
||||
bool lock::set_image(const image& img) {
|
||||
return p->set_image(img);
|
||||
}
|
||||
|
||||
bool lock::get_image(image& img) const {
|
||||
return p->get_image(img);
|
||||
}
|
||||
|
||||
bool lock::get_image_spec(image_spec& spec) const {
|
||||
return p->get_image_spec(spec);
|
||||
}
|
||||
|
||||
format empty_format() { return 0; }
|
||||
format text_format() { return 1; }
|
||||
format image_format() { return 2; }
|
||||
|
||||
bool has(format f) {
|
||||
lock l;
|
||||
if (l.locked())
|
||||
return l.is_convertible(f);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool clear() {
|
||||
lock l;
|
||||
if (l.locked())
|
||||
return l.clear();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set_text(const std::string& value) {
|
||||
lock l;
|
||||
if (l.locked()) {
|
||||
l.clear();
|
||||
return l.set_data(text_format(), value.c_str(), value.size());
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_text(std::string& value) {
|
||||
lock l;
|
||||
if (!l.locked())
|
||||
return false;
|
||||
|
||||
format f = text_format();
|
||||
if (!l.is_convertible(f))
|
||||
return false;
|
||||
|
||||
size_t len = l.get_data_length(f);
|
||||
if (len > 0) {
|
||||
std::vector<char> buf(len);
|
||||
l.get_data(f, &buf[0], len);
|
||||
value = &buf[0];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
value.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool set_image(const image& img) {
|
||||
lock l;
|
||||
if (l.locked()) {
|
||||
l.clear();
|
||||
return l.set_image(img);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_image(image& img) {
|
||||
lock l;
|
||||
if (!l.locked())
|
||||
return false;
|
||||
|
||||
format f = image_format();
|
||||
if (!l.is_convertible(f))
|
||||
return false;
|
||||
|
||||
return l.get_image(img);
|
||||
}
|
||||
|
||||
bool get_image_spec(image_spec& spec) {
|
||||
lock l;
|
||||
if (!l.locked())
|
||||
return false;
|
||||
|
||||
format f = image_format();
|
||||
if (!l.is_convertible(f))
|
||||
return false;
|
||||
|
||||
return l.get_image_spec(spec);
|
||||
}
|
||||
|
||||
void set_error_handler(error_handler handler) {
|
||||
g_error_handler = handler;
|
||||
}
|
||||
|
||||
error_handler get_error_handler() {
|
||||
return g_error_handler;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XCB_XLIB_H
|
||||
static int g_x11_timeout = 1000;
|
||||
void set_x11_wait_timeout(int msecs) { g_x11_timeout = msecs; }
|
||||
int get_x11_wait_timeout() { return g_x11_timeout; }
|
||||
#else
|
||||
void set_x11_wait_timeout(int) { }
|
||||
int get_x11_wait_timeout() { return 1000; }
|
||||
#endif
|
||||
|
||||
} // namespace clip
|
||||
180
src/vendor/clip/clip.h
vendored
180
src/vendor/clip/clip.h
vendored
|
|
@ -1,180 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (c) 2015-2022 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef CLIP_H_INCLUDED
|
||||
#define CLIP_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace clip {
|
||||
|
||||
// ======================================================================
|
||||
// Low-level API to lock the clipboard/pasteboard and modify it
|
||||
// ======================================================================
|
||||
|
||||
// Clipboard format identifier.
|
||||
typedef size_t format;
|
||||
|
||||
class image;
|
||||
struct image_spec;
|
||||
|
||||
class lock {
|
||||
public:
|
||||
// You can give your current HWND as the "native_window_handle."
|
||||
// Windows clipboard functions use this handle to open/close
|
||||
// (lock/unlock) the clipboard. From the MSDN documentation we
|
||||
// need this handler so SetClipboardData() doesn't fail after a
|
||||
// EmptyClipboard() call. Anyway it looks to work just fine if we
|
||||
// call OpenClipboard() with a null HWND.
|
||||
lock(void* native_window_handle = nullptr);
|
||||
~lock();
|
||||
|
||||
// Returns true if we've locked the clipboard successfully in
|
||||
// lock() constructor.
|
||||
bool locked() const;
|
||||
|
||||
// Clears the clipboard content. If you don't clear the content,
|
||||
// previous clipboard content (in unknown formats) could persist
|
||||
// after the unlock.
|
||||
bool clear();
|
||||
|
||||
// Returns true if the clipboard can be converted to the given
|
||||
// format.
|
||||
bool is_convertible(format f) const;
|
||||
bool set_data(format f, const char* buf, size_t len);
|
||||
bool get_data(format f, char* buf, size_t len) const;
|
||||
size_t get_data_length(format f) const;
|
||||
|
||||
// For images
|
||||
bool set_image(const image& image);
|
||||
bool get_image(image& image) const;
|
||||
bool get_image_spec(image_spec& spec) const;
|
||||
|
||||
private:
|
||||
class impl;
|
||||
std::unique_ptr<impl> p;
|
||||
};
|
||||
|
||||
format register_format(const std::string& name);
|
||||
|
||||
// This format is when the clipboard has no content.
|
||||
format empty_format();
|
||||
|
||||
// When the clipboard has UTF8 text.
|
||||
format text_format();
|
||||
|
||||
// When the clipboard has an image.
|
||||
format image_format();
|
||||
|
||||
// Returns true if the clipboard has content of the given type.
|
||||
bool has(format f);
|
||||
|
||||
// Clears the clipboard content.
|
||||
bool clear();
|
||||
|
||||
// ======================================================================
|
||||
// Error handling
|
||||
// ======================================================================
|
||||
|
||||
enum class ErrorCode {
|
||||
CannotLock,
|
||||
ImageNotSupported,
|
||||
};
|
||||
|
||||
typedef void (*error_handler)(ErrorCode code);
|
||||
|
||||
void set_error_handler(error_handler f);
|
||||
error_handler get_error_handler();
|
||||
|
||||
// ======================================================================
|
||||
// Text
|
||||
// ======================================================================
|
||||
|
||||
// High-level API to put/get UTF8 text in/from the clipboard. These
|
||||
// functions returns false in case of error.
|
||||
bool set_text(const std::string& value);
|
||||
bool get_text(std::string& value);
|
||||
|
||||
// ======================================================================
|
||||
// Image
|
||||
// ======================================================================
|
||||
|
||||
struct image_spec {
|
||||
unsigned long width = 0;
|
||||
unsigned long height = 0;
|
||||
unsigned long bits_per_pixel = 0;
|
||||
unsigned long bytes_per_row = 0;
|
||||
unsigned long red_mask = 0;
|
||||
unsigned long green_mask = 0;
|
||||
unsigned long blue_mask = 0;
|
||||
unsigned long alpha_mask = 0;
|
||||
unsigned long red_shift = 0;
|
||||
unsigned long green_shift = 0;
|
||||
unsigned long blue_shift = 0;
|
||||
unsigned long alpha_shift = 0;
|
||||
|
||||
unsigned long required_data_size() const;
|
||||
};
|
||||
|
||||
// The image data must contain straight RGB values
|
||||
// (non-premultiplied by alpha). The image retrieved from the
|
||||
// clipboard will be non-premultiplied too. Basically you will be
|
||||
// always dealing with straight alpha images.
|
||||
//
|
||||
// Details: Windows expects premultiplied images on its clipboard
|
||||
// content, so the library code make the proper conversion
|
||||
// automatically. macOS handles straight alpha directly, so there is
|
||||
// no conversion at all. Linux/X11 images are transferred in
|
||||
// image/png format which are specified in straight alpha.
|
||||
class image {
|
||||
public:
|
||||
image();
|
||||
image(const image_spec& spec);
|
||||
image(const void* data, const image_spec& spec);
|
||||
image(const image& image);
|
||||
image(image&& image);
|
||||
~image();
|
||||
|
||||
image& operator=(const image& image);
|
||||
image& operator=(image&& image);
|
||||
|
||||
char* data() const { return m_data; }
|
||||
const image_spec& spec() const { return m_spec; }
|
||||
|
||||
bool is_valid() const { return m_data != nullptr; }
|
||||
void reset();
|
||||
|
||||
private:
|
||||
void copy_image(const image& image);
|
||||
void move_image(image&& image);
|
||||
|
||||
bool m_own_data;
|
||||
char* m_data;
|
||||
image_spec m_spec;
|
||||
};
|
||||
|
||||
// High-level API to set/get an image in/from the clipboard. These
|
||||
// functions returns false in case of error.
|
||||
bool set_image(const image& img);
|
||||
bool get_image(image& img);
|
||||
bool get_image_spec(image_spec& spec);
|
||||
|
||||
// ======================================================================
|
||||
// Platform-specific
|
||||
// ======================================================================
|
||||
|
||||
// Only for X11: Sets the time (in milliseconds) that we must wait
|
||||
// for the selection/clipboard owner to receive the content. This
|
||||
// value is 1000 (one second) by default.
|
||||
void set_x11_wait_timeout(int msecs);
|
||||
int get_x11_wait_timeout();
|
||||
|
||||
} // namespace clip
|
||||
|
||||
#endif // CLIP_H_INCLUDED
|
||||
76
src/vendor/clip/clip_common.h
vendored
76
src/vendor/clip/clip_common.h
vendored
|
|
@ -1,76 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (C) 2020 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef CLIP_COMMON_H_INCLUDED
|
||||
#define CLIP_COMMON_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
namespace clip {
|
||||
namespace details {
|
||||
|
||||
inline void divide_rgb_by_alpha(image& img,
|
||||
bool hasAlphaGreaterThanZero = false) {
|
||||
const image_spec& spec = img.spec();
|
||||
|
||||
bool hasValidPremultipliedAlpha = true;
|
||||
|
||||
for (unsigned long y=0; y<spec.height; ++y) {
|
||||
const uint32_t* dst = (uint32_t*)(img.data()+y*spec.bytes_per_row);
|
||||
for (unsigned long x=0; x<spec.width; ++x, ++dst) {
|
||||
const uint32_t c = *dst;
|
||||
const int r = ((c & spec.red_mask ) >> spec.red_shift );
|
||||
const int g = ((c & spec.green_mask) >> spec.green_shift);
|
||||
const int b = ((c & spec.blue_mask ) >> spec.blue_shift );
|
||||
const int a = ((c & spec.alpha_mask) >> spec.alpha_shift);
|
||||
|
||||
if (a > 0)
|
||||
hasAlphaGreaterThanZero = true;
|
||||
if (r > a || g > a || b > a)
|
||||
hasValidPremultipliedAlpha = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned long y=0; y<spec.height; ++y) {
|
||||
uint32_t* dst = (uint32_t*)(img.data()+y*spec.bytes_per_row);
|
||||
for (unsigned long x=0; x<spec.width; ++x, ++dst) {
|
||||
const uint32_t c = *dst;
|
||||
int r = ((c & spec.red_mask ) >> spec.red_shift );
|
||||
int g = ((c & spec.green_mask) >> spec.green_shift);
|
||||
int b = ((c & spec.blue_mask ) >> spec.blue_shift );
|
||||
int a = ((c & spec.alpha_mask) >> spec.alpha_shift);
|
||||
|
||||
// If all alpha values = 0, we make the image opaque.
|
||||
if (!hasAlphaGreaterThanZero) {
|
||||
a = 255;
|
||||
|
||||
// We cannot change the image spec (e.g. spec.alpha_mask=0) to
|
||||
// make the image opaque, because the "spec" of the image is
|
||||
// read-only. The image spec used by the client is the one
|
||||
// returned by get_image_spec().
|
||||
}
|
||||
// If there is alpha information and it's pre-multiplied alpha
|
||||
else if (hasValidPremultipliedAlpha) {
|
||||
if (a > 0) {
|
||||
// Convert it to straight alpha
|
||||
r = r * 255 / a;
|
||||
g = g * 255 / a;
|
||||
b = b * 255 / a;
|
||||
}
|
||||
}
|
||||
|
||||
*dst =
|
||||
(r << spec.red_shift ) |
|
||||
(g << spec.green_shift) |
|
||||
(b << spec.blue_shift ) |
|
||||
(a << spec.alpha_shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace clip
|
||||
|
||||
#endif // CLIP_H_INCLUDED
|
||||
33
src/vendor/clip/clip_lock_impl.h
vendored
33
src/vendor/clip/clip_lock_impl.h
vendored
|
|
@ -1,33 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (c) 2015-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef CLIP_LOCK_IMPL_H_INCLUDED
|
||||
#define CLIP_LOCK_IMPL_H_INCLUDED
|
||||
|
||||
namespace clip {
|
||||
|
||||
class lock::impl {
|
||||
public:
|
||||
impl(void* native_window_handle);
|
||||
~impl();
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
bool clear();
|
||||
bool is_convertible(format f) const;
|
||||
bool set_data(format f, const char* buf, size_t len);
|
||||
bool get_data(format f, char* buf, size_t len) const;
|
||||
size_t get_data_length(format f) const;
|
||||
bool set_image(const image& image);
|
||||
bool get_image(image& image) const;
|
||||
bool get_image_spec(image_spec& spec) const;
|
||||
|
||||
private:
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
} // namespace clip
|
||||
|
||||
#endif
|
||||
646
src/vendor/clip/clip_win.cpp
vendored
646
src/vendor/clip/clip_win.cpp
vendored
|
|
@ -1,646 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (C) 2015-2020 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "clip.h"
|
||||
#include "clip_common.h"
|
||||
#include "clip_lock_impl.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "clip_win_wic.h"
|
||||
|
||||
#ifndef LCS_WINDOWS_COLOR_SPACE
|
||||
#define LCS_WINDOWS_COLOR_SPACE 'Win '
|
||||
#endif
|
||||
|
||||
#ifndef CF_DIBV5
|
||||
#define CF_DIBV5 17
|
||||
#endif
|
||||
|
||||
namespace clip {
|
||||
|
||||
namespace {
|
||||
|
||||
// Data type used as header for custom formats to indicate the exact
|
||||
// size of the user custom data. This is necessary because it looks
|
||||
// like GlobalSize() might not return the exact size, but a greater
|
||||
// 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) {
|
||||
}
|
||||
|
||||
explicit Hglobal(HGLOBAL handle) : m_handle(handle) {
|
||||
}
|
||||
|
||||
explicit Hglobal(size_t len) : m_handle(GlobalAlloc(GHND, len)) {
|
||||
}
|
||||
|
||||
~Hglobal() {
|
||||
if (m_handle)
|
||||
GlobalFree(m_handle);
|
||||
}
|
||||
|
||||
void release() {
|
||||
m_handle = nullptr;
|
||||
}
|
||||
|
||||
operator HGLOBAL() {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
private:
|
||||
HGLOBAL m_handle;
|
||||
};
|
||||
|
||||
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:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
lock::impl::impl(void* hwnd) : m_locked(false) {
|
||||
for (int i=0; i<5; ++i) {
|
||||
if (OpenClipboard((HWND)hwnd)) {
|
||||
m_locked = true;
|
||||
break;
|
||||
}
|
||||
Sleep(20);
|
||||
}
|
||||
|
||||
if (!m_locked) {
|
||||
error_handler e = get_error_handler();
|
||||
if (e)
|
||||
e(ErrorCode::CannotLock);
|
||||
}
|
||||
}
|
||||
|
||||
lock::impl::~impl() {
|
||||
if (m_locked)
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
bool lock::impl::clear() {
|
||||
return (EmptyClipboard() ? true: false);
|
||||
}
|
||||
|
||||
bool lock::impl::is_convertible(format f) const {
|
||||
if (f == text_format()) {
|
||||
return
|
||||
(IsClipboardFormatAvailable(CF_TEXT) ||
|
||||
IsClipboardFormatAvailable(CF_UNICODETEXT) ||
|
||||
IsClipboardFormatAvailable(CF_OEMTEXT));
|
||||
}
|
||||
else if (f == image_format()) {
|
||||
return (IsClipboardFormatAvailable(CF_DIB) ? true: false);
|
||||
}
|
||||
else if (IsClipboardFormatAvailable(f))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lock::impl::set_data(format f, const char* buf, size_t len) {
|
||||
bool result = false;
|
||||
|
||||
if (f == text_format()) {
|
||||
if (len > 0) {
|
||||
int reqsize = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0);
|
||||
if (reqsize > 0) {
|
||||
++reqsize;
|
||||
|
||||
Hglobal hglobal(sizeof(WCHAR)*reqsize);
|
||||
LPWSTR lpstr = static_cast<LPWSTR>(GlobalLock(hglobal));
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, len, lpstr, reqsize);
|
||||
GlobalUnlock(hglobal);
|
||||
|
||||
result = (SetClipboardData(CF_UNICODETEXT, hglobal)) ? true: false;
|
||||
if (result)
|
||||
hglobal.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Hglobal hglobal(len+sizeof(CustomSizeT));
|
||||
if (hglobal) {
|
||||
auto dst = (uint8_t*)GlobalLock(hglobal);
|
||||
if (dst) {
|
||||
*((CustomSizeT*)dst) = len;
|
||||
memcpy(dst+sizeof(CustomSizeT), buf, len);
|
||||
GlobalUnlock(hglobal);
|
||||
result = (SetClipboardData(f, hglobal) ? true: false);
|
||||
if (result)
|
||||
hglobal.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lock::impl::get_data(format f, char* buf, size_t len) const {
|
||||
assert(buf);
|
||||
|
||||
if (!buf || !is_convertible(f))
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (f == text_format()) {
|
||||
if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
|
||||
HGLOBAL hglobal = GetClipboardData(CF_UNICODETEXT);
|
||||
if (hglobal) {
|
||||
LPWSTR lpstr = static_cast<LPWSTR>(GlobalLock(hglobal));
|
||||
if (lpstr) {
|
||||
size_t reqsize =
|
||||
WideCharToMultiByte(CP_UTF8, 0, lpstr, -1,
|
||||
nullptr, 0, nullptr, nullptr);
|
||||
|
||||
assert(reqsize <= len);
|
||||
if (reqsize <= len) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, lpstr, -1,
|
||||
buf, reqsize, nullptr, nullptr);
|
||||
result = true;
|
||||
}
|
||||
GlobalUnlock(hglobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsClipboardFormatAvailable(CF_TEXT)) {
|
||||
HGLOBAL hglobal = GetClipboardData(CF_TEXT);
|
||||
if (hglobal) {
|
||||
LPSTR lpstr = static_cast<LPSTR>(GlobalLock(hglobal));
|
||||
if (lpstr) {
|
||||
// TODO check length
|
||||
memcpy(buf, lpstr, len);
|
||||
result = true;
|
||||
GlobalUnlock(hglobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (IsClipboardFormatAvailable(f)) {
|
||||
HGLOBAL hglobal = GetClipboardData(f);
|
||||
if (hglobal) {
|
||||
const SIZE_T total_size = GlobalSize(hglobal);
|
||||
auto ptr = (const uint8_t*)GlobalLock(hglobal);
|
||||
if (ptr) {
|
||||
CustomSizeT reqsize = *((CustomSizeT*)ptr);
|
||||
|
||||
// If the registered length of data in the first CustomSizeT
|
||||
// number of bytes of the hglobal data is greater than the
|
||||
// GlobalSize(hglobal), something is wrong, it should not
|
||||
// happen.
|
||||
assert(reqsize <= total_size);
|
||||
if (reqsize > total_size)
|
||||
reqsize = total_size - sizeof(CustomSizeT);
|
||||
|
||||
if (reqsize <= len) {
|
||||
memcpy(buf, ptr+sizeof(CustomSizeT), reqsize);
|
||||
result = true;
|
||||
}
|
||||
GlobalUnlock(hglobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t lock::impl::get_data_length(format f) const {
|
||||
size_t len = 0;
|
||||
|
||||
if (f == text_format()) {
|
||||
if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
|
||||
HGLOBAL hglobal = GetClipboardData(CF_UNICODETEXT);
|
||||
if (hglobal) {
|
||||
LPWSTR lpstr = static_cast<LPWSTR>(GlobalLock(hglobal));
|
||||
if (lpstr) {
|
||||
len =
|
||||
WideCharToMultiByte(CP_UTF8, 0, lpstr, -1,
|
||||
nullptr, 0, nullptr, nullptr);
|
||||
GlobalUnlock(hglobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsClipboardFormatAvailable(CF_TEXT)) {
|
||||
HGLOBAL hglobal = GetClipboardData(CF_TEXT);
|
||||
if (hglobal) {
|
||||
LPSTR lpstr = (LPSTR)GlobalLock(hglobal);
|
||||
if (lpstr) {
|
||||
len = strlen(lpstr) + 1;
|
||||
GlobalUnlock(hglobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (f != empty_format()) {
|
||||
if (IsClipboardFormatAvailable(f)) {
|
||||
HGLOBAL hglobal = GetClipboardData(f);
|
||||
if (hglobal) {
|
||||
const SIZE_T total_size = GlobalSize(hglobal);
|
||||
auto ptr = (const uint8_t*)GlobalLock(hglobal);
|
||||
if (ptr) {
|
||||
len = *((CustomSizeT*)ptr);
|
||||
|
||||
assert(len <= total_size);
|
||||
if (len > total_size)
|
||||
len = total_size - sizeof(CustomSizeT);
|
||||
|
||||
GlobalUnlock(hglobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool lock::impl::set_image(const image& image) {
|
||||
const image_spec& spec = image.spec();
|
||||
|
||||
// Add the PNG clipboard format for images with alpha channel
|
||||
// (useful to communicate with some Windows programs that only use
|
||||
// alpha data from PNG clipboard format)
|
||||
if (spec.bits_per_pixel == 32 &&
|
||||
spec.alpha_mask) {
|
||||
UINT png_format = RegisterClipboardFormatA("PNG");
|
||||
if (png_format) {
|
||||
Hglobal png_handle(win::write_png(image));
|
||||
if (png_handle)
|
||||
SetClipboardData(png_format, png_handle);
|
||||
}
|
||||
}
|
||||
|
||||
image_spec out_spec = spec;
|
||||
|
||||
int palette_colors = 0;
|
||||
int padding = 0;
|
||||
switch (spec.bits_per_pixel) {
|
||||
case 24: padding = (4-((spec.width*3)&3))&3; break;
|
||||
case 16: padding = ((4-((spec.width*2)&3))&3)/2; break;
|
||||
case 8: padding = (4-(spec.width&3))&3; break;
|
||||
}
|
||||
out_spec.bytes_per_row += padding;
|
||||
|
||||
// Create the BITMAPV5HEADER structure
|
||||
Hglobal hmem(
|
||||
GlobalAlloc(
|
||||
GHND,
|
||||
sizeof(BITMAPV5HEADER)
|
||||
+ palette_colors*sizeof(RGBQUAD)
|
||||
+ out_spec.bytes_per_row*out_spec.height));
|
||||
if (!hmem)
|
||||
return false;
|
||||
|
||||
out_spec.red_mask = 0x00ff0000;
|
||||
out_spec.green_mask = 0xff00;
|
||||
out_spec.blue_mask = 0xff;
|
||||
out_spec.alpha_mask = 0xff000000;
|
||||
out_spec.red_shift = 16;
|
||||
out_spec.green_shift = 8;
|
||||
out_spec.blue_shift = 0;
|
||||
out_spec.alpha_shift = 24;
|
||||
|
||||
BITMAPV5HEADER* bi = (BITMAPV5HEADER*)GlobalLock(hmem);
|
||||
bi->bV5Size = sizeof(BITMAPV5HEADER);
|
||||
bi->bV5Width = out_spec.width;
|
||||
bi->bV5Height = out_spec.height;
|
||||
bi->bV5Planes = 1;
|
||||
bi->bV5BitCount = (WORD)out_spec.bits_per_pixel;
|
||||
bi->bV5Compression = BI_RGB;
|
||||
bi->bV5SizeImage = out_spec.bytes_per_row*spec.height;
|
||||
bi->bV5RedMask = out_spec.red_mask;
|
||||
bi->bV5GreenMask = out_spec.green_mask;
|
||||
bi->bV5BlueMask = out_spec.blue_mask;
|
||||
bi->bV5AlphaMask = out_spec.alpha_mask;
|
||||
bi->bV5CSType = LCS_WINDOWS_COLOR_SPACE;
|
||||
bi->bV5Intent = LCS_GM_GRAPHICS;
|
||||
bi->bV5ClrUsed = 0;
|
||||
|
||||
switch (spec.bits_per_pixel) {
|
||||
case 32: {
|
||||
const char* src = image.data();
|
||||
char* dst = (((char*)bi)+bi->bV5Size) + (out_spec.height-1)*out_spec.bytes_per_row;
|
||||
for (long y=spec.height-1; y>=0; --y) {
|
||||
const uint32_t* src_x = (const uint32_t*)src;
|
||||
uint32_t* dst_x = (uint32_t*)dst;
|
||||
|
||||
for (unsigned long x=0; x<spec.width; ++x, ++src_x, ++dst_x) {
|
||||
uint32_t c = *src_x;
|
||||
int r = ((c & spec.red_mask ) >> spec.red_shift );
|
||||
int g = ((c & spec.green_mask) >> spec.green_shift);
|
||||
int b = ((c & spec.blue_mask ) >> spec.blue_shift );
|
||||
int a = ((c & spec.alpha_mask) >> spec.alpha_shift);
|
||||
|
||||
// Windows requires premultiplied RGBA values
|
||||
r = r * a / 255;
|
||||
g = g * a / 255;
|
||||
b = b * a / 255;
|
||||
|
||||
*dst_x =
|
||||
(r << out_spec.red_shift ) |
|
||||
(g << out_spec.green_shift) |
|
||||
(b << out_spec.blue_shift ) |
|
||||
(a << out_spec.alpha_shift);
|
||||
}
|
||||
|
||||
src += spec.bytes_per_row;
|
||||
dst -= out_spec.bytes_per_row;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error_handler e = get_error_handler();
|
||||
if (e)
|
||||
e(ErrorCode::ImageNotSupported);
|
||||
return false;
|
||||
}
|
||||
|
||||
GlobalUnlock(hmem);
|
||||
SetClipboardData(CF_DIBV5, hmem);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lock::impl::get_image(image& output_img) const {
|
||||
// Get the "PNG" clipboard format (this is useful only for 32bpp
|
||||
// images with alpha channel, in other case we can use the regular
|
||||
// DIB format)
|
||||
UINT png_format = RegisterClipboardFormatA("PNG");
|
||||
if (png_format && IsClipboardFormatAvailable(png_format)) {
|
||||
HANDLE png_handle = GetClipboardData(png_format);
|
||||
if (png_handle) {
|
||||
size_t png_size = GlobalSize(png_handle);
|
||||
uint8_t* png_data = (uint8_t*)GlobalLock(png_handle);
|
||||
bool result = win::read_png(png_data, png_size, &output_img, nullptr);
|
||||
GlobalUnlock(png_handle);
|
||||
if (result)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
return false;
|
||||
}
|
||||
|
||||
image_spec spec;
|
||||
bi.fill_spec(spec);
|
||||
image img(spec);
|
||||
|
||||
switch (bi.bit_count) {
|
||||
|
||||
case 32:
|
||||
case 24:
|
||||
case 16: {
|
||||
const uint8_t* src = nullptr;
|
||||
|
||||
if (bi.compression == BI_RGB ||
|
||||
bi.compression == BI_BITFIELDS) {
|
||||
if (bi.b5)
|
||||
src = ((uint8_t*)bi.b5) + bi.b5->bV5Size;
|
||||
else
|
||||
src = ((uint8_t*)bi.bi) + bi.bi->bmiHeader.biSize;
|
||||
if (bi.compression == BI_BITFIELDS)
|
||||
src += sizeof(RGBQUAD)*3;
|
||||
}
|
||||
|
||||
if (src) {
|
||||
const int src_bytes_per_row = spec.width*((bi.bit_count+7)/8);
|
||||
const int padding = (4-(src_bytes_per_row&3))&3;
|
||||
|
||||
for (long y=spec.height-1; y>=0; --y, src+=src_bytes_per_row+padding) {
|
||||
char* dst = img.data()+y*spec.bytes_per_row;
|
||||
std::copy(src, src+src_bytes_per_row, dst);
|
||||
}
|
||||
}
|
||||
|
||||
// Windows uses premultiplied RGB values, and we use straight
|
||||
// alpha. So we have to divide all RGB values by its alpha.
|
||||
if (bi.bit_count == 32 && spec.alpha_mask) {
|
||||
details::divide_rgb_by_alpha(img);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 8: {
|
||||
assert(bi.bi);
|
||||
|
||||
const int colors = (bi.bi->bmiHeader.biClrUsed > 0 ? bi.bi->bmiHeader.biClrUsed: 256);
|
||||
std::vector<uint32_t> palette(colors);
|
||||
for (int c=0; c<colors; ++c) {
|
||||
palette[c] =
|
||||
(bi.bi->bmiColors[c].rgbRed << spec.red_shift) |
|
||||
(bi.bi->bmiColors[c].rgbGreen << spec.green_shift) |
|
||||
(bi.bi->bmiColors[c].rgbBlue << spec.blue_shift);
|
||||
}
|
||||
|
||||
const uint8_t* src = (((uint8_t*)bi.bi) + bi.bi->bmiHeader.biSize + sizeof(RGBQUAD)*colors);
|
||||
const int padding = (4-(spec.width&3))&3;
|
||||
|
||||
for (long y=spec.height-1; y>=0; --y, src+=padding) {
|
||||
char* dst = img.data()+y*spec.bytes_per_row;
|
||||
|
||||
for (unsigned long x=0; x<spec.width; ++x, ++src, dst+=3) {
|
||||
int idx = *src;
|
||||
if (idx < 0)
|
||||
idx = 0;
|
||||
else if (idx >= colors)
|
||||
idx = colors-1;
|
||||
|
||||
*((uint32_t*)dst) = palette[idx];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(output_img, img);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lock::impl::get_image_spec(image_spec& spec) const {
|
||||
UINT png_format = RegisterClipboardFormatA("PNG");
|
||||
if (png_format && IsClipboardFormatAvailable(png_format)) {
|
||||
HANDLE png_handle = GetClipboardData(png_format);
|
||||
if (png_handle) {
|
||||
size_t png_size = GlobalSize(png_handle);
|
||||
uint8_t* png_data = (uint8_t*)GlobalLock(png_handle);
|
||||
bool result = win::read_png(png_data, png_size, nullptr, &spec);
|
||||
GlobalUnlock(png_handle);
|
||||
if (result)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BitmapInfo bi;
|
||||
if (!bi.is_valid())
|
||||
return false;
|
||||
bi.fill_spec(spec);
|
||||
return true;
|
||||
}
|
||||
|
||||
format register_format(const std::string& name) {
|
||||
int reqsize = 1+MultiByteToWideChar(CP_UTF8, 0,
|
||||
name.c_str(), name.size(), NULL, 0);
|
||||
std::vector<WCHAR> buf(reqsize);
|
||||
MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name.size(),
|
||||
&buf[0], reqsize);
|
||||
|
||||
// From MSDN, registered clipboard formats are identified by values
|
||||
// in the range 0xC000 through 0xFFFF.
|
||||
return (format)RegisterClipboardFormatW(&buf[0]);
|
||||
}
|
||||
|
||||
} // namespace clip
|
||||
246
src/vendor/clip/clip_win_wic.h
vendored
246
src/vendor/clip/clip_win_wic.h
vendored
|
|
@ -1,246 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (c) 2020 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "clip.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <shlwapi.h>
|
||||
#include <wincodec.h>
|
||||
|
||||
namespace clip {
|
||||
namespace win {
|
||||
|
||||
// Successful calls to CoInitialize() (S_OK or S_FALSE) must match
|
||||
// the calls to CoUninitialize().
|
||||
// From: https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize#remarks
|
||||
struct coinit {
|
||||
HRESULT hr;
|
||||
coinit() {
|
||||
hr = CoInitialize(nullptr);
|
||||
}
|
||||
~coinit() {
|
||||
if (hr == S_OK || hr == S_FALSE)
|
||||
CoUninitialize();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class comptr {
|
||||
public:
|
||||
comptr() : m_ptr(nullptr) { }
|
||||
explicit comptr(T* ptr) : m_ptr(ptr) { }
|
||||
comptr(const comptr&) = delete;
|
||||
comptr& operator=(const comptr&) = delete;
|
||||
~comptr() { reset(); }
|
||||
|
||||
T** operator&() { return &m_ptr; }
|
||||
T* operator->() { return m_ptr; }
|
||||
bool operator!() const { return !m_ptr; }
|
||||
|
||||
T* get() { return m_ptr; }
|
||||
void reset() {
|
||||
if (m_ptr) {
|
||||
m_ptr->Release();
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
private:
|
||||
T* m_ptr;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Encode the image as PNG format
|
||||
|
||||
bool write_png_on_stream(const image& image,
|
||||
IStream* stream) {
|
||||
const image_spec& spec = image.spec();
|
||||
|
||||
comptr<IWICBitmapEncoder> encoder;
|
||||
HRESULT hr = CoCreateInstance(CLSID_WICPngEncoder,
|
||||
nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&encoder));
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = encoder->Initialize(stream, WICBitmapEncoderNoCache);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
comptr<IWICBitmapFrameEncode> frame;
|
||||
comptr<IPropertyBag2> options;
|
||||
hr = encoder->CreateNewFrame(&frame, &options);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = frame->Initialize(options.get());
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
// PNG encoder (and decoder) only supports GUID_WICPixelFormat32bppBGRA for 32bpp.
|
||||
// See: https://docs.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats#png-native-codec
|
||||
WICPixelFormatGUID pixelFormat = GUID_WICPixelFormat32bppBGRA;
|
||||
hr = frame->SetPixelFormat(&pixelFormat);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = frame->SetSize(spec.width, spec.height);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
std::vector<uint32_t> buf;
|
||||
uint8_t* ptr = (uint8_t*)image.data();
|
||||
int bytes_per_row = spec.bytes_per_row;
|
||||
|
||||
// Convert to GUID_WICPixelFormat32bppBGRA if needed
|
||||
if (spec.red_mask != 0xff0000 ||
|
||||
spec.green_mask != 0xff00 ||
|
||||
spec.blue_mask != 0xff ||
|
||||
spec.alpha_mask != 0xff000000) {
|
||||
buf.resize(spec.width * spec.height);
|
||||
uint32_t* dst = (uint32_t*)&buf[0];
|
||||
uint32_t* src = (uint32_t*)image.data();
|
||||
for (int y=0; y<spec.height; ++y) {
|
||||
auto src_line_start = src;
|
||||
for (int x=0; x<spec.width; ++x) {
|
||||
uint32_t c = *src;
|
||||
*dst = ((((c & spec.red_mask ) >> spec.red_shift ) << 16) |
|
||||
(((c & spec.green_mask) >> spec.green_shift) << 8) |
|
||||
(((c & spec.blue_mask ) >> spec.blue_shift ) ) |
|
||||
(((c & spec.alpha_mask) >> spec.alpha_shift) << 24));
|
||||
++dst;
|
||||
++src;
|
||||
}
|
||||
src = (uint32_t*)(((uint8_t*)src_line_start) + spec.bytes_per_row);
|
||||
}
|
||||
ptr = (uint8_t*)&buf[0];
|
||||
bytes_per_row = 4 * spec.width;
|
||||
}
|
||||
|
||||
hr = frame->WritePixels(spec.height,
|
||||
bytes_per_row,
|
||||
bytes_per_row * spec.height,
|
||||
(BYTE*)ptr);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = frame->Commit();
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = encoder->Commit();
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HGLOBAL write_png(const image& image) {
|
||||
coinit com;
|
||||
|
||||
comptr<IStream> stream;
|
||||
HRESULT hr = CreateStreamOnHGlobal(nullptr, false, &stream);
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
bool result = write_png_on_stream(image, stream.get());
|
||||
|
||||
HGLOBAL handle;
|
||||
hr = GetHGlobalFromStream(stream.get(), &handle);
|
||||
if (result)
|
||||
return handle;
|
||||
|
||||
GlobalFree(handle);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Decode the clipboard data from PNG format
|
||||
|
||||
bool read_png(const uint8_t* buf,
|
||||
const UINT len,
|
||||
image* output_image,
|
||||
image_spec* output_spec) {
|
||||
coinit com;
|
||||
|
||||
comptr<IStream> stream(SHCreateMemStream(buf, len));
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
comptr<IWICBitmapDecoder> decoder;
|
||||
HRESULT hr = CoCreateInstance(CLSID_WICPngDecoder2,
|
||||
nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&decoder));
|
||||
if (FAILED(hr)) {
|
||||
hr = CoCreateInstance(CLSID_WICPngDecoder1,
|
||||
nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&decoder));
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = decoder->Initialize(stream.get(), WICDecodeMetadataCacheOnDemand);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
comptr<IWICBitmapFrameDecode> frame;
|
||||
hr = decoder->GetFrame(0, &frame);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
WICPixelFormatGUID pixelFormat;
|
||||
hr = frame->GetPixelFormat(&pixelFormat);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
// Only support this pixel format
|
||||
// TODO add support for more pixel formats
|
||||
if (pixelFormat != GUID_WICPixelFormat32bppBGRA)
|
||||
return false;
|
||||
|
||||
UINT width = 0, height = 0;
|
||||
hr = frame->GetSize(&width, &height);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
image_spec spec;
|
||||
spec.width = width;
|
||||
spec.height = height;
|
||||
spec.bits_per_pixel = 32;
|
||||
spec.bytes_per_row = 4 * width;
|
||||
spec.red_mask = 0xff0000;
|
||||
spec.green_mask = 0xff00;
|
||||
spec.blue_mask = 0xff;
|
||||
spec.alpha_mask = 0xff000000;
|
||||
spec.red_shift = 16;
|
||||
spec.green_shift = 8;
|
||||
spec.blue_shift = 0;
|
||||
spec.alpha_shift = 24;
|
||||
|
||||
if (output_spec)
|
||||
*output_spec = spec;
|
||||
|
||||
if (output_image) {
|
||||
image img(spec);
|
||||
|
||||
hr = frame->CopyPixels(
|
||||
nullptr, // Entire bitmap
|
||||
spec.bytes_per_row,
|
||||
spec.bytes_per_row * spec.height,
|
||||
(BYTE*)img.data());
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::swap(*output_image, img);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace win
|
||||
} // namespace clip
|
||||
1094
src/vendor/clip/clip_x11.cpp
vendored
1094
src/vendor/clip/clip_x11.cpp
vendored
File diff suppressed because it is too large
Load diff
230
src/vendor/clip/clip_x11_png.h
vendored
230
src/vendor/clip/clip_x11_png.h
vendored
|
|
@ -1,230 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (c) 2018-2021 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "clip.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "png.h"
|
||||
|
||||
namespace clip {
|
||||
namespace x11 {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Functions to convert clip::image into png data to store it in the
|
||||
// clipboard.
|
||||
|
||||
void write_data_fn(png_structp png, png_bytep buf, png_size_t len) {
|
||||
std::vector<uint8_t>& output = *(std::vector<uint8_t>*)png_get_io_ptr(png);
|
||||
const size_t i = output.size();
|
||||
output.resize(i+len);
|
||||
std::copy(buf, buf+len, output.begin()+i);
|
||||
}
|
||||
|
||||
bool write_png(const image& image,
|
||||
std::vector<uint8_t>& output) {
|
||||
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
nullptr, nullptr, nullptr);
|
||||
if (!png)
|
||||
return false;
|
||||
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if (!info) {
|
||||
png_destroy_write_struct(&png, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_write_struct(&png, &info);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_write_fn(png,
|
||||
(png_voidp)&output,
|
||||
write_data_fn,
|
||||
nullptr); // No need for a flush function
|
||||
|
||||
const image_spec& spec = image.spec();
|
||||
int color_type = (spec.alpha_mask ?
|
||||
PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
PNG_COLOR_TYPE_RGB);
|
||||
|
||||
png_set_IHDR(png, info,
|
||||
spec.width, spec.height, 8, color_type,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
png_write_info(png, info);
|
||||
png_set_packing(png);
|
||||
|
||||
png_bytep row =
|
||||
(png_bytep)png_malloc(png, png_get_rowbytes(png, info));
|
||||
|
||||
for (png_uint_32 y=0; y<spec.height; ++y) {
|
||||
const uint32_t* src =
|
||||
(const uint32_t*)(((const uint8_t*)image.data())
|
||||
+ y*spec.bytes_per_row);
|
||||
uint8_t* dst = row;
|
||||
unsigned int x, c;
|
||||
|
||||
for (x=0; x<spec.width; x++) {
|
||||
c = *(src++);
|
||||
*(dst++) = (c & spec.red_mask ) >> spec.red_shift;
|
||||
*(dst++) = (c & spec.green_mask) >> spec.green_shift;
|
||||
*(dst++) = (c & spec.blue_mask ) >> spec.blue_shift;
|
||||
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
||||
*(dst++) = (c & spec.alpha_mask) >> spec.alpha_shift;
|
||||
}
|
||||
|
||||
png_write_rows(png, &row, 1);
|
||||
}
|
||||
|
||||
png_free(png, row);
|
||||
png_write_end(png, info);
|
||||
png_destroy_write_struct(&png, &info);
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Functions to convert png data stored in the clipboard to a
|
||||
// clip::image.
|
||||
|
||||
struct read_png_io {
|
||||
const uint8_t* buf;
|
||||
size_t len;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
void read_data_fn(png_structp png, png_bytep buf, png_size_t len) {
|
||||
read_png_io& io = *(read_png_io*)png_get_io_ptr(png);
|
||||
if (io.pos < io.len) {
|
||||
size_t n = std::min(len, io.len-io.pos);
|
||||
if (n > 0) {
|
||||
std::copy(io.buf+io.pos,
|
||||
io.buf+io.pos+n,
|
||||
buf);
|
||||
io.pos += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool read_png(const uint8_t* buf,
|
||||
const size_t len,
|
||||
image* output_image,
|
||||
image_spec* output_spec) {
|
||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
||||
nullptr, nullptr, nullptr);
|
||||
if (!png)
|
||||
return false;
|
||||
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if (!info) {
|
||||
png_destroy_read_struct(&png, nullptr, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_read_struct(&png, &info, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
read_png_io io = { buf, len, 0 };
|
||||
png_set_read_fn(png, (png_voidp)&io, read_data_fn);
|
||||
|
||||
png_read_info(png, info);
|
||||
|
||||
png_uint_32 width, height;
|
||||
int bit_depth, color_type, interlace_type;
|
||||
png_get_IHDR(png, info, &width, &height,
|
||||
&bit_depth, &color_type,
|
||||
&interlace_type,
|
||||
nullptr, nullptr);
|
||||
|
||||
image_spec spec;
|
||||
spec.width = width;
|
||||
spec.height = height;
|
||||
spec.bits_per_pixel = 32;
|
||||
|
||||
// Don't use png_get_rowbytes(png, info) here because this is the
|
||||
// bytes_per_row of the output clip::image (the png file could
|
||||
// contain 24bpp but we want to return a 32bpp anyway with alpha=255
|
||||
// in that case).
|
||||
spec.bytes_per_row = 4*width;
|
||||
|
||||
spec.red_mask = 0x000000ff;
|
||||
spec.green_mask = 0x0000ff00;
|
||||
spec.blue_mask = 0x00ff0000;
|
||||
spec.red_shift = 0;
|
||||
spec.green_shift = 8;
|
||||
spec.blue_shift = 16;
|
||||
|
||||
if ((color_type & PNG_COLOR_MASK_ALPHA) == PNG_COLOR_MASK_ALPHA) {
|
||||
spec.alpha_mask = 0xff000000;
|
||||
spec.alpha_shift = 24;
|
||||
}
|
||||
else {
|
||||
spec.alpha_mask = 0;
|
||||
spec.alpha_shift = 0;
|
||||
}
|
||||
|
||||
if (output_spec)
|
||||
*output_spec = spec;
|
||||
|
||||
if (output_image &&
|
||||
width > 0 &&
|
||||
height > 0) {
|
||||
image img(spec);
|
||||
|
||||
// We want RGB 24-bit or RGBA 32-bit as a result
|
||||
png_set_strip_16(png); // Down to 8-bit (TODO we might support 16-bit values)
|
||||
png_set_packing(png); // Use one byte if color depth < 8-bit
|
||||
png_set_expand_gray_1_2_4_to_8(png);
|
||||
png_set_palette_to_rgb(png);
|
||||
png_set_gray_to_rgb(png);
|
||||
png_set_tRNS_to_alpha(png);
|
||||
|
||||
int number_passes = png_set_interlace_handling(png);
|
||||
png_read_update_info(png, info);
|
||||
|
||||
const int src_bytes_per_row = png_get_rowbytes(png, info);
|
||||
png_bytepp rows = (png_bytepp)png_malloc(png, sizeof(png_bytep)*height);
|
||||
png_uint_32 y;
|
||||
for (y=0; y<height; ++y)
|
||||
rows[y] = (png_bytep)png_malloc(png, src_bytes_per_row);
|
||||
|
||||
for (int pass=0; pass<number_passes; ++pass)
|
||||
for (y=0; y<height; ++y)
|
||||
png_read_rows(png, rows+y, nullptr, 1);
|
||||
|
||||
for (y=0; y<height; ++y) {
|
||||
const uint8_t* src = rows[y];
|
||||
uint32_t* dst = (uint32_t*)(img.data() + y*spec.bytes_per_row);
|
||||
unsigned int x, r, g, b, a = 0;
|
||||
|
||||
for (x=0; x<width; x++) {
|
||||
r = *(src++);
|
||||
g = *(src++);
|
||||
b = *(src++);
|
||||
if (spec.alpha_mask)
|
||||
a = *(src++);
|
||||
*(dst++) =
|
||||
(r << spec.red_shift) |
|
||||
(g << spec.green_shift) |
|
||||
(b << spec.blue_shift) |
|
||||
(a << spec.alpha_shift);
|
||||
}
|
||||
png_free(png, rows[y]);
|
||||
}
|
||||
png_free(png, rows);
|
||||
|
||||
std::swap(*output_image, img);
|
||||
}
|
||||
|
||||
png_destroy_read_struct(&png, &info, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace x11
|
||||
} // namespace clip
|
||||
99
src/vendor/clip/image.cpp
vendored
99
src/vendor/clip/image.cpp
vendored
|
|
@ -1,99 +0,0 @@
|
|||
// Clip Library
|
||||
// Copyright (c) 2015-2022 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "clip.h"
|
||||
|
||||
namespace clip {
|
||||
|
||||
unsigned long image_spec::required_data_size() const
|
||||
{
|
||||
unsigned long n = (bytes_per_row * height);
|
||||
|
||||
// For 24bpp we add some extra space to access the last pixel (3
|
||||
// bytes) as an uint32_t
|
||||
if (bits_per_pixel == 24) {
|
||||
if ((n % 4) > 0)
|
||||
n += 4 - (n % 4);
|
||||
else
|
||||
++n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
image::image()
|
||||
: m_own_data(false),
|
||||
m_data(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
image::image(const image_spec& spec)
|
||||
: m_own_data(true),
|
||||
m_data(new char[spec.required_data_size()]),
|
||||
m_spec(spec) {
|
||||
}
|
||||
|
||||
image::image(const void* data, const image_spec& spec)
|
||||
: m_own_data(false),
|
||||
m_data((char*)data),
|
||||
m_spec(spec) {
|
||||
}
|
||||
|
||||
image::image(const image& image)
|
||||
: m_own_data(false),
|
||||
m_data(nullptr),
|
||||
m_spec(image.m_spec) {
|
||||
copy_image(image);
|
||||
}
|
||||
|
||||
image::image(image&& image)
|
||||
: m_own_data(false),
|
||||
m_data(nullptr) {
|
||||
move_image(std::move(image));
|
||||
}
|
||||
|
||||
image::~image() {
|
||||
reset();
|
||||
}
|
||||
|
||||
image& image::operator=(const image& image) {
|
||||
copy_image(image);
|
||||
return *this;
|
||||
}
|
||||
|
||||
image& image::operator=(image&& image) {
|
||||
move_image(std::move(image));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void image::reset() {
|
||||
if (m_own_data) {
|
||||
delete[] m_data;
|
||||
m_own_data = false;
|
||||
m_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void image::copy_image(const image& image) {
|
||||
reset();
|
||||
|
||||
m_spec = image.spec();
|
||||
std::size_t n = m_spec.required_data_size();
|
||||
|
||||
m_own_data = true;
|
||||
m_data = new char[n];
|
||||
std::copy(image.data(),
|
||||
image.data()+n,
|
||||
m_data);
|
||||
}
|
||||
|
||||
void image::move_image(image&& image) {
|
||||
std::swap(m_own_data, image.m_own_data);
|
||||
std::swap(m_data, image.m_data);
|
||||
std::swap(m_spec, image.m_spec);
|
||||
}
|
||||
|
||||
} // namespace clip
|
||||
|
|
@ -1 +1 @@
|
|||
1716
|
||||
1718
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
# Note: This file is meant to be ran by CMake
|
||||
# and it should not be ran manually.
|
||||
#
|
||||
# It uses hardcoded paths, relative to
|
||||
# the root of the project (the OmniaX directory)
|
||||
# therefore it is only meant to run directly
|
||||
# from that directory and not form the
|
||||
# OmniaX/tools directory (in which it is located).
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import os.path
|
||||
import sys
|
||||
from os import path
|
||||
|
||||
verbose = False
|
||||
|
||||
def run_fast_scandir(dir, ext):
|
||||
subfolders, files = [], []
|
||||
|
||||
for f in os.scandir(dir):
|
||||
if f.is_dir():
|
||||
subfolders.append(f.path)
|
||||
if f.is_file():
|
||||
if os.path.splitext(f.name)[1].lower() in ext:
|
||||
files.append(f.path)
|
||||
|
||||
|
||||
for dir in list(subfolders):
|
||||
sf, f = run_fast_scandir(dir, ext)
|
||||
subfolders.extend(sf)
|
||||
files.extend(f)
|
||||
return subfolders, files
|
||||
|
||||
def install_includes(source_dir, include_dir, exception_dirs):
|
||||
_list = run_fast_scandir(source_dir, [".hpp", ".h", ".inl", ".cpp", ".c"])
|
||||
if path.exists(include_dir):
|
||||
if verbose:
|
||||
print("Removing old include directory...")
|
||||
shutil.rmtree(include_dir)
|
||||
os.mkdir(include_dir)
|
||||
|
||||
for elem in _list[0]:
|
||||
elem = elem[len(source_dir) + 1:]
|
||||
elem = os.path.join(include_dir, elem)
|
||||
#elem = include_dir + "/" + elem
|
||||
os.mkdir(elem)
|
||||
if verbose:
|
||||
print("Creating Directory: " + elem)
|
||||
|
||||
if verbose:
|
||||
print("\n")
|
||||
|
||||
for elem in _list[1]:
|
||||
#new_elem = include_dir + "/" + elem[len(source_dir):]
|
||||
new_elem = os.path.join(include_dir, elem[len(source_dir) + 1:])
|
||||
found = True
|
||||
if elem.endswith(".c") or elem.endswith(".cpp"):
|
||||
found = False
|
||||
for exep in exception_dirs:
|
||||
if new_elem.startswith(exep):
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
shutil.copy(elem, new_elem)
|
||||
if verbose:
|
||||
print("Creating File: " + new_elem)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "--verbose":
|
||||
verbose = True
|
||||
#src_dir = "./src/omniax/"
|
||||
#inc_dir = "./Build/include"
|
||||
#excep_dirs = [inc_dir + "/vendor/GLAD", inc_dir + "/vendor/glm"]
|
||||
src_dir = os.path.join(".", "src")
|
||||
inc_dir = os.path.join(".", "Build", "include")
|
||||
excep_dirs = [os.path.join(inc_dir, "vendor", "GLAD"), os.path.join(inc_dir, "vendor", "glm"), os.path.join(inc_dir, "vendor", "clip"), os.path.join(inc_dir, "vendor", "MiniAudio")]
|
||||
install_includes(src_dir, inc_dir, excep_dirs)
|
||||
|
||||
BIN
tools/inc_bnr
BIN
tools/inc_bnr
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue