You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言结合stb库实现任意尺寸QR码PNG图像编码导出

问题描述

使用QR-Code-generator 1.8.0与stb_image_write库将QR码渲染为PNG、SVG格式图像时,参照官方demo示例可以正确生成QR码,但输出图像尺寸过小,不清楚缩放实现方式。经判断缩放逻辑应在图像写入环节实现,但不知道如何调整像素数据构造逻辑,实现通过函数参数传入目标尺寸,输出任意自定义大小的QR码图像。

初始问题代码

#include "qrcodegen.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

#define Border    4

void qr_make_image_data(const uint8_t *data, uint8_t **result) {
  int size = qrcodegen_getSize(data);
  int border = Border;
  *result = calloc(1, (size + border*2)*(size + border*2)*2);
  int count = 0;
  for (int y = -border; y < size + border; y++)
    for (int x = -border; x < size + border; x++) 
      (*result)[count++] = qrcodegen_getModule(data, x, y) ? 0xff : 0x00;
}

int qr_make(char *text, char *file_out) {
  uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
  uint8_t temp_buf[qrcodegen_BUFFER_LEN_MAX];
  bool ok = qrcodegen_encodeText(text, temp_buf, qrcode,
      qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
      qrcodegen_Mask_AUTO, true);
  if (!ok) return -1;
  int size = qrcodegen_getSize(qrcode);
  uint8_t *data = NULL;
  qr_make_image_data(qrcode, &data);

  int image_side = size + Border * 2;
  int result = stbi_write_png(file_out, image_side, image_side, 1, data, 0);
  free(data);
  return result;
}

int main(void) {
  char *sample_text_1 = "Donec diam neque, vestibulum eget, "
    "vulputate ut, ultrices vel, augue. Donec posuere metus "
    "vitae ipsum. Mauris sit amet eros. Vestibulum ac est "
    "lacinia nisi venenatis tristique. Integer pede justo, "
    "lacinia eget, tincidunt eget, tempus vel, pede.";

  char *sample_text_2 = "www.stackoverflow.com";

  qr_make(sample_text_1, "qr1.png");
  qr_make(sample_text_2, "qr2.png");
}
解决方案

修复原有代码中像素值反转的错误,引入stb_image_resize库实现输出图像缩放,支持传入缩放因子调整输出尺寸。

  • 修正点1:原代码中QR码模块颜色逻辑写反,黑色模块对应像素值0x00、白色背景对应0xff
  • 修正点2:移除原像素缓冲区多余的2倍内存分配,单通道灰度图每个像素仅占1字节
  • 修正点3:新增resize_factor缩放因子参数,使用盒式滤镜缩放保证QR码边缘锐利无模糊
  • 修正点4:缩放完成后及时释放原始像素缓冲区与缩放后缓冲区,避免内存泄漏

修正后完整代码

#include "qrcodegen.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"

#define Border    4

void qr_make_image_data(const uint8_t *data, uint8_t **result) {
  int size = qrcodegen_getSize(data);
  int border = Border;
  *result = calloc(1, (size + border*2)*(size + border*2));
  int count = 0;
  for (int y = -border; y < size + border; y++)
    for (int x = -border; x < size + border; x++) {
      (*result)[count++] = qrcodegen_getModule(data, x, y) ? 0x00 : 0xff;
    }
}

int qr_make(char *text, char *file_out, int resize_factor) {
  uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
  uint8_t temp_buf[qrcodegen_BUFFER_LEN_MAX];

  // 编码文本生成QR码
  bool ok = qrcodegen_encodeText(text, temp_buf, qrcode,
      qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
      qrcodegen_Mask_AUTO, false);

  if (!ok) return -1;
  int size = qrcodegen_getSize(qrcode);
  uint8_t *data = NULL;
  qr_make_image_data(qrcode, &data);

  // 计算原始尺寸与缩放后尺寸
  int image_side = size + Border * 2;
  int image_side_resized = image_side * resize_factor;

  // 分配缩放后图像的内存缓冲区
  uint8_t *resized_data = malloc(image_side_resized * image_side_resized * 1);

  stbir_resize(data, image_side, image_side, 0, resized_data, image_side_resized, image_side_resized, 0,
      STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP,
      STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_SRGB, NULL);

  // 将像素数据编码为PNG文件写入磁盘
  int result = stbi_write_png(file_out, image_side_resized, image_side_resized, 1, resized_data, 0);
  free(data);
  free(resized_data);

  return result;
}

int main(void) {
  char *sample_text_1 = "Donec diam neque, vestibulum eget, "
    "vulputate ut, ultrices vel, augue. Donec posuere metus "
    "vitae ipsum. Mauris sit amet eros. Vestibulum ac est "
    "lacinia nisi venenatis tristique. Integer pede justo, "
    "lacinia eget, tincidunt eget, tempus vel, pede.";


  char *sample_text_2 = "www.stackoverflow.com";

  // 传入缩放因子4,输出4倍放大的QR码
  qr_make(sample_text_1, "QR1.png", 4);
  qr_make(sample_text_2, "QR2.png", 4);
}

内容的提问来源于stack exchange,提问作者anewb33

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:31:11