Files
soft/CristalDiskMark/source/CrystalDiskMark/Priscilla/ImageFx.h
T

420 lines
7.8 KiB
C++

#pragma once
#include <windows.h>
#include <tchar.h>
#include "stb_image.h"
#include "stb_image_write.h"
class CImage
{
public:
enum
{
createAlphaChannel = 0x01
};
CImage()
{
Init();
}
~CImage()
{
Destroy();
}
operator HBITMAP() const { return m_hBitmap; }
BOOL IsNull() const { return m_hBitmap == NULL; }
int GetWidth() const { return m_width; }
int GetHeight() const { return m_height; }
int GetPitch() const { return m_pitch; }
int GetBPP() const { return 32; }
void* GetBits() const { return m_bits; }
BOOL Create(int w, int h, int bpp, DWORD flags = 0)
{
Destroy();
if (bpp != 32) return FALSE;
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = -h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
void* bits = NULL;
m_hBitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
if (!m_hBitmap) return FALSE;
m_bits = (BYTE*)bits;
m_width = w;
m_height = h;
m_pitch = w * 4;
m_hasAlpha = (flags & createAlphaChannel) != 0;
memset(m_bits, 0, w * h * 4);
return TRUE;
}
void Destroy()
{
ReleaseDC();
if (m_hBitmap)
{
DeleteObject(m_hBitmap);
m_hBitmap = NULL;
}
Init();
}
BOOL Load(LPCTSTR fileName)
{
Destroy();
HANDLE hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
DWORD size = GetFileSize(hFile, NULL);
BYTE* buf = (BYTE*)malloc(size);
DWORD read = 0;
if (ReadFile(hFile, buf, size, &read, NULL) == FALSE || read != size)
{
free(buf);
CloseHandle(hFile);
return FALSE;
}
BOOL result = FALSE;
if (IsPNG(buf))
{
result = LoadPNG(buf, size);
}
else if (IsBMP(buf))
{
result = LoadBMP(buf, size);
}
free(buf);
return result;
}
static void png_write_func(void* context, void* data, int size)
{
HANDLE hFile = (HANDLE)context;
DWORD written = 0;
WriteFile(hFile, data, size, &written, NULL);
}
BOOL Save(LPCTSTR fileName)
{
if (!m_bits || !fileName)
return FALSE;
if (IsPNGFileName(fileName))
return SavePNG(fileName);
if (IsBMPFileName(fileName))
return SaveBMP(fileName);
return FALSE;
}
BOOL IsPNGFileName(LPCTSTR fileName)
{
LPCTSTR ext = _tcsrchr(fileName, _T('.'));
if (!ext) return FALSE;
return _tcsicmp(ext, _T(".png")) == 0;
}
BOOL IsBMPFileName(LPCTSTR fileName)
{
LPCTSTR ext = _tcsrchr(fileName, _T('.'));
if (!ext) return FALSE;
return _tcsicmp(ext, _T(".bmp")) == 0;
}
BOOL SavePNG(LPCTSTR fileName)
{
HANDLE hFile = CreateFile(
fileName,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
size_t size = (size_t)m_width * m_height * 4;
BYTE* tmp = (BYTE*)malloc(size);
if (!tmp) {
CloseHandle(hFile);
return FALSE;
}
for (int y = 0; y < m_height; y++)
{
BYTE* src = m_bits + y * m_pitch;
BYTE* dst = tmp + y * m_width * 4;
for (int x = 0; x < m_width; x++)
{
dst[x * 4 + 0] = src[x * 4 + 2];
dst[x * 4 + 1] = src[x * 4 + 1];
dst[x * 4 + 2] = src[x * 4 + 0];
dst[x * 4 + 3] = 255;
}
}
int result = stbi_write_png_to_func(
png_write_func,
(void*)hFile,
m_width,
m_height,
4,
tmp,
m_width * 4);
free(tmp);
CloseHandle(hFile);
return result != 0;
}
BOOL SaveBMP(LPCTSTR fileName)
{
HANDLE hFile = CreateFile(
fileName,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
int rowSize = ((m_width * 3 + 3) / 4) * 4;
int dataSize = rowSize * m_height;
BITMAPFILEHEADER bf = {};
bf.bfType = 0x4D42; // 'BM'
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bf.bfSize = bf.bfOffBits + dataSize;
BITMAPINFOHEADER bi = {};
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = m_width;
bi.biHeight = m_height; // bottom-up
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = BI_RGB;
DWORD written = 0;
WriteFile(hFile, &bf, sizeof(bf), &written, NULL);
WriteFile(hFile, &bi, sizeof(bi), &written, NULL);
BYTE* line = (BYTE*)malloc(rowSize);
if (!line)
{
CloseHandle(hFile);
return FALSE;
}
for (int y = m_height - 1; y >= 0; y--)
{
BYTE* src = m_bits + y * m_pitch;
BYTE* dst = line;
memset(line, 0, rowSize);
for (int x = 0; x < m_width; x++)
{
dst[0] = src[0]; // B
dst[1] = src[1]; // G
dst[2] = src[2]; // R
src += 4;
dst += 3;
}
if (!WriteFile(hFile, line, rowSize, &written, NULL) || written != (DWORD)rowSize)
{
free(line);
CloseHandle(hFile);
return FALSE;
}
}
free(line);
CloseHandle(hFile);
return TRUE;
}
BOOL BitBlt(HDC hDest, int x, int y, DWORD rop = SRCCOPY) const
{
return BitBlt(hDest, x, y, m_width, m_height, 0, 0, rop);
}
BOOL BitBlt(HDC hDest, int x, int y, int w, int h, int sx, int sy, DWORD rop) const
{
HDC hSrc = GetDC();
BOOL r = ::BitBlt(hDest, x, y, w, h, hSrc, sx, sy, rop);
ReleaseDC();
return r;
}
COLORREF GetPixel(int x, int y) const
{
BYTE* p = m_bits + y * m_pitch + x * 4;
return RGB(p[2], p[1], p[0]);
}
HDC GetDC() const
{
if (!m_hDC)
{
m_hDC = CreateCompatibleDC(NULL);
m_hOldBitmap = (HBITMAP)SelectObject(m_hDC, m_hBitmap);
}
return m_hDC;
}
void ReleaseDC() const
{
if (m_hDC)
{
SelectObject(m_hDC, m_hOldBitmap);
DeleteDC(m_hDC);
m_hDC = NULL;
m_hOldBitmap = NULL;
}
}
void Attach(HBITMAP hBitmap)
{
Destroy();
m_hBitmap = hBitmap;
BITMAP bm;
GetObject(hBitmap, sizeof(bm), &bm);
m_width = bm.bmWidth;
m_height = bm.bmHeight;
m_pitch = bm.bmWidthBytes;
m_bits = (BYTE*)bm.bmBits;
m_hasAlpha = (bm.bmBitsPixel == 32);
}
HBITMAP Detach()
{
HBITMAP h = m_hBitmap;
Init();
return h;
}
private:
void Init()
{
m_hBitmap = NULL;
m_bits = NULL;
m_width = m_height = m_pitch = 0;
m_hDC = NULL;
m_hOldBitmap = NULL;
m_hasAlpha = false;
}
BOOL IsPNG(BYTE* p)
{
static BYTE sig[8] = { 137,80,78,71,13,10,26,10 };
return memcmp(p, sig, 8) == 0;
}
BOOL IsBMP(BYTE* p)
{
return p[0] == 'B' && p[1] == 'M';
}
BOOL LoadPNG(BYTE* data, int size)
{
int w, h, c;
unsigned char* img = stbi_load_from_memory(data, size, &w, &h, &c, 4);
if (!img) return FALSE;
Create(w, h, 32, createAlphaChannel);
for (int i = 0; i < w * h; i++)
{
BYTE r = img[i * 4 + 0];
BYTE g = img[i * 4 + 1];
BYTE b = img[i * 4 + 2];
BYTE a = img[i * 4 + 3];
m_bits[i * 4 + 0] = b;
m_bits[i * 4 + 1] = g;
m_bits[i * 4 + 2] = r;
m_bits[i * 4 + 3] = a;
}
stbi_image_free(img);
return TRUE;
}
BOOL LoadBMP(BYTE* data, int)
{
BITMAPFILEHEADER* bf = (BITMAPFILEHEADER*)data;
BITMAPINFOHEADER* bi = (BITMAPINFOHEADER*)(data + sizeof(BITMAPFILEHEADER));
BYTE* src = data + bf->bfOffBits;
Create(bi->biWidth, abs(bi->biHeight), 32);
for (int y = 0; y < m_height; y++)
{
BYTE* d = m_bits + y * m_pitch;
BYTE* s = src + (m_height - 1 - y) * ((m_width * 3 + 3) & ~3);
for (int x = 0; x < m_width; x++)
{
d[0] = s[0];
d[1] = s[1];
d[2] = s[2];
d[3] = 255;
d += 4; s += 3;
}
}
return TRUE;
}
private:
HBITMAP m_hBitmap;
BYTE* m_bits;
int m_width, m_height, m_pitch;
mutable HDC m_hDC;
mutable HBITMAP m_hOldBitmap;
bool m_hasAlpha;
};