Im trying to convert the code found here: soft-edged-images-in-gdi, to c . Its used to create bitmaps with rounded corners and soft edges.
#include <windows.h>
#include <iostream>
#include <exception>
#include <gdiplus.h>
#include <gdipluspath.h>
#include <gdiplusimaging.h>
#include <gdipluspixelformats.h >
#include <wingdi.h>
#pragma comment (lib, "gdiplus.lib")
using namespace Gdiplus;
GraphicsPath* createRoundRect(int x, int y, int width, int height, int radius)
{
GraphicsPath* gp = new GraphicsPath;
if (radius == 0)
gp->AddRectangle(Rect(x, y, width, height));
else
{
gp->AddLine(x radius, y, x width - radius, y);
gp->AddArc(x width - radius, y, radius, radius, 270, 90);
gp->AddLine(x width, y radius, x width, y height - radius);
gp->AddArc(x width - radius, y height - radius, radius, radius, 0, 90);
gp->AddLine(x width - radius, y height, x radius, y height);
gp->AddArc(x, y height - radius, radius, radius, 90, 90);
gp->AddLine(x, y height - radius, x, y radius);
gp->AddArc(x, y, radius, radius, 180, 90);
gp->CloseFigure();
}
return gp;
}
Brush* createFluffyBrush(GraphicsPath* gp, float* blendPositions, float* blendFactors, INT count, INT* in_out_count)
{
PathGradientBrush* pgb = new PathGradientBrush(gp);
//Blend blend = new Blend();
//blend.Positions = blendPositions;
//blend.Factors = blendFactors;
//pgb->Blend = blend;
/* count:
Type: INT
Integer that specifies the number of elements in the blendFactors array.
This is the same as the number of elements in the blendPositions array.
*/
pgb->SetBlend(blendFactors, blendPositions, count);
pgb->SetCenterColor(Color::White);
// in_out_count:
/*
Type: INT*
Pointer to an integer that, on input, specifies the number of Color objects in the colors array.
If the method succeeds, this parameter, on output, receives the number of surround colors set.
If the method fails, this parameter does not receive a value.
*/
pgb->SetSurroundColors(new Color(Color::Black), in_out_count);
return pgb;
}
enum ChannelARGB
{
Blue = 0,
Green = 1,
Red = 2,
Alpha = 3
};
void transferOneARGBChannelFromOneBitmapToAnother(Bitmap* source, Bitmap* dest, ChannelARGB sourceChannel, ChannelARGB destChannel)
{
if ((source->GetWidth() != dest->GetWidth())
|| (source->GetHeight() != dest->GetHeight())
)
{
//throw ArgumentException();
};
Rect* r = new Rect(0, 0, source->GetWidth(), source->GetHeight());
BitmapData* bdSrc = new BitmapData;
source->LockBits(r, ImageLockMode::ImageLockModeRead, PixelFormat32bppARGB, bdSrc); //PixelFormat(Format32bppArgb)
BitmapData* bdDst = new BitmapData;
dest->LockBits(r, ImageLockMode::ImageLockModeRead, PixelFormat32bppARGB, bdDst);
try
{
byte* bpSrc = (byte*)bdSrc->Scan0;//ToPointer()
byte* bpDst = (byte*)bdDst->Scan0;
bpSrc = (int)sourceChannel;
bpDst = (int)destChannel;
for (int i = r->Height * r->Width; i > 0; i--)
{
*bpDst = *bpSrc;
bpSrc = 4;
bpDst = 4;
}
}
catch (const std::exception&)
{
}
source->UnlockBits(bdSrc);
dest->UnlockBits(bdDst);
}
//////////////////////////////////////
//////////////////////////////////////
//Bitmap* bmpFluffy = new Bitmap(bmpOriginal);
Gdiplus::Bitmap* bmpFluffy = Gdiplus::Bitmap::FromFile(L"picture.png", false);
Rect r(0, 0, bmpFluffy->GetWidth(), bmpFluffy->GetHeight());
Bitmap* bmpMask = new Bitmap(r.Width, r.Height);
Graphics* g = Graphics::FromImage(bmpMask);
GraphicsPath* path = createRoundRect(
r.X, r.Y,
r.Width, r.Height,
min(r.Width, r.Height) / 5);;
int in_out_count = 1;
Brush brush = createFluffyBrush(
path,
new float[] { 0.0f, 0.1f, 1.0f },
new float[] { 0.0f, 0.95f, 1.0f }, 3, &in_out_count);
{
g->FillRectangle(new SolidBrush(Color::Black), r); //Brush to solidbrush
g->SetSmoothingMode(SmoothingMode::SmoothingModeHighQuality);
g->FillPath(&brush, path);
transferOneARGBChannelFromOneBitmapToAnother(
bmpMask,
bmpFluffy,
ChannelARGB::Blue,
ChannelARGB::Alpha);
}
I have no experience with .net
, and im not sure if the code has been converted correctly, i wonder if someone could take a look at it.
Current im getting error only at this line: Brush brush = createFluffyBrush(
no suitable constructor exist to convert from "Gdiplus::Brush *" to "Gdiplus::Brush"
CodePudding user response:
createFluffyBrush return a pointer to Brush,
so you should use :
Brush brush = *createFluffyBrush(...)
or (better here ?)
Brush * brush = createFluffyBrush(...)
CodePudding user response:
Avoid using the new
operator in modern C . Gdiplus is kind of old, so you can keep using pointers and new
in some places, for example to declare Gdiplus::Bitmap*
object. For structures such as Gdiplus::GraphicsPath
you can use pass by reference, that's usually the easiest and safest method.
To draw rounded images, get the rounded path, clip the region, then use anti-aliasing to draw a rounded rectangle over that image. Example:
#include <windows.h>
#include <gdiplus.h>
#pragma comment (lib,"Gdiplus.lib")
void GetRoundRectPath(Gdiplus::GraphicsPath& path, Gdiplus::Rect rc, int diameter)
{
if (diameter > rc.Width) diameter = rc.Width;
if (diameter > rc.Height) diameter = rc.Height;
int dx = rc.Width - diameter;
int dy = rc.Height - diameter;
Gdiplus::Rect tl(rc.X, rc.Y, diameter, diameter); //top-left
Gdiplus::Rect tr = tl; tr.Offset(dx, 0); //top-right
Gdiplus::Rect br = tl; br.Offset(dx, dy); //bottom-right
Gdiplus::Rect bl = tl; bl.Offset(0, dy); //bottom-left
path.Reset();
path.AddArc(br, 0, 90);
path.AddArc(bl, 90, 90);
path.AddArc(tl, 180, 90);
path.AddArc(tr, 270, 90);
path.CloseFigure();
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static Gdiplus::Image* img = nullptr;
switch (message)
{
case WM_CREATE:
img = Gdiplus::Bitmap::FromFile(L"test.jpg");
if (img->GetLastStatus() != 0)
MessageBox(0, L"no image", 0, 0);
return 0;
case WM_PAINT:
{
if (!img)
break;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics g(hdc);
Gdiplus::GraphicsPath path;
Gdiplus::Rect rc{ 10, 10, (int)img->GetWidth(), (int)img->GetHeight() };
GetRoundRectPath(path, rc, 32);
Gdiplus::Region rgn(&path);
g.SetClip(&rgn);
g.DrawImage(img, rc);
rgn.MakeInfinite();
g.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
Gdiplus::Pen pen(Gdiplus::Color::White, 2.0F);
g.DrawPath(&pen, &path);
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
if(img) delete img;
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, PSTR, INT)
{
ULONG_PTR token;
Gdiplus::GdiplusStartupInput tmp;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
WNDCLASS wndClass {0};
wndClass.lpfnWndProc = WndProc;
wndClass.hInstance = hinst;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszClassName = L"test";
RegisterClass(&wndClass);
CreateWindow(wndClass.lpszClassName, L"Test", WS_VISIBLE|WS_OVERLAPPEDWINDOW,
100, 100, 800, 600, NULL, NULL, hinst, nullptr);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Gdiplus::GdiplusShutdown(token);
return 0;
}