php转换图片为.bin文件
[我的另外一個博客地址:http://www.ncmacker.cc,那邊排版會比較好點。]
公司的打印機最近新添加一個打印圖片的功能,具體是用戶在后臺設置他的logo,服務器接收到圖片文件,轉換單色的bmp文件(熱敏打印機),再由php將單色bmp圖片轉換成bin文件,里面包含了圖片的頭信息和數據。做這么個小功能還花了我不少時間,走了很多彎路,各位看官請容我一一講述吧。
思路1:使用PHP擴展用c語言來完成這個操作
最開始的時候,認為這個操作php語言無法勝任,于是選用了php extension。可是作為菜鳥的我,何曾玩過這么高大上的技能?沒辦法了,只好現學現賣了,最開始我以為是只要用c語言將轉換的功能實現了,然后封裝下就可以給php調用,做到后面才發現很多c語言的函數都不能直接使用,要么是被閹割掉了,要么就是被zend重寫了,只有遵循zend_api才能夠做出一個有用的php擴展。網上搜索了很多關于php extension的資料,發現中文資料還是相對較少。雖然有那么幾個稍微系統點的資料:
PHP擴展開發及內核應用
這本書的是翻譯的一本國外一個大牛的擴展開發的書籍,翻譯的還是比較有水準的,這個翻譯項目的發起人也是大牛,其中最為知名的應該是鳥哥,如果連鳥哥都不知道的話,你這php程序員估計也是白當了。
還有極客學院也有一份這本書,與上面介紹的差不多。還有這本深入理解php內核:Thinking In PHP Int ernals也不錯。還有一些國外牛人整理的一些資料,先不再這里羅嗦,待會放在結尾當福利發送哈。
我的php extension第一步是先搭建環境,我也把搭建環境的步驟也講下吧,這樣也方便其他需要使用到擴展的童鞋。
1.下載php的完整版源碼,我的是php-5.4.41版本的,因為公司的服務器就是使用的5.4.41的,不然版本不對,擴展就算開發好了,后面也是無法添加到php里的(可以兼容老版本的,但是開發版本不能比服務器版本高)。
2.將下載好的php源碼解壓放在某個地方,我的是放在主文件夾里(就是ubuntu的個人文件夾里)。
然后用cd命令跳轉到php-5.4.41/ext目錄下:
cd /home/pchangl/php-5.4.41/ext然后在主文件夾下創建一個extension_def的目錄(這個目錄不是必須的,只是我為了方便管理.def的文件才建立的),在這個文件夾下建立一個叫做pchangl.def的文件(def的文件是擴展方法的簽名)。
這個時候建立好了def的文件,我們就開始使用php/ext目錄下的ext_skel小工具為我們的擴展生成框架。
root@pchangl:/home/pchangl/php-5.4.41/ext #ext_skel --extname=pchangl --proto=/home/pchangl/php-extension/pchangl.def這個時候就給我們生成了擴展的框架:
這個時候我們的框架已經生成了,我們先把config.m4文件修改下,刪除掉第16,17,18行前的dnl注釋
這個時候我們就可以修改pchangl.c的代碼了,這個文件里的代碼就是我們自己的程序代碼。
#ifdef HAVE_CONFIG_H #include "config.h" #endif#include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_pchangl.h" static int le_pchangl; const zend_function_entry pchangl_functions[] = { PHP_FE(confirm_pchangl_compiled, NULL) /* For testing, remove later. */ PHP_FE_END /* Must be the last line in pchangl_functions[] */ }; zend_module_entry pchangl_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "pchangl", pchangl_functions, PHP_MINIT(pchangl), PHP_MSHUTDOWN(pchangl), PHP_RINIT(pchangl), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(pchangl), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(pchangl), #if ZEND_MODULE_API_NO >= 20010901 PHP_PCHANGL_VERSION, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PCHANGL ZEND_GET_MODULE(pchangl) #endif PHP_MINIT_FUNCTION(pchangl) { return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(pchangl) { return SUCCESS; } PHP_RINIT_FUNCTION(pchangl) { return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(pchangl) { return SUCCESS; } PHP_MINFO_FUNCTION(pchangl) { php_info_print_table_start(); php_info_print_table_header(2, "pchangl support", "enabled"); php_info_print_table_end(); } PHP_FUNCTION(confirm_pchangl_compiled) { char *arg = NULL; int arg_len, len; char *strg; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { return; } len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "pchangl", arg); RETURN_STRINGL(strg, len, 0); }上面的這個代碼是ext_skel工具生成的框架,你寫的擴展也要按照他的標準來寫,由于代碼長度的原因,我刪除掉了一部分生成的注釋,如果想看的話,你可以自己編寫個框架看看注視,下面我就講解下幾個比較重要的部分吧。
PHP_MINIT_FUNCTION(pchangl) {return SUCCESS; }這個方法隨著php在apache或者nginx中啟動而誕生內存的時候,就會執行,可以把這個方法當成初始化的方法吧。
PHP_RINIT_FUNCTION(pchangl) {return SUCCESS; }
這個方法會在每一個頁面請求到來的時候執行。
PHP_RSHUTDOWN_FUNCTION(pchangl) {return SUCCESS; }
RINIT_FUNCTION方法執行玩后,請求也處理的差不多了,這個時候就會進入這個方法,啟動回收程序來收拾爛攤子。
PHP_MSHUTDOWN_FUNCTION(pchangl) {return SUCCESS; }
前面該啟動的也啟動了,該結束的也結束了,現在該apache老人家休息的時候,當apache通知php自己要stop的時候,就會進入這個方法。給擴展下最后通碟,如果有未了的心愿,就放在這個方法里,這可是最后的機會哦
PHP_FUNCTION(function name) { //實現 }
這個方法就是我們擴展方法的主體了。
pchangl.c這個文件就介紹到這里了,其他的內容就到我推薦的幾個資料中查詢吧,都有的。我也就不一一講解了。
介紹完了環境的搭建,我就開始寫自己的擴展,我們的bmp轉bin的c代碼是這樣的:
#include <stdio.h> #include <stdlib.h> #include <memory.h>//調試開關 #define PRINTF_DEBUG 0//四個字節對齊 進1制處理 #define WIDTHBYTES(bits) (((bits)+31)/32*4) //每一行的像素寬度必須是4的倍數,否則補0補齊。 /*定義BYTE為無符號一個字節的類型*/ typedef unsigned char BYTE; /*定義WORD為無符號兩個字節的類型*/ typedef unsigned short WORD; /*定義DWORD為無符號四個字節的類型*/ typedef unsigned long DWORD; #pragma pack(1) /*位圖文件頭*/ typedef struct BMP_FILE_HEADER { WORD bType; /* 文件標識符 */ DWORD bSize; /* 文件的大小 */ WORD bReserved1; /* 保留值,必須設置為0 */ WORD bReserved2; /* 保留值,必須設置為0 */ DWORD bOffset; /* 文件頭的最后到圖像數據位開始的偏移量 */ } BMPFILEHEADER; /*位圖信息頭*/ typedef struct BMP_INFO { DWORD bInfoSize; /* 信息頭的大小 */ DWORD bWidth; /* 圖像的寬度 */ DWORD bHeight; /* 圖像的高度 */ WORD bPlanes; /* 圖像的位面數 */ WORD bBitCount; /* 每個像素的位數 */ DWORD bCompression; /* 壓縮類型 */ DWORD bmpImageSize; /* 圖像的大小,以字節為單位 */ DWORD bXPelsPerMeter; /* 水平分辨率 */ DWORD bYPelsPerMeter; /* 垂直分辨率 */ DWORD bClrUsed; /* 使用的色彩數 */ DWORD bClrImportant; /* 重要的顏色數 */ } BMPINF; typedef struct tagRGBQUAD { BYTE rgbBlue; //藍色的亮度(值范圍為0-255) BYTE rgbGreen; //綠色的亮度(值范圍為0-255) BYTE rgbRed; //紅色的亮度(值范圍為0-255) BYTE rgbReserved; //保留,必須為0 } RGBQUAD; #pragma pack() int main() { FILE *fpin = NULL; FILE *fpout = NULL; BMPFILEHEADER fileHeader = { 0, 0 }; BMPINF infoHeader = { 0, 0 }; RGBQUAD imgHeader[256 * 4] = { 0, 0 }; DWORD offset = 0, width = 0, height = 0, bitCount = 0; DWORD l_width = 0, bmp_width = 0, bmp_height = 0; DWORD i = 0, j = 0, m = 0; BYTE *bmpDataTmp = NULL; BYTE *bmpPixelTmp = NULL; BYTE bmp_start[8] = "ICONTOP"; BYTE bmp_end[8]轉載于:https://www.cnblogs.com/pchangl/p/4937684.html
總結
以上是生活随笔為你收集整理的php转换图片为.bin文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 1800: [Ahoi2009
- 下一篇: 抓包工具收集