在开发这个生成二维码扩展 dcode 的时候,需要将生成的二维码 png 图片以字符串的方式返回给调用者,而不是直接生成文件,这样比较方便的是不用去操作文件,将文件的操作完全交给用户。
生成图片采用了 libpng 的库,关于 libpng 的文档大家可以到 这里 png 文档 看。我使用这个库在 Ubuntu14.04 上编译我的扩展的时候还有个小问题 png_create_write_struct in Unknown on line 0 on ubuntu 14,到网上一搜索,还是非常常见的。
下面简单的列一下代码:
<code><span>/** {{{ dcode_png_writer()
* function is custom png_write callback function
* Return void */</span><span>static</span><span>void</span> dcode_png_writer(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_mem_encode* p = (png_mem_encode*) png_get_io_ptr(png_ptr);
size_t nsize = p->size + length;
<span>if</span> (p->buffer)
p->buffer = erealloc(p->buffer, nsize);
<span>else</span>
p->buffer = emalloc(nsize);
<span>if</span> (!p->buffer)
{
png_error(png_ptr, <span>"PNG allocate memory error"</span>);
<span>exit</span>(FAILURE);
}
<span>memcpy</span>(p->buffer + p->size, data, length);
p->size += length;
}
<span>/* }}} */</span></code><code><span>/** {{{ dcode_write_to_png()
* write qrcode struct to memory
* Return char* */</span><span>static</span><span>char</span>* dcode_write_to_png(QRcode *qrcode, <span>int</span> size, <span>int</span> margin, <span>int</span> *pp_len)
{
png_structp png_ptr;
png_infop info_ptr;
<span>unsigned</span><span>char</span> *row, *p, *q;
<span>int</span> x, y, xx, yy, bit;
<span>int</span> realwidth;
realwidth = (qrcode->width + margin * <span>2</span>) * size;
<span>int</span> row_fill_len = (realwidth + <span>7</span>) / <span>8</span>;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
<span>if</span> (png_ptr == NULL)
{
php_error(E_ERROR, <span>"Failed to initialize PNG writer"</span>);
<span>return</span> NULL;
}
info_ptr = png_create_info_struct(png_ptr);
<span>if</span> (info_ptr == NULL)
{
php_error(E_ERROR, <span>"Failed to initialize PNG info"</span>);
<span>return</span> NULL;
}
<span>if</span> (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_write_struct(&png_ptr, &info_ptr);
php_error(E_ERROR, <span>"Failed to set PNG jmpbuf"</span>);
<span>return</span> NULL;
}
row = (<span>unsigned</span><span>char</span> *) emalloc(row_fill_len);
<span>if</span> (row == NULL)
{
png_destroy_write_struct(&png_ptr, &info_ptr);
php_error(E_ERROR, <span>"Failed to allocate memory"</span>);
<span>return</span> NULL;
}
png_mem_encode state = {NULL, <span>0</span>};
png_set_write_fn(png_ptr, &state, &dcode_png_writer, NULL);
png_set_IHDR(png_ptr,
info_ptr,
realwidth,
realwidth,
<span>1</span>,
PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
<span>memset</span>(row, <span>0xff</span>, (realwidth + <span>7</span>) / <span>8</span>);
<span>for</span>(y = <span>0</span>; y < margin * size; y ++) {
png_write_row(png_ptr, row);
}
p = qrcode->data;
<span>for</span>(y = <span>0</span>; y < qrcode->width; y ++) {
bit = <span>7</span>;
<span>memset</span>(row, <span>0xff</span>, (realwidth + <span>7</span>) / <span>8</span>);
q = row;
q += margin * size / <span>8</span>;
bit = <span>7</span> - (margin * size % <span>8</span>);
<span>for</span>(x = <span>0</span>; x < qrcode->width; x ++) {
<span>for</span>(xx = <span>0</span>; xx <size; xx ++) {
*q ^= (*p & <span>1</span>) << bit;
bit--;
<span>if</span>(bit < <span>0</span>) {
q++;
bit = <span>7</span>;
}
}
p++;
}
<span>for</span>(yy = <span>0</span>; yy < size; yy ++ ) {
png_write_row(png_ptr, row);
}
}
<span>memset</span>(row, <span>0xff</span>, (realwidth + <span>7</span>) / <span>8</span>);
<span>for</span>(y = <span>0</span>; y < margin * size; y ++) {
png_write_row(png_ptr, row);
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
efree(row);
<span>char</span> *bin_data = NULL;
<span>if</span> (state.buffer) {
bin_data = estrndup(state.buffer, state.size);
*pp_len = state.size;
efree(state.buffer);
}
<span>return</span> bin_data;
}
<span>/** }}} */</span></code>dcode_png_writer 是自定义的写 png 数据的 callback 函数。dcode_write_to_png 是将 QRcode 数据写入 png主要可以看下这个部分
<code>png_set_write_fn(png_ptr, &state, &dcode_png_writer, NULL);</code>
这个地方就是调用了自定义的 write 函数 dcode_png_writer,将数据写到了 state 这个结构体里,state 结构体如下
立即学习“PHP免费学习笔记(深入)”;
<code><span>typedef</span><span>struct</span> _png_mem_encode {
<span>char</span> *buffer;
size_t size;
} png_mem_encode ;</code>png_set_write_fn 函数设置了自定义的 write 函数,通过 dcode_png_writer 来像 state 写入数据,动态的来分配内存。
关于 png_set_write_fn 的定义,可以参看上面提到的 PNG 文档,自定义函数还可以自定义错误处理等功能,这样可以根据实际情况来接管 error handler 而不是让其在内部退出。更多的相关代码请看 DCode 扩展
生成 QRCode 的速度还是很快的,如果用 for ($i = 0; $i 的 <code>$i 作为参数,3秒就能生成 10000 个。
版权声明:本文为博主原创文章,未经博主允许不得转载。
以上就介绍了php扩展开发笔记(10)自定义 libpng 库中的 IO 函数,将图片写入内存,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号