Bootstrap

C++ 2D矢量绘图库

代码

#include <iostream>
#include "include/blend2d.h"
#include "include/blend2d/image.h"

void useCoreDrawImage() {
  BLResult r;
  BLImageCore img;
  BLContextCore ctx;

  r = blImageInitAs(&img, 480, 480, BL_FORMAT_PRGB32);
  if (r != BL_SUCCESS)
    return;

  r = blContextInitAs(&ctx, &img, NULL);
  if (r != BL_SUCCESS) {
    // Image has been already created, so destroy it.
    blImageDestroy(&img);
    return;
  }

  blContextClearAll(&ctx);

  // First shape filled with a radial gradient.
  // By default, SRC_OVER composition is used.
  BLGradientCore radial;
  BLRadialGradientValues radialValues = {
      180, 180, 180, 180, 180
  };

  blGradientInitAs(&radial,
                   BL_GRADIENT_TYPE_RADIAL, &radialValues,
                   BL_EXTEND_MODE_PAD, NULL, 0, NULL);
  blGradientAddStopRgba32(&radial, 0.0, 0xFFFFFFFFu);
  blGradientAddStopRgba32(&radial, 1.0, 0xFFFF6F3Fu);

  BLCircle circle = {180, 180, 160};
  blContextFillGeometryExt(&ctx,
                           BL_GEOMETRY_TYPE_CIRCLE, &circle, &radial);

  // Unused styles must be destroyed.
  blGradientDestroy(&radial);

  // Second shape filled with a linear gradient.
  BLGradientCore linear;
  BLLinearGradientValues linearValues = {
      195, 195, 470, 470
  };

  blGradientInitAs(&linear,
                   BL_GRADIENT_TYPE_LINEAR, &linearValues,
                   BL_EXTEND_MODE_PAD, NULL, 0, NULL);
  blGradientAddStopRgba32(&linear, 0.0, 0xFFFFFFFFu);
  blGradientAddStopRgba32(&linear, 1.0, 0xFF3F9FFFu);

  // Use 'blContextSetCompOp()' to change a composition operator.
  blContextSetCompOp(&ctx, BL_COMP_OP_DIFFERENCE);

  BLRoundRect roundRect = { 195, 195, 270, 270, 25, 25 };
  blContextFillGeometryExt(&ctx,
                           BL_GEOMETRY_TYPE_ROUND_RECT, &roundRect, &linear);

  // Unused styles must be destroyed.
  blGradientDestroy(&linear);

  // Finalize the rendering and destroy the rendering context.
  blContextDestroy(&ctx);

  // An example of querying a codec from Blend2D internal codecs.
  BLImageCodecCore codec;
  blImageCodecInitByName(&codec, "PNG", SIZE_MAX, NULL);
  blImageWriteToFile(&img, "bl_sample_capi.png", &codec);
  blImageCodecDestroy(&codec);

  blImageDestroy(&img);
}

void drawImage(int w, int h) {
  BLImage m_blImage(w, h, BL_FORMAT_PRGB32);
  BLContextCreateInfo createInfo{};
  // GetPitch这个很重要了,图像的间距
  // m_blImage.createFromData(m_bckImge.GetWidth(), m_bckImge.GetHeight(), BL_FORMAT_XRGB32, m_bckImge.GetBits(), m_bckImge.GetPitch());

  BLContext ctx(m_blImage, createInfo);
  ctx.setFillStyle(BLRgba32(0xFF000000));
  ctx.fillAll();

  BLPath path;
  BLGradient linear(BLLinearGradientValues(0, 0, 0, 480));
  // Color stops can be added in any order.
  linear.addStop(0.0, BLRgba32(0xFFFFFFFF));
  linear.addStop(0.5, BLRgba32(0xFF5FAFDF));
  linear.addStop(1.0, BLRgba32(0xFF2F5FDF));
  // `setFillStyle()` can be used for both colors
  // and styles. Alternatively, a color or style
  // can be passed explicitly to a render function.
  ctx.setFillStyle(linear);

  // Rounded rect will be filled with the linear
  // gradient.
  ctx.fillRoundRect(640.0, 40.0, 400.0, 400.0, 45.5);

  int yLen = m_blImage.height();
  int xLen = m_blImage.width();
  int xCenter = m_blImage.width() / 2;
  int yCenter = m_blImage.height() / 2;
  path.addLine(BLLine(0, yCenter, xLen, yCenter));
  path.addLine(BLLine(xCenter, 0, xCenter, yLen));

  // 圆
  path.addCircle(BLCircle(xCenter / 2, xCenter / 2, 50));
  // 弧
  path.addArc(BLArc(150, 150, 50, 50, 0, 120 * 3.1415926 / 180.0f));

  // Create a path having cubic curves.
  path.moveTo(26, 31);
  path.cubicTo(642, 132, 587, -136, 25, 464);
  path.cubicTo(882, 404, 144, 267, 27, 31);

  BLFontFace face;
  BLResult err = face.createFromFile("ABeeZee-Regular.ttf");
  // 文字
  BLFont font;
  font.createFromFace(face, 50.0f);

  ctx.setFillStyle(BLRgba32(0xFFFFFFFF));
  ctx.fillUtf8Text(BLPoint(xCenter + 150, yCenter + 180), font, "Hello World!");
  ctx.rotate(0.785398);
  ctx.fillUtf8Text(BLPoint(250, 80), font, "rotatedText");

  ctx.setCompOp(BL_COMP_OP_SRC_OVER);
  ctx.setStrokeStyle(linear);
  ctx.setStrokeWidth(1);
  ctx.strokePath(path);

  // Fill a path with opaque white - 0xAARRGGBB.
//  ctx.fillPath(path, BLRgba32(0xFFFFFFFF));

  ctx.end();

  // Let's use some built-in codecs provided by Blend2D.
  m_blImage.writeToFile("bl_sample_1.png");
}

void clipImage(int w, int h) {
  BLImage img(w, h, BL_FORMAT_PRGB32);
  BLContext ctx(img);

  ctx.clearAll();
  // Read an image from file.
  BLImage texture;
  BLResult err = texture.readFromFile("bl_sample_1.png");

  // Handle a possible error.
  if (err != BL_SUCCESS) {
    printf("Failed to load a texture (err=%u)\n", err);
    return;
  }

  // Rotate by 45 degrees about a point at [240, 240].
  // ctx.rotate(0.785398, 240.0, 240.0);

  // Create a pattern and use it to fill a rounded-rect.
  // By default a repeat extend mode is used, but it can
  // be configured to use more extend modes
  BLPattern pattern(texture);
  ctx.fillRoundRect(
      BLRoundRect(640.0, 40.0, 400.0, 400.0, 45.5),
      pattern);

  ctx.end();
  img.writeToFile("bl_sample_2.png");
}

void blendMode() {
  BLImage img(480, 480, BL_FORMAT_PRGB32);
  BLContext ctx(img);

  ctx.clearAll();

  // First shape filled with a radial gradient.
  // By default, SRC_OVER composition is used.
  BLGradient radial(
      BLRadialGradientValues(180, 180, 180, 180, 180));
  radial.addStop(0.0, BLRgba32(0xFFFFFFFF));
  radial.addStop(1.0, BLRgba32(0xFFFF6F3F));
  ctx.fillCircle(180, 180, 160, radial);

  // Second shape filled with a linear gradient.
  BLGradient linear(
      BLLinearGradientValues(195, 195, 470, 470));
  linear.addStop(0.0, BLRgba32(0xFFFFFFFF));
  linear.addStop(1.0, BLRgba32(0xFF3F9FFF));

  // Use 'setCompOp()' to change a composition operator.
  ctx.setCompOp(BL_COMP_OP_DIFFERENCE);
  ctx.fillRoundRect(
      BLRoundRect(195, 195, 270, 270, 25), linear);

  ctx.end();

  img.writeToFile("blend.png");
}


int strokeCap() {
  BLImage img(480, 480, BL_FORMAT_PRGB32);
  BLContext ctx(img);

  ctx.clearAll();

  BLGradient linear(
      BLLinearGradientValues(0, 0, 0, 480));
  linear.addStop(0.0, BLRgba32(0xFFFFFFFF));
  linear.addStop(0.5, BLRgba32(0xFFFF1F7F));
  linear.addStop(1.0, BLRgba32(0xFF1F7FFF));

  BLPath path;
  path.moveTo(119, 49);
  path.cubicTo(259, 29, 99, 279, 275, 267);
  path.cubicTo(537, 245, 300, -170, 274, 430);

  // Use 'setStrokeXXX' to change stroke options.
  ctx.setStrokeWidth(15);
  ctx.setStrokeStartCap(BL_STROKE_CAP_ROUND);
  ctx.setStrokeEndCap(BL_STROKE_CAP_BUTT);

  ctx.strokePath(path, linear);

  ctx.end();

  img.writeToFile("strokeCap.png");
  return 0;
}

void multiLineText() {
  BLImage img(480, 480, BL_FORMAT_PRGB32);
  BLContext ctx(img);

  const char fontName[] = "ABeeZee-Regular.ttf";
  const char* str =
      "Hello Blend2D!\n"
      "I'm a simple multiline text example\n"
      "that uses GlyphBuffer and GlyphRun!";
  BLRgba32 color(0xFFFFFFFFu);

  BLFontFace face;
  BLResult result = face.createFromFile(fontName);
  if (result != BL_SUCCESS) {
    printf("Failed to load a face (err=%u)\n", result);
    return;
  }

  BLFont font;
  font.createFromFace(face, 20.0f);

  BLGlyphBuffer gb;
  BLTextMetrics tm;
  BLFontMetrics fm = font.metrics();
  double y = 190 + fm.ascent;

  ctx.clearAll();
  do {
    const char* nl = strchr(str, '\n');
    gb.setUtf8Text(str,
                   nl ? (size_t)(nl - str) : SIZE_MAX);
    font.shape(gb);
    font.getTextMetrics(gb, tm);

    double x = (tm.boundingBox.x1 - tm.boundingBox.x0);
    ctx.fillGlyphRun(BLPoint((480.0 - x) / 2, y),
                     font, gb.glyphRun(), color);

    y += fm.ascent + fm.descent + fm.lineGap;
    str = nl ? nl + 1 : nullptr;
  } while (str);
  ctx.end();

  img.writeToFile("multi_line_text.png");
}


int main() {
  drawImage(1600, 900); // 绘制
  clipImage(1600, 900); // 裁剪
  blendMode(); // 混合模式
  strokeCap();  // 描边
  multiLineText(); // 多行文本排版
  printf("Hello World!");
  return 0;
}
效果 

参考

 C++ 几何计算库-CSDN博客

C++ OPENGL 贝塞尔曲线绘制-CSDN博客

https://github.com/blend2d/blend2d

3rdparty\asmjit


创作不易,小小的支持一下吧!

;