首頁  >  文章  >  後端開發  >  php擴充開發筆記(10)自訂 libpng 函式庫中的 IO 函數,將圖片寫入記憶體

php擴充開發筆記(10)自訂 libpng 函式庫中的 IO 函數,將圖片寫入記憶體

WBOY
WBOY原創
2016-08-08 09:21:341333瀏覽

在開發這個生成二維碼擴展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>
  1. 第一個函數 dcode_png_writer 是自訂的寫 png 資料的 callback 函數。
  2. 第二個函數dcode_write_to_png 是將QRcode 資料寫入png

主要可以看下這個部分

<code>png_set_write_fn(png_ptr, &state, &dcode_png_writer, NULL);</code>

這個地方就是調用了自定義的write 函數結構體裡,state 結構體如下

<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 的

$i 作為參數,3秒就能生成10000 個。

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。

以上就介紹了php擴充開發筆記(10)自訂 libpng 庫中的 IO 函數,將圖片寫入內存,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:nginx-代碼-499下一篇:nginx-代碼-499