/* * Image.h * ------- * Purpose: Bitmap and Vector image file handling. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "../common/FileReaderFwd.h" // GDI+ namespace Gdiplus { #include class Image; class Bitmap; class Metafile; } OPENMPT_NAMESPACE_BEGIN class bad_image : public std::runtime_error { public: bad_image() : std::runtime_error("") { } }; class RawGDIDIB { public: struct Pixel { // Component order must be compatible with Microsoft DIBs! uint8 b; uint8 g; uint8 r; uint8 a; constexpr Pixel() noexcept : b(0), g(0), r(0), a(0) {} constexpr Pixel(uint8 r, uint8 g, uint8 b, uint8 a) noexcept : b(b), g(g), r(r), a(a) {} constexpr Pixel(COLORREF color) noexcept : b(GetBValue(color)), g(GetGValue(color)), r(GetRValue(color)), a(0) {} }; private: uint32 width; uint32 height; std::vector pixels; public: RawGDIDIB(uint32 width, uint32 height); public: constexpr uint32 Width() const noexcept { return width; } constexpr uint32 Height() const noexcept { return height; } MPT_FORCEINLINE Pixel &operator()(uint32 x, uint32 y) noexcept { return pixels[y * width + x]; } MPT_FORCEINLINE const Pixel &operator()(uint32 x, uint32 y) const noexcept { return pixels[y * width + x]; } std::vector &Pixels() { return pixels; } const std::vector &Pixels() const { return pixels; } }; class GdiplusRAII { private: ULONG_PTR gdiplusToken = 0; public: GdiplusRAII(); ~GdiplusRAII(); }; namespace GDIP { std::unique_ptr LoadPixelImage(mpt::const_byte_span file); std::unique_ptr LoadPixelImage(FileReader file); std::unique_ptr LoadVectorImage(mpt::const_byte_span file); std::unique_ptr LoadVectorImage(FileReader file); std::unique_ptr ResizeImage(Gdiplus::Image &src, double scaling, int spriteWidth = 0, int spriteHeight = 0); std::unique_ptr ResizeImage(Gdiplus::Bitmap &src, double scaling, int spriteWidth = 0, int spriteHeight = 0); using Pixel = Gdiplus::ARGB; template inline Pixel * GetScanline(const TBitmapData &bitmapData, std::size_t y) noexcept { if(bitmapData.Stride >= 0) { return reinterpret_cast(mpt::void_cast(mpt::void_cast(bitmapData.Scan0) + y * bitmapData.Stride)); } else { return reinterpret_cast(mpt::void_cast(mpt::void_cast(bitmapData.Scan0) + (bitmapData.Height - 1 - y) * (-bitmapData.Stride))); } } constexpr Pixel AsPixel(uint8 r, uint8 g, uint8 b, uint8 a) noexcept { return Pixel(0) | (static_cast(r) << RED_SHIFT) | (static_cast(g) << GREEN_SHIFT) | (static_cast(b) << BLUE_SHIFT) | (static_cast(a) << ALPHA_SHIFT) ; } constexpr uint8 R(Pixel p) noexcept { return static_cast(p >> RED_SHIFT); } constexpr uint8 G(Pixel p) noexcept { return static_cast(p >> GREEN_SHIFT); } constexpr uint8 B(Pixel p) noexcept { return static_cast(p >> BLUE_SHIFT); } constexpr uint8 A(Pixel p) noexcept { return static_cast(p >> ALPHA_SHIFT); } constexpr RawGDIDIB::Pixel ToRawGDIDIB(Pixel p) noexcept { return RawGDIDIB::Pixel(GDIP::R(p), GDIP::G(p), GDIP::B(p), GDIP::A(p)); } } // namespace GDIP std::unique_ptr ToRawGDIDIB(Gdiplus::Bitmap &bitmap); bool CopyToCompatibleBitmap(CBitmap &dst, CDC &dc, const RawGDIDIB &src); bool CopyToCompatibleBitmap(CBitmap &dst, CDC &dc, Gdiplus::Image &src); std::unique_ptr LoadPixelImage(mpt::const_byte_span file, double scaling = 1.0, int spriteWidth = 0, int spriteHeight = 0); std::unique_ptr LoadPixelImage(FileReader file, double scaling = 1.0, int spriteWidth = 0, int spriteHeight = 0); bool LoadCompatibleBitmapFromPixelImage(CBitmap &dst, CDC &dc, mpt::const_byte_span file); bool LoadCompatibleBitmapFromPixelImage(CBitmap &dst, CDC &dc, FileReader file); OPENMPT_NAMESPACE_END