duckstation/src/util/image.h
2024-11-24 23:29:29 +10:00

112 lines
3.7 KiB
C++

// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include "common/align.h"
#include "common/heap_array.h"
#include "common/types.h"
#include <cstdio>
#include <optional>
#include <span>
#include <string_view>
class Error;
enum class ImageFormat : u8
{
None,
RGBA8,
BGRA8,
RGB565,
RGBA5551,
BGR8,
BC1,
BC2,
BC3,
BC7,
MaxCount,
};
class Image
{
public:
static constexpr u8 DEFAULT_SAVE_QUALITY = 85;
public:
using PixelStorage = Common::unique_aligned_ptr<u8[]>;
Image();
Image(u32 width, u32 height, ImageFormat format);
Image(u32 width, u32 height, ImageFormat format, const void* pixels, u32 pitch);
Image(u32 width, u32 height, ImageFormat format, PixelStorage pixels, u32 pitch);
Image(const Image& copy);
Image(Image&& move);
Image& operator=(const Image& copy);
Image& operator=(Image&& move);
static const char* GetFormatName(ImageFormat format);
static u32 GetPixelSize(ImageFormat format);
static bool IsCompressedFormat(ImageFormat format);
static u32 CalculatePitch(u32 width, u32 height, ImageFormat format);
static u32 CalculateStorageSize(u32 width, u32 height, ImageFormat format);
static u32 CalculateStorageSize(u32 width, u32 height, u32 pitch, ImageFormat format);
ALWAYS_INLINE bool IsValid() const { return (m_width > 0 && m_height > 0); }
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
ALWAYS_INLINE u32 GetPitch() const { return m_pitch; }
ALWAYS_INLINE ImageFormat GetFormat() const { return m_format; }
ALWAYS_INLINE const u8* GetPixels() const { return m_pixels.get(); }
ALWAYS_INLINE u8* GetPixels() { return m_pixels.get(); }
ALWAYS_INLINE const u8* GetRowPixels(u32 y) const { return &m_pixels[y * m_pitch]; }
ALWAYS_INLINE u8* GetRowPixels(u32 y) { return &m_pixels[y * m_pitch]; }
// ALWAYS_INLINE void SetPixel(u32 x, u32 y, PixelType pixel) { m_pixels[y * m_width + x] = pixel; }
// ALWAYS_INLINE PixelType GetPixel(u32 x, u32 y) const { return m_pixels[y * m_width + x]; }
u32 GetBlockXCount() const;
u32 GetBlockYCount() const;
u32 GetStorageSize() const;
std::span<const u8> GetPixelsSpan() const;
std::span<u8> GetPixelsSpan();
void Clear();
void Invalidate();
void Resize(u32 new_width, u32 new_height, bool preserve);
void Resize(u32 new_width, u32 new_height, ImageFormat format, bool preserve);
void SetPixels(u32 width, u32 height, ImageFormat format, const void* pixels, u32 pitch);
void SetPixels(u32 width, u32 height, ImageFormat format, PixelStorage pixels, u32 pitch);
bool SetAllPixelsOpaque();
PixelStorage TakePixels();
bool LoadFromFile(const char* filename, Error* error = nullptr);
bool LoadFromFile(std::string_view filename, std::FILE* fp, Error* error = nullptr);
bool LoadFromBuffer(std::string_view filename, std::span<const u8> data, Error* error = nullptr);
bool RasterizeSVG(const std::span<const u8> data, u32 width, u32 height, Error* error = nullptr);
bool SaveToFile(const char* filename, u8 quality = DEFAULT_SAVE_QUALITY, Error* error = nullptr) const;
bool SaveToFile(std::string_view filename, std::FILE* fp, u8 quality = DEFAULT_SAVE_QUALITY,
Error* error = nullptr) const;
std::optional<DynamicHeapArray<u8>> SaveToBuffer(std::string_view filename, u8 quality = DEFAULT_SAVE_QUALITY,
Error* error = nullptr) const;
std::optional<Image> ConvertToRGBA8(Error* error) const;
void FlipY();
protected:
u32 m_width = 0;
u32 m_height = 0;
u32 m_pitch = 0;
ImageFormat m_format = ImageFormat::None;
PixelStorage m_pixels;
};