Filled in image.cpp. Also switched on WIC since we'll need it for uiArea, though uiTable will still need classic GDI. Now let's integrate this into uiTable.

This commit is contained in:
Pietro Gagliardi 2018-06-09 19:24:36 -04:00
parent 3aee505f4e
commit a858300f25
6 changed files with 148 additions and 6 deletions

View File

@ -78,7 +78,7 @@ set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE)
# TODO prune this list # TODO prune this list
set(_LIBUI_LIBS set(_LIBUI_LIBS
user32 kernel32 gdi32 comctl32 uxtheme msimg32 comdlg32 d2d1 dwrite ole32 oleaut32 oleacc uuid user32 kernel32 gdi32 comctl32 uxtheme msimg32 comdlg32 d2d1 dwrite ole32 oleaut32 oleacc uuid windowscodecs
PARENT_SCOPE) PARENT_SCOPE)
if(NOT MSVC) if(NOT MSVC)

View File

@ -1,12 +1,23 @@
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
// stubbed out windows image list implementation.
// Required for uiTable control, but windows implemenation IWICImagingFactory *uiprivWICFactory = NULL;
// doesn't currently have image support.
HRESULT uiprivInitImage(void)
{
return CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory, (void **) (&uiprivWICFactory));
}
void uiprivUninitImage(void)
{
uiprivWICFactory->Release();
uiprivWICFactory = NULL;
}
struct uiImage { struct uiImage {
double width; double width;
double height; double height;
// HIMAGELIST images; std::vector<IWICBitmap *> *bitmaps;
}; };
uiImage *uiNewImage(double width, double height) uiImage *uiNewImage(double width, double height)
@ -16,16 +27,132 @@ uiImage *uiNewImage(double width, double height)
i = uiprivNew(uiImage); i = uiprivNew(uiImage);
i->width = width; i->width = width;
i->height = height; i->height = height;
i->bitmaps = new std::vector<IWICBitmap *>;
return i; return i;
} }
void uiFreeImage(uiImage *i) void uiFreeImage(uiImage *i)
{ {
for (IWICBitmap *b : *(i->bitmaps))
b->Release();
delete i->bitmaps;
uiprivFree(i); uiprivFree(i);
} }
void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int pixelStride) void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int pixelStride)
{ {
// not implemented IWICBitmap *b;
HRESULT hr;
hr = uiprivWICFactory->CreateBitmapFromMemory(pixelWidth, pixelHeight,
GUID_WICPixelFormat32bppRGBA, pixelStride,
pixelStride * pixelHeight, (BYTE *) pixels,
&b);
if (hr != S_OK)
logHRESULT(L"error calling CreateBitmapFromMemory() in uiImageAppend()", hr);
i->bitmaps->push_back(b);
} }
struct matcher {
IWICBitmap *best;
int distX;
int distY;
int targetX;
int targetY;
bool foundLarger;
};
// TODO is this the right algorithm?
static void match(IWICBitmap *b, struct matcher *m)
{
UINT ux, uy;
int x, y;
int x2, y2;
HRESULT hr;
hr = b->GetSize(&ux, &uy);
if (hr != S_OK)
logHRESULT(L"error calling GetSize() in match()", hr);
x = ux;
y = uy;
if (m->best == NULL)
goto writeMatch;
if (x < m->targetX && y < m->targetY)
if (m->foundLarger)
// always prefer larger ones
return;
if (x >= m->targetX && y >= m->targetY && !m->foundLarger)
// we set foundLarger below
goto writeMatch;
// TODO
#define abs(x) ((x) < 0 ? -(x) : (x))
x2 = abs(m->targetX - x);
y2 = abs(m->targetY - y);
if (x2 < m->distX && y2 < m->distY)
goto writeMatch;
// TODO weight one dimension? threshhold?
return;
writeMatch:
// must set this here too; otherwise the first image will never have ths set
if (x >= m->targetX && y >= m->targetY && !m->foundLarger)
m->foundLarger = true;
m->best = b;
m->distX = abs(m->targetX - x);
m->distY = abs(m->targetY - y);
}
IWICBitmap *uiprivImageAppropriateForDC(uiImage *i, HDC dc)
{
struct matcher m;
m.best = NULL;
m.distX = INT_MAX;
m.distY = INT_MAX;
m.targetX = i->width * GetDeviceCaps(dc, LOGPIXELSX);
m.targetY = i->height * GetDeviceCaps(dc, LOGPIXELSY);
m.foundLarger = false;
for (IWICBitmap *b : *(i->bitmaps))
match(b, &m);
return m.best;
}
// TODO see if we can really pass NULL to CreateDIBSection()'s HDC parameter, and if so, use HBITMAPs before WIC maybe?
HBITMAP uiprivWICToGDI(IWICBitmap *b, HDC dc)
{
BITMAPINFO bmi;
UINT width, height;
HBITMAP hb;
VOID *bits;
BITMAP bmp;
HRESULT hr;
ZeroMemory(&bmi, sizeof (BITMAPINFO));
bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
hr = b->GetSize(&width, &height);
if (hr != S_OK)
logHRESULT(L"error calling GetSize() in uiprivWICToGDI()", hr);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -((int) height);
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
hb = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS,
&bits, NULL, 0);
if (hb == NULL)
logLastError(L"error calling CreateDIBSection() in uiprivWICToGDI()");
// now we need to figure out the stride of the image data GDI gave us
// TODO find out if CreateDIBSection fills that in bmi for us
if (GetObject(hb, sizeof (BITMAP), &bmp) == 0)
logLastError(L"error calling GetObject() in uiprivWICToGDI()");
hr = b->CopyPixels(NULL, bmp.bmWidthBytes,
bmp.bmWidthBytes * bmp.bmHeight, (BYTE *) bits);
if (hr != S_OK)
logHRESULT(L"error calling CopyPixels() in uiprivWICToGDI()", hr);
return hb;
}

View File

@ -131,11 +131,16 @@ const char *uiInit(uiInitOptions *o)
if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0) if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0)
return ieLastErr("initializing D2D scratch window class"); return ieLastErr("initializing D2D scratch window class");
hr = uiprivInitImage();
if (hr != S_OK)
return ieHRESULT("initializing WIC", hr);
return NULL; return NULL;
} }
void uiUninit(void) void uiUninit(void)
{ {
uiprivUninitImage();
uninitMenus(); uninitMenus();
unregisterD2DScratchClass(); unregisterD2DScratchClass();
unregisterMessageFilter(); unregisterMessageFilter();

View File

@ -416,6 +416,8 @@ uiTable *uiNewTable(uiTableModel *model)
t->backgroundColumn = -1; t->backgroundColumn = -1;
// TODO update these when the DPI changes // TODO update these when the DPI changes
// TODO handle errors
// TODO try adding a real transparent image
t->dummyLarge = ImageList_Create( t->dummyLarge = ImageList_Create(
GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
ILC_COLOR32, ILC_COLOR32,

View File

@ -163,3 +163,10 @@ extern D2D1_SIZE_F realGetSize(ID2D1RenderTarget *rt);
// draw.cpp // draw.cpp
extern ID2D1DCRenderTarget *makeHDCRenderTarget(HDC dc, RECT *r); extern ID2D1DCRenderTarget *makeHDCRenderTarget(HDC dc, RECT *r);
// image.cpp
extern IWICImagingFactory *uiprivWICFactory;
extern HRESULT uiprivInitImage(void);
extern void uiprivUninitImage(void);
extern IWICBitmap *uiprivImageAppropriateForDC(uiImage *i, HDC dc);
extern HBITMAP uiprivWICToGDI(IWICBitmap *b, HDC dc);

View File

@ -42,6 +42,7 @@
#include <d2d1.h> #include <d2d1.h>
#include <d2d1helper.h> #include <d2d1helper.h>
#include <dwrite.h> #include <dwrite.h>
#include <wincodec.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>