
2026/02/22 3:50
キャンバス・イティ:C++ 用の極小で単一ヘッダーな `<canvas>` に似た 2D ラスタライザ―
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
本段落は、C++ の
ライブラリで描画された 256 × 256 ピクセルの星が、同一の図形を HTML5 Canvas 上で JavaScript によって描画した場合とまったく同じ視覚結果になることを示しています。canvas_ity星の幾何学 – 両プログラムともに、座標 (128,28)、(157,87)、(223,97)、(175,143)、(186,208)、(128,178)、(69,208)、(80,143)、(32,97)、および (98,87) を用いて十角形の閉じたパスを定義します。
影 – 最初に塗りつぶす前に、
、shadowBlur = 8.0fと色shadowOffsetY = 4.0fを持つドロップシャドウが適用されます。その後、そのアルファを 0 に設定して無効化します。rgba(0,0,0,0.5)スタイリング – 星はまず純粋な黄色 (
/rgba(1.0,0.9,0.2,1.0)) で塗りつぶされます。その後、二度にわたりストロークが行われます。最初は太い赤色の線幅12、丸みを帯びたジョイン(#ffe633/rgba(0.9,0,0.5,1.0))で描画され、次に細めのオレンジの破線が線幅6、丸みのあるキャップ、ダッシュパターン#e60080、オフセット10、色[21,9,1,9,7,9,1,9]/rgba(0.95,0.65,0.15,1.0)で描かれます。#f2a626グラデーションの輝き – (64,0) から (192,256) への線形グラデーションがキャンバス全体に追加され、停止点は 0.30(
)、0.35 & 0.45(rgba(1,1,1,0))、および 0.50(rgba(1,1,1,0.8))です。合成モードはrgba(1,1,1,0)が使用されます。source-atopエクスポート – 最終的な RGBA ピクセルバッファは BGRA 順序に変換され、32‑ビット深度の 12 バイトヘッダー付き TGA ファイル
として書き込まれます。example.tgaJavaScript 等価 – 同伴する HTML ページでは、
を使用し、影・塗りつぶし・ストローク・ダッシュ・グラデーションのパラメータを一致させることで、この正確な描画手順が再現されます。getContext("2d")この例は、ネイティブ C++ の
を用いたキャンバス描画とブラウザ上の HTML5 Canvas API との間でグラフィックロジックを移植できること、かつ視覚的な損失がないことを示しており、デスクトップとウェブプラットフォーム間で一貫したビジュアルを必要とする開発者にとって価値があります。canvas_ity
本文
C++(
)example.cpp
#include <algorithm> #include <fstream> #define CANVAS_ITY_IMPLEMENTATION #include "canvas_ity.hpp" int main() { /* キャンバスを構築する */ static const int width = 256, 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_iety::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_iety::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); /* TGA ファイル(BGRA 順序)として結果をエクスポートする */ unsigned char* image = new unsigned char[height * width * 4]; context.get_image_data(image, width, height, width * 4, 0, 0); for (int pixel = 0; pixel < height * width; ++pixel) std::swap(image[pixel * 4 + 0], image[pixel * 4 + 2]); unsigned char header[] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, width & 255, width >> 8, height & 255, height >> 8, 32, 40 }; std::ofstream stream("example.tga", std::ios::binary); stream.write(reinterpret_cast<char*>(header), sizeof(header)); stream.write(reinterpret_cast<char*>(image), height * width * 4); delete[] image; }
HTML(
)index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Example</title> <style> canvas { border:1px solid #000; } </style> </head> <body> <canvas id="example" width="256" height="256"></canvas> <script> const ctx = document.getElementById('example').getContext('2d'); /* 星形パスを作成する */ ctx.moveTo(128.0, 28.0); ctx.lineTo(157.0, 87.0); ctx.lineTo(223.0, 97.0); ctx.lineTo(175.0, 143.0); ctx.lineTo(186.0, 208.0); ctx.lineTo(128.0, 178.0); ctx.lineTo(69.0, 208.0); ctx.lineTo(80.0, 143.0); ctx.lineTo(32.0, 97.0); ctx.lineTo(98.0, 87.0); ctx.closePath(); /* ドロップシャドウを設定する */ ctx.shadowBlur = 8; ctx.shadowOffsetY = 4; ctx.shadowColor = 'rgba(0,0,0,.5)'; /* 黄色で塗りつぶす */ ctx.fillStyle = '#ffe633'; ctx.fill(); /* 太い赤のストローク(角は丸める)を描く */ ctx.lineJoin = 'round'; ctx.lineWidth = 12; ctx.strokeStyle = '#e60080'; ctx.stroke(); /* より薄いオレンジの破線ストローク */ const segments = [21.0, 9.0, 1.0, 9.0, 7.0, 9.0, 1.0, 9.0]; ctx.setLineDash(segments); ctx.lineDashOffset = 10; ctx.lineCap = 'round'; ctx.lineWidth = 6; ctx.strokeStyle = '#f2a626'; ctx.stroke(); /* ドロップシャドウを無効にする */ ctx.shadowColor = 'rgba(0,0,0,.0)'; /* 光沢レイヤーを追加する */ const grad = ctx.createLinearGradient(64.0, 0.0, 192.0, 256.0); grad.addColorStop(0.30, 'rgba(255,255,255,0)'); grad.addColorStop(0.35, 'rgba(255,255,255,.8)'); grad.addColorStop(0.45, 'rgba(255,255,255,.8)'); grad.addColorStop(0.50, 'rgba(255,255,255,0)'); ctx.fillStyle = grad; ctx.globalCompositeOperation = 'source-atop'; ctx.fillRect(0, 0, 256, 256); </script> </body> </html>
不要な改行や空白はすべて削除し、読みやすさのためにインデントを揃えました。