Canvas_ity:一个小型、单头文件的 <canvas> 类 2D rasterizer,适用于 C++
发布: (2026年2月22日 GMT+8 02:50)
4 分钟阅读
原文: Hacker News
Source: Hacker News
Cleaned Example (C++)
#include
#include
// 包含库头文件和实现。
#define CANVAS_ITY_IMPLEMENTATION
#include "canvas_ity.hpp"
int main()
{
// --------------------------------------------------------------------
// 构建画布。
// --------------------------------------------------------------------
static const int width = 256;
static const int height = 256;
canvas_ity::canvas context( width, height );
// --------------------------------------------------------------------
// 构建星形路径。
// --------------------------------------------------------------------
context.move_to( 128.0f, 28.0f ); context.line_to( 157.0f, 87.0f );
context.line_to( 223.0f, 97.0f ); context.line_to( 175.0f, 143.0f );
context.line_to( 186.0f, 208.0f ); context.line_to( 128.0f, 178.0f );
context.line_to( 69.0f, 208.0f ); context.line_to( 80.0f, 143.0f );
context.line_to( 32.0f, 97.0f ); context.line_to( 98.0f, 87.0f );
context.close_path();
// --------------------------------------------------------------------
// 设置投影。
// --------------------------------------------------------------------
context.set_shadow_blur( 8.0f );
context.shadow_offset_y = 4.0f;
context.set_shadow_color( 0.0f, 0.0f, 0.0f, 0.5f );
// --------------------------------------------------------------------
// 用黄色填充星形。
// --------------------------------------------------------------------
context.set_color( canvas_ity::fill_style, 1.0f, 0.9f, 0.2f, 1.0f );
context.fill();
// --------------------------------------------------------------------
// 用粗红色描边并圆角绘制星形。
// --------------------------------------------------------------------
context.line_join = canvas_ity::rounded;
context.set_line_width( 12.0f );
context.set_color( canvas_ity::stroke_style, 0.9f, 0.0f, 0.5f, 1.0f );
context.stroke();
// --------------------------------------------------------------------
// 再次绘制星形,使用虚线细橙色描边。
// --------------------------------------------------------------------
float segments[] = { 21.0f, 9.0f, 1.0f, 9.0f, 7.0f, 9.0f, 1.0f, 9.0f };
context.set_line_dash( segments, 8 );
context.line_dash_offset = 10.0f;
context.line_cap = canvas_ity::circle;
context.set_line_width( 6.0f );
context.set_color( canvas_ity::stroke_style, 0.95f, 0.65f, 0.15f, 1.0f );
context.stroke();
// --------------------------------------------------------------------
// 关闭投影。
// --------------------------------------------------------------------
context.set_shadow_color( 0.0f, 0.0f, 0.0f, 0.0f );
// --------------------------------------------------------------------
// 在星形上添加光泽层。
// --------------------------------------------------------------------
context.set_linear_gradient( canvas_ity::fill_style, 64.0f, 0.0f, 192.0f, 256.0f );
context.add_color_stop( canvas_ity::fill_style, 0.30f, 1.0f, 1.0f, 1.0f, 0.0f );
context.add_color_stop( canvas_ity::fill_style, 0.35f, 1.0f, 1.0f, 1.0f, 0.8f );
context.add_color_stop( canvas_iy::fill_style, 0.45f, 1.0f, 1.0f, 1.0f, 0.8f );
context.add_color_stop( canvas_ity::fill_style, 0.50f, 1.0f, 1.0f, 1.0f, 0.0f );
context.global_composite_operation = canvas_ity::source_atop;
context.fill_rectangle( 0.0f, 0.0f, 256.0f, 256.0f );
// --------------------------------------------------------------------
// 从整个画布获取渲染后的 RGBA 像素。
// --------------------------------------------------------------------
unsigned char *image = new unsigned char[ height * width * 4 ];
context.get_image_data( image, width, height, width * 4, 0, 0 );
// -----------------------------------------------------
// Convert to BGRA for TGA and write the file.
// --------------------------------------------------------------------
for ( int i = 0; i ( width & 0xFF ),
static_cast( width >> 8 ),
static_cast( height & 0xFF ),
static_cast( height >> 8 ),
32, 40
};
std::ofstream stream( "example.tga", std::ios::binary );
stream.write( reinterpret_cast( header ), sizeof( header ) );
stream.write( reinterpret_cast( image ), height * width * 4 );
delete[] image;
}
上述代码可以编译,并使用 canvas_ity 库生成一张 example.tga 的风格化星形图像。
JavaScript 代码片段(独立)
// Get the 2‑D drawing context.
const context = document.getElementById("example").getContext("2d");
// Build a star path.
context.moveTo(128.0, 28.0);
context.lineTo(157.0, 87.0);
context.lineTo(223.0, 97.0);
context.lineTo(175.0, 143.0);
context.lineTo(186.0, 208.0);
context.lineTo(128.0, 178.0);
context.lineTo(69.0, 208.0);
context.lineTo(80.0, 143.0);
context.lineTo(32.0, 97.0);
context.lineTo(98.0, 87.0);
context.closePath();
// Set up the drop shadow.
context.shadowBlur = 8.0;
context.shadowOffsetY = 4.0;
context.shadowColor = "rgba(0,0,0,0.5)";
// Fill the star with yellow.
context.fillStyle = "#ffe633";
context.fill();
// Draw the star with a thick red stroke and rounded points.
context.lineJoin = "round";
context.lineWidth = 12.0;
context.strokeStyle = "#e60080";
context.stroke();
// Draw the star again with a dashed thinner orange stroke.
const segments = [21.0, 9.0, 1.0, 9.0, 7.0, 9.0, 1.0, 9.0];
context.setLineDash(segments);
context.lineDashOffset = 10.0;
context.lineCap = "round";
context.lineWidth = 6.0;
context.strokeStyle = "#f2a626";
context.stroke();
// Turn off the drop shadow.
context.shadowColor = "rgba(0,0,0,0.0)";
// Add a shine layer over the star.
let gradient = context.createLinearGradient(64.0, 0.0, 192.0, 256.0);
gradient.addColorStop(0.30, "rgba(255,255,255,0.0)");
gradient.addColorStop(0.35, "rgba(255,255,255,0.8)");
gradient.addColorStop(0.45, "rgba(255,255,255,0.8)");
gradient.addColorStop(0.50, "rgba(255,255,255,0.0)");
context.fillStyle = gradient;
context.globalCompositeOperation = "source-atop";
context.fillRect(0.0, 0.0, 256.0, 256.0);
完整的 HTML 示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<canvas id="example" width="256" height="256"></canvas>
<script>
const context = document.getElementById("example").getContext("2d");
// Build a star path.
context.moveTo(128.0, 28.0);
context.lineTo(157.0, 87.0);
context.lineTo(223.0, 97.0);
context.lineTo(175.0, 143.0);
context.lineTo(186.0, 208.0);
context.moveTo(128.0, 178.0);
context.lineTo(69.0, 208.0);
context.lineTo(80.0, 143.0);
context.lineTo(32.0, 97.0);
context.lineTo(98.0, 87.0);
context.closePath();
// Set up the drop shadow.
context.shadowBlur = 8.0;
context.shadowOffsetY = 4.0;
context.shadowColor = "rgba(0,0,0,0.5)";
// Fill the star with yellow.
context.fillStyle = "#ffe633";
context.fill();
// Draw the star with a thick red stroke and rounded points.
context.lineJoin = "round";
context.lineWidth = 12.0;
context.strokeStyle = "#e60080";
context.stroke();
// Draw the star again with a dashed thinner orange stroke.
const segments = [21.0, 9.0, 1.0, 9.0, 7.0, 9.0, 1.0, 9.0];
context.setLineDash(segments);
context.lineDashOffset = 10.0;
context.lineCap = "round";
context.lineWidth = 6.0;
context.strokeStyle = "#f2a626";
context.stroke();
// Turn off the drop shadow.
context.shadowColor = "rgba(0,0,0,0.0)";
// Add a shine layer over the star.
let gradient = context.createLinearGradient(64.0, 0.0, 192.0, 256.0);
gradient.addColorStop(0.30, "rgba(255,255,255,0.0)");
gradient.addColorStop(0.35, "rgba(255,255,255,0.8)");
gradient.addColorStop(0.45, "rgba(255,255,255,0.8)");
gradient.addColorStop(0.50, "rgba(255,255,255,0.0)");
context.fillStyle = gradient;
context.globalCompositeOperation = "source-atop";
context.fillRect(0.0, 0.0, 256.0, 256.0);
</script>
</body>
</html>