用 EasyX 画一个海报(使用 Direct2D 进行抗锯齿绘图)
2023-12-2
(0)
前言
今天是我写代码的第六周年,想干什么来纪念一下,想到初学的时候用的就是 EasyX 这个库入门,便打算用 EasyX 给自己画一个六周年纪念海报,六年时间一眨眼就过去了,真让人感叹光影似箭~ 正好赶上今天比较空,抽了点时间做了这个海报,做的比较随意,但也当作是一个六年以来的纪念吧。
想起六年前第一次写代码的时候,还是用的一个在线代码运行器跑起了一个 Hello World,自此开始了我的计算机不归路,想起六年前的那个夜晚,和曾经的自己不禁让人感到"物是人非事事休,欲语泪先流”。
运行代码后,会创建一个高八百宽一千的窗口并展示海报。
运行截图
代码
/**
* 作 者:Margoo
* 邮 箱:1683691371@qq.com
* 编写环境:CLion NOVA(Preview) + MSVC17.7.0 + EasyX_20220901
* 编写日期:2023/12/2
*/
/**
* 强制使用 UNICODE 字符集
*/
#define UNICODE
#define _UNICODE
#include <graphics.h>
#include <conio.h>
#include <d2d1.h>
#include <cmath>
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "MSIMG32.LIB")
constexpr auto Width = 800;
constexpr auto Height = 1000;
constexpr auto HalfWidth = Width / 2;
constexpr auto HalfHeight = Height / 2;
/**
* \brief D2D 相关变量
*/
ID2D1Factory* Facotry;
ID2D1SolidColorBrush* WhiteBrush;
ID2D1DCRenderTarget* RenderTarget;
/**
* \brief 生成一个旋转点
*/
inline D2D_POINT_2F RotatePoint(const int& X, const int& Y, const float& Degree)
{
if (Degree != 0)
{
const auto& DX = static_cast<float>(X - HalfWidth);
const auto& DY = static_cast<float>(Y - HalfHeight);
const auto RotatedX = DX * std::cos(Degree) - DY * std::sin(Degree);
const auto RotatedY = DX * std::sin(Degree) + DY * std::cos(Degree);
return D2D_POINT_2F{
.x = static_cast<float>(HalfWidth + RotatedX), .y = static_cast<float>(HalfHeight + RotatedY)
};
}
else
{
return D2D_POINT_2F{.x = static_cast<float>(X), .y = static_cast<float>(Y)};
}
}
/**
* \brief 画一个被旋转过的正方形
*/
void DrawRectangle(const int& Radius, const float& Degree)
{
const D2D_POINT_2F Points[] = {
RotatePoint(HalfWidth - Radius, HalfHeight + Radius, Degree),
RotatePoint(HalfWidth + Radius, HalfHeight + Radius, Degree),
RotatePoint(HalfWidth + Radius, HalfHeight - Radius, Degree),
RotatePoint(HalfWidth - Radius, HalfHeight - Radius, Degree),
RotatePoint(HalfWidth - Radius, HalfHeight + Radius, Degree)
};
for (int Count = 0; Count < 4; ++Count)
{
RenderTarget->DrawLine(Points[Count], Points[Count + 1], WhiteBrush, 1.5f);
}
}
/**
* \brief 初始化画布
*/
void InitLayout()
{
initgraph(Width, Height);
}
/**
* \brief 画一层旋转正方形
*/
void DrawLayout(float Degree, const int& MinSize)
{
for (int Count = Width + 100; Count >= MinSize; Count -= 4)
{
DrawRectangle(Count, Degree);
Degree += 0.015;
}
}
/**
* \brief 初始化 D2D 环境
*/
void InitD2D()
{
const HRESULT ResultHandle = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&Facotry
);
const auto Property = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE::D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE
), 0.0, 0.0, D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, D2D1_FEATURE_LEVEL_DEFAULT
);
HRESULT Result = Facotry->CreateDCRenderTarget(
&Property,
&RenderTarget
);
if (FAILED(Result) || FAILED(ResultHandle))
{
printf("D2D Facotry Created Failed\n");
MessageBox(GetHWnd(), L"Failed to create D2D factory, program will exit!", L"ERROR", MB_OK + 16);
exit(-1);
}
Result = RenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White),
&WhiteBrush
);
if (FAILED(Result))
{
printf("D2D Brush Failed to Create\n");
MessageBox(GetHWnd(), L"D2D Brush Failed to Create, program will exit!", L"ERROR", MB_OK + 16);
exit(-1);
}
RenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE::D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
constexpr RECT Rect = {0, 0, Width, Height};
Result = RenderTarget->BindDC(GetImageHDC(GetWorkingImage()), &Rect);
if (FAILED(Result))
{
printf("D2D Brush Failed to Bind EasyX DC\n");
MessageBox(GetHWnd(), L"D2D Brush Failed to Bind EasyX DC, program will exit!", L"ERROR", MB_OK + 16);
exit(-1);
}
}
/**
* \brief 生成矩形旋转图片
*/
IMAGE* RectangleImage()
{
auto* RectangleImage = new IMAGE(Width, Height);
SetWorkingImage(RectangleImage);
InitD2D();
RenderTarget->BeginDraw();
RenderTarget->Clear(D2D_COLOR_F(D3DCOLORVALUE{.r = 0.2, .g = 0.2, .b = 0.1, .a = 1}));
DrawLayout(0.32, 60);
DrawLayout(4.2, 60);
RenderTarget->EndDraw();
SetWorkingImage();
return RectangleImage;
}
/**
* \brief 生成渐变图片(线性插值)
*/
IMAGE* BackPicture()
{
auto* RectangleImage = new IMAGE(Width, Height);
SetWorkingImage(RectangleImage);
const auto Buffer = GetImageBuffer(RectangleImage);
constexpr double RDiff = 151 - 67;
constexpr double GDiff = 8 - 203;
constexpr double BDiff = 204 - 255;
for (int Y = 0; Y < Height; ++Y)
{
const double Percent = static_cast<float>(Y) / Height;
const COLORREF LineColor = BGR(RGB(67 + RDiff * Percent, 203 + GDiff * Percent, 255 + BDiff * Percent));
for (int X = 0; X < Width; ++X)
{
Buffer[Y * Width + X] = LineColor;
}
}
SetWorkingImage();
return RectangleImage;
}
/**
* \brief 正片叠底操作
*/
void LayerOverlay(IMAGE* Source, IMAGE* Target)
{
const DWORD* SourceBuffer = GetImageBuffer(Source);
DWORD* TargetBuffer = GetImageBuffer(Target);
for (int Count = 0; Count < Width * Height; ++Count)
{
DWORD R = ((TargetBuffer[Count] & 0xff0000) >> 16);
DWORD G = ((TargetBuffer[Count] & 0xff00) >> 8);
DWORD B = (TargetBuffer[Count] & 0xff);
const DWORD SR = ((SourceBuffer[Count] & 0xff0000) >> 16);
const DWORD SG = ((SourceBuffer[Count] & 0xff00) >> 8);
const DWORD SB = (SourceBuffer[Count] & 0xff);
R = (R * SR) / 255;
G = (G * SG) / 255;
B = (B * SB) / 255;
if (RGB(R, G, B) != BLACK)
{
TargetBuffer[Count] = BGR(RGB(R, G, B));
}
}
}
/**
* \brief 输出文字
*/
void PrintText()
{
setbkmode(TRANSPARENT);
LOGFONT Font;
gettextstyle(&Font);
_tcscpy_s(Font.lfFaceName, L"Microsoft YaHei");
Font.lfQuality = PROOF_QUALITY;
Font.lfHeight = 30;
settextcolor(RGB(240, 240, 240));
settextstyle(&Font);
outtextxy(44, 834, L"FROM 2017 TO 2023");
Font.lfHeight = 90;
Font.lfWeight = FW_BLACK;
settextstyle(&Font);
outtextxy(44, 754, L"6TH CODING YEAR!");
Font.lfHeight = 29;
Font.lfWeight = FW_LIGHT;
settextstyle(&Font);
outtextxy(HalfWidth - textwidth(L"- Keep Moving -") / 2, 924, L"- Keep Moving -");
}
/**
* \brief 画出海报整体
*/
void PrintPoster()
{
const auto Rectangle = RectangleImage();
const auto BackgroundImage = BackPicture();
LayerOverlay(BackgroundImage, Rectangle);
putimage(0, 0, Rectangle);
PrintText();
}
int main()
{
// 欲买桂花同载酒,终不似,少年游
InitLayout();
PrintPoster();
_getch();
return 0;
}
添加评论
取消回复