文章目錄
2 圖像處理應(yīng)用開發(fā)
2.1 BMP圖像處理
2.1.1 BMP文件格式解析
2.1.2 代碼實(shí)現(xiàn):將BMP文件解析為RGB格式,在LCD上顯示
2.2 JPEG圖像處理
2.2.1 JPEG文件格式和libjpeg編譯
2.2.2 libjpeg接口函數(shù)的解析和使用
2.2.3 使用libjpeg把JPEG文件解析為RGB格式,在LCD上顯示
2.3 PNG圖像處理
2.3.1 PNG文件格式和libpng編譯
2.3.2 libpng接口函數(shù)的解析和使用
2.3.3 使用libpng把png文件轉(zhuǎn)為rgb格式,在LCD上顯示
2.4 圖像調(diào)整
2.4.1 圖像的縮放
2.4.1.1 圖像縮放算法淺析
2.4.1.2源碼編寫:圖像縮放算法
2.4.2 圖像的旋轉(zhuǎn)
2.4.2.1 圖像旋轉(zhuǎn)算法淺析
2.4.2.2 源碼編寫:圖像旋轉(zhuǎn)算法
2 圖像處理應(yīng)用開發(fā)
前言:所有的圖像文件,都是一種二進(jìn)制格式文件,每一個(gè)圖像文件,都可以通過(guò)解析文件中的每一組二進(jìn)制數(shù)的含義來(lái)獲得文件中的各種信息,如圖像高度,寬度,像素位數(shù)等等。只是不同的文件格式所代表的二進(jìn)制數(shù)含義不一樣罷了。我們可以通過(guò)UltraEdit軟件打開圖像文件并查看里面的二進(jìn)制數(shù)排列。
2.1 BMP圖像處理
2.1.1 BMP文件格式解析
BMP是一種常見的圖像格式,BMP文件可看成由4個(gè)部分組成:位圖文件頭(bitmap-file header)、位圖信息頭(bitmap-information header)、調(diào)色板(color palette)和定義位圖的字節(jié)陣列。以最簡(jiǎn)單的24位真彩色BMP文件作例子講解:
位圖文件頭(bitmap-file header)
這部分可以理解為是一個(gè)結(jié)構(gòu)體,里面的每一個(gè)成員都表示一個(gè)屬性
位數(shù)文件頭由以下信息組成:
bfType | 2字節(jié) |
表明它是BMP格式的文件, 內(nèi)容固定為0x42,0x4D, 即ASCII字符中的“B”“M” |
bfSize | 4字節(jié) | BMP文件的大小,單位為字節(jié) |
bfReserved1 | 2字節(jié) | 保留 |
bfReserved2 | 2字節(jié) | 保留 |
名稱 | 字節(jié)數(shù) | 含義 |
---|
我們用UltraEdit打開一個(gè)BMP文件,可以看到如下信息
這是該BMP文件前32字節(jié)的數(shù)據(jù),可以看到,前兩個(gè)字節(jié)分別為0x42,0x4D;
接著后面4個(gè)字節(jié)依次是0x36,0xF9,0x15,0x00。
在BMP格式中,文件的存儲(chǔ)方式是小端模式,即如果一個(gè)數(shù)據(jù)需要用幾個(gè)字節(jié)來(lái)表示的話,那么,低位數(shù)據(jù)存在低位地址上,高位數(shù)據(jù)存在高位地址上。類似的,還有大端模式,即:如果一個(gè)數(shù)據(jù)需要用幾個(gè)字節(jié)來(lái)表示的話,那么,低位數(shù)據(jù)存在高位地址上,高位數(shù)據(jù)存在低位地址上。
所以0x36,0xF9,0x15,0x00四個(gè)數(shù)據(jù)拼接方法應(yīng)該是:0x0015F936(在數(shù)字中個(gè)位即最右邊才是最低位),它正好就是這個(gè)文件的大小:
緊接著是4個(gè)保留位字節(jié),其數(shù)據(jù)必須為0x00。
最后是4個(gè)字節(jié)的便宜位,可以看到位圖文件頭+位圖信息頭+調(diào)色板的大小應(yīng)該是0x36。
位圖信息頭(bitmap-information header)
位圖信息頭也可以理解為是一個(gè)結(jié)構(gòu)體,其成員有:
biSize | 4 | 整個(gè)位圖信息頭結(jié)構(gòu)體的大小 |
biWidth | 4 | 圖像寬度,單位為像素 |
biHeight | 4 |
圖像高度,單位為像素。 此外,這個(gè)數(shù)的 正負(fù)可以判斷圖像是正向還是倒向的,若為 正,則表示是正向;若為負(fù),則表示反向。 其實(shí)根本不同就是坐標(biāo)系的建立方法不一樣。 后面寫代碼時(shí)會(huì)講。 |
biPlanes | 2 | 顏色平面書,其值總為1 |
biBitCount | 2 |
即1個(gè)像素用多少位的數(shù)據(jù)來(lái)表示,其值可 能為1,4,8,16,24,32。我們是以24位 真彩色為例子講解的 |
biCompression | 4 | 數(shù)據(jù)的壓縮類型 |
biSizeImage | 4 | 圖像數(shù)據(jù)的大小,單位為字節(jié) |
biXPelsPerMeter | 4 | 水平分辨率,單位是像素/米 |
biYPelsPerMeter | 4 | 垂直分辨率,單位是像素/米 |
biClrUsed | 4 | 調(diào)色板中的顏色索引數(shù) |
biClrImportant | 4 |
說(shuō)明有對(duì)圖像有重要影響的顏色索引的數(shù) 目,若為0,表示都重要 |
名稱 | 字節(jié)數(shù) | 含義 |
---|
對(duì)照源文件數(shù)據(jù):
0E-11:00000028h = 40,表示這個(gè)結(jié)構(gòu)體大小是40字節(jié)。
12-15:00000320h = 800,圖像寬為800像素。
16-19:00000258h = 600,圖像高為600像素,與文件屬性一致。這是一個(gè)正數(shù),說(shuō)明圖像是正向的,數(shù)據(jù)是以圖像左下角為原點(diǎn),以水平向右為X軸正方向,以垂直向上為Y軸正方向排列的。若為負(fù),則說(shuō)明圖像是反向的,數(shù)據(jù)是以圖像左上角角為原點(diǎn),以水平向右為X軸正方向,以垂直向下為Y軸正方向排列的。
1A-1B:0001h, 該值總為1。
1C-1D:0018h = 24, 表示每個(gè)像素占24個(gè)比特,即24位真彩色
上面這幾個(gè)信息跟文件屬性是一致的:
1E-21:00000000h,BI_RGB, 說(shuō)明本圖像不壓縮。
22-25:00000000h,圖像的大小,因?yàn)槭褂肂I_RGB,所以設(shè)置為0。
26-29:00000000h,水平分辨率,缺省。
2A-2D:00000000h,垂直分辨率,缺省。
2E-31:00000000h,對(duì)于24位真彩色來(lái)說(shuō),是沒(méi)有調(diào)色板的,所以為0。
32-35:00000000h,對(duì)于24位真彩色來(lái)說(shuō),是沒(méi)有調(diào)色板的,所以為0。
調(diào)色板(color palette)
24位真彩色沒(méi)有調(diào)色板,這里為了簡(jiǎn)化不贅訴。
定義位圖的字節(jié)陣列
這一部分就是真正的圖像數(shù)據(jù)了,24位真彩色數(shù)據(jù)是按按BGR各一字節(jié)循環(huán)排列而成。
2.1.2 代碼實(shí)現(xiàn):將BMP文件解析為RGB格式,在LCD上顯示
讓BMP文件在開發(fā)板的LCD上顯示出來(lái),有幾個(gè)需要注意的點(diǎn):
開發(fā)板LCD上的顯示格式是RGB格式的,而且有多種表示格式:可能用2字節(jié)表示(RGB565格式),可能用3字節(jié)表示(RGB888),而原始的24位真彩色BMP文件則是按BGR格式排列的,需要對(duì)原始的圖像數(shù)據(jù)進(jìn)行轉(zhuǎn)化。
在轉(zhuǎn)化過(guò)程中,LCD上的顯存地址固定是以LCD左上角為首地址,而BMP格式中正向圖像是以圖片的左下角為數(shù)據(jù)首地址的。因此在進(jìn)行數(shù)據(jù)轉(zhuǎn)化時(shí)還需要注意坐標(biāo)的變換。
代碼清單2.1實(shí)現(xiàn)了將24位真彩色的BMP圖像轉(zhuǎn)化為RGB格式
代碼清單2.1 1. /********************************************************************** 2. * 函數(shù)名稱: IsBmp 3. * 功能描述: 判斷該文件是否為BMP文件 4. * 輸入參數(shù): ptFileMap - 內(nèi)含文件信息 5. * 輸出參數(shù): 無(wú) 6. * 返 回 值: 0 - 是BMP格式, -1 -不是BMP格式 7. ***********************************************************************/ 8. int IsBmp(FILE **ppFp, const char *strFileName) 9. { 10. char strCheckHeader[2]; 11. *ppFp= fopen(strFileName, "rb+"); 12. if (*ppFp== NULL) { 13. return -1; 14. } 15. if (fread(strCheckHeader, 1, 2, *ppFp) != 2) 16. return -1; 17. 18. if (strCheckHeader[0] != 0x42 || strCheckHeader[1] != 0x4d) 19. return -1; 20. else 21. return 0; 22. } 23. 24. 25. 26. /********************************************************************** 27. * 函數(shù)名稱: MapFile 28. * 功能描述: 使用mmap函數(shù)映射一個(gè)文件到內(nèi)存,以后就可以直接通過(guò)內(nèi)存來(lái)訪問(wèn)文件 29. * 輸入?yún)?shù): PT_PictureData ptData 內(nèi)含圖像數(shù)據(jù) 30. * 輸出參數(shù): ptData->iFileSize : 文件大小 31. * ptData->pucFileData : 映射內(nèi)存的首地址 32. * 返 回 值: 0 - 成功其他值 - 失敗 33. ***********************************************************************/ 34. int MapFile(PT_PictureData ptData) 35. { 36. int iFd; 37. struct stat tStat; 38. 39. /* 打開文件 */ 40. iFd = fileno(ptData->ptFp); 41. fstat(iFd, &tStat); 42. ptData->iFileSize= tStat.st_size; 43. ptData->pucFileData= (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFd, 0); 44. if (ptData->pucFileData == (unsigned char *)-1) 45. { 46. printf("mmap error!n"); 47. return -1; 48. } 49. return 0; 50. } 51. 52. /********************************************************************** 53. * 函數(shù)名稱: DecodeBmp2Rgb 54. * 功能描述:把BMP文件轉(zhuǎn)化為rgb格式 55. * 輸入?yún)?shù): strFileName - 文件名 56. * ptData - 內(nèi)含圖像信息 57. * 返 回 值: 0 - 成功其他值 - 失敗 58. * -1 - 文件不是BMP格式 59. * -2 - 不支持的bpp 60. * -3 - 圖像緩存區(qū)分配失敗 61. ***********************************************************************/ 62. static int DecodeBmp2Rgb(const char *strFileName, PT_PictureData ptData) { 63. int x,y; 64. int iPos = 0; 65. int iLineWidthAlign; 66. BITMAPFILEHEADER *ptBITMAPFILEHEADER; 67. BITMAPINFOHEADER *ptBITMAPINFOHEADER; 68. unsigned char *aFileHead; 69. unsigned char *pucSrc; 70. unsigned char *pucDest; 71. int iLineBytes; 72. 73. /* 判斷該文件是否為BMP格式 */ 74. if (IsBmp(&ptData->ptFp, strFileName)) 75. return -1; 76. 77. /* 將BMP文件映射到內(nèi)存空間 */ 78. MapFile(ptData); 79. 80. 81. aFileHead = ptData->pucFileData; 82. 83. ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead; 84. ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER)); 85. /* 獲取必要的圖像信息 */ 86. ptData->iWidth = ptBITMAPINFOHEADER->biWidth; 87. ptData->iHeight = ptBITMAPINFOHEADER->biHeight; 88. ptData->iBpp = ptBITMAPINFOHEADER->biBitCount; 89. iLineBytes = ptData->iWidth*ptData->iBpp/8;//一行數(shù)據(jù)的字節(jié)數(shù) 90. ptData->iBmpDataSize= ptData->iHeight * iLineBytes;//整個(gè)BMP圖像的字節(jié)數(shù) 91. /*暫時(shí)只支持24bpp格式*/ 92. if (ptData->iBpp != 24) 93. { 94. printf("iBMPBpp = %dn", ptData->iBpp); 95. printf("sizeof(BITMAPFILEHEADER) = %dn", sizeof(BITMAPFILEHEADER)); 96. return -2; 97. } 98. 99. /* 分配空間 */ 100. ptData->pucBmpData = malloc(ptData->iBmpDataSize); 101. ptData->pucRgbData = malloc(ptData->iBmpDataSize); 102. 103. if (NULL == ptData->pucBmpData||NULL == ptData->pucRgbData) 104. return -2; 105. 106. /* 從bmp文件中讀取圖像信息,24bpp的BMP圖像為BGR格式 */ 107. pucDest = ptData->pucBmpData; 108. iLineWidthAlign = (iLineBytes + 3) & ~0x3; /* 向4取整 */ 109. pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits; 110. 111. pucSrc = pucSrc + (ptData->iHeight - 1) * iLineWidthAlign; 112. 113. /* 對(duì)于bmp文件中的源數(shù)據(jù),是以左下角為原點(diǎn)計(jì)算坐標(biāo)的,因此拷貝數(shù)據(jù)時(shí)需要轉(zhuǎn)換坐標(biāo) */ 114. for (y = 0; y < ptData->iHeight; y++) 115. { 116. memcpy(pucDest, pucSrc, ptData->iWidth*3); 117. pucSrc -= iLineWidthAlign; 118. pucDest += iLineBytes; 119. } 120. 121. 122. /* 將得到的BGR數(shù)據(jù)轉(zhuǎn)化為RGB數(shù)據(jù) */ 123. for (y = 0; y < ptData->iHeight; y++){ 124. for(x = 0;xiWidth*3;x+=3){ 125. ptData->pucRgbData[iPos++] = ptData->pucBmpData[y*ptData->iWidth*3+x+2]; 126. ptData->pucRgbData[iPos++] = ptData->pucBmpData[y*ptData->iWidth*3+x+1]; 127. ptData->pucRgbData[iPos++] = ptData->pucBmpData[y*ptData->iWidth*3+x+0]; 128. } 129. } 130. 131. return 0; 132. 133. }
2.2 JPEG圖像處理
2.2.1 JPEG文件格式和libjpeg編譯
JPEG的后綴名為.jpg的圖像文件。對(duì)于圖像內(nèi)容和信息相同的JPEG文件和BMP文件,JPEG格式的文件要比BMP格式的文件小得多,這是因?yàn)镴PEG文件是經(jīng)過(guò)JPEG壓縮算法后得到的一種文件格式。
相對(duì)于BMP格式的文件,JPEG由于壓縮算法的關(guān)系,其文件解析較為復(fù)雜,我們可以利用Linux系統(tǒng)開源的優(yōu)點(diǎn),使用開源工具對(duì)jpeg文件進(jìn)行格式的解析和轉(zhuǎn)換。
我們可以使用libjpeg庫(kù)來(lái)對(duì)jpeg文件進(jìn)行格式的解析和轉(zhuǎn)換。libjpeg支持X86,ARM等架構(gòu)。libjpeg是開源工具,所以可以在網(wǎng)上免費(fèi)下載。
在使用libjpeg之前,我們先要交叉編譯libjpeg的庫(kù)文件和頭文件并存到開發(fā)板的文件系統(tǒng)中。以下是libjpeg的編譯過(guò)程:
解壓并進(jìn)入文件目錄
tar xzf libjpeg-turbo-1.2.1.tar.gz cd libjpeg-turbo-1.2.1/
交叉編譯
tar xzf libjpeg-turbo-1.2.1.tar.gz ./configure --prefix=/work/projects/libjpeg-turbo-1.2.1/tmp/ --host=arm-linux make make install
將編譯出來(lái)的頭文件和庫(kù)文件拷貝到交叉編譯器的相應(yīng)目錄下
cd /work/projects/libjpeg-turbo-1.2.1/tmp/include cp * /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include cd /work/projects/libjpeg-turbo-1.2.1/tmp/lib cp *so* -d /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
將編譯出來(lái)的頭文件和庫(kù)文件拷貝到開發(fā)板文件系統(tǒng)的相應(yīng)目錄下
cd /work/projects/libjpeg-turbo-1.2.1/tmp/lib cp *.so* /work/nfs_root/fs_mini_mdev_new/lib/ -d
2.2.2 libjpeg接口函數(shù)的解析和使用
libjpeg的使用方法可以參考解壓包中的使用說(shuō)明libjpeg.txt和例程example.c。libjpeg的使用步驟簡(jiǎn)單總結(jié)如下:
1.分配和初始化一個(gè)jpeg_compress_struct結(jié)構(gòu)體
cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo);
2.指定源文件
jpeg_stdio_src(&cinfo, infile);
參數(shù)1是步驟1中分配的jpeg_compress_struct類型的結(jié)構(gòu)體
參數(shù)2是要解析的JPEG文件的文件句柄。
3.獲得jpg信息頭并設(shè)置解壓參數(shù)
jpeg_read_header(&cinfo, TRUE);
當(dāng)調(diào)用完這個(gè)參數(shù)之后,我們就可以通過(guò)cinfo中的image_width,image_height等成員來(lái)獲得圖像的信息了。此外我們還可以設(shè)置cinfo中的scale_num和scale_denom等成員變量來(lái)設(shè)置解壓參數(shù)。
4.啟動(dòng)解壓
jpeg_start_decompress(&cinfo);
調(diào)用這個(gè)函數(shù)后,就可以對(duì)cinfo所指定的源文件進(jìn)行解壓,并將解壓后的數(shù)據(jù)存到cinfo結(jié)構(gòu)體的成員變量中。
5.讀取解壓后數(shù)據(jù)
jpeg_read_scanlines(&cinfo, buffer, 1);
調(diào)用這個(gè)函數(shù)后,可以讀取RGB數(shù)據(jù)到buffer中,參數(shù)3能指定讀取多少行
6.完成讀取
jpeg_finish_decompress(&cinfo);
7.釋放jpeg_compress_struct結(jié)構(gòu)體
jpeg_destroy_decompress(&cinfo);
完成讀取后釋放結(jié)構(gòu)體
2.2.3 使用libjpeg把JPEG文件解析為RGB格式,在LCD上顯示
根據(jù)上節(jié)的解析,利用上述的庫(kù)函數(shù)將JPEG文件解析為RGB格式了。
代碼清單2.2 1. /********************************************************************** 2. * 函數(shù)名稱: IsJpg 3. * 功能描述:判斷是否為Jpg文件 4. * 輸入?yún)?shù): ptData - 內(nèi)含圖像信息 5. strFileName - 文件名 6. * 返 回 值:0 - 不是JPG格式 其他-是JPG格式 7. ***********************************************************************/ 8. static int IsJpg(PT_PictureData ptData, const char *strFileName) 9. { 10. int iRet; 11. 12. jpeg_stdio_src(&ptData->tInfo, ptData->ptFp); 13. 14. /* 用jpeg_read_header獲得jpeg信息*/ 15. iRet = jpeg_read_header(&ptData->tInfo, TRUE); 16. 17. return (iRet == JPEG_HEADER_OK); 18. } 19. 20. /********************************************************************** 21. * 函數(shù)名稱: DecodeJpg2Rgb 22. * 功能描述:把JPG文件解析為RGB888格式 23. * 輸入?yún)?shù): ptData - 內(nèi)含文件信息 24. * strFileName - 文件名 25. * 輸出參數(shù):PT_PictureData->pucRgbData - 內(nèi)含rgb數(shù)據(jù) 26. * 返 回 值:0 - 成功 其他-失敗 27. ***********************************************************************/ 28. static int DecodeJpg2Rgb(const char *strFileName, PT_PictureData ptData){ 29. int iRowSize; 30. unsigned char *pucbuffer; 31. unsigned char *pucHelp;//輔助拷貝變量 32. 33. /* 1.分配和初始化一個(gè)jpeg_compress_struct結(jié)構(gòu)體 */ 34. ptData->tInfo.err = jpeg_std_error(&ptData->tJerr); 35. jpeg_create_decompress(&ptData->tInfo); 36. 37. 38. /* 2.指定源文件*/ 39. if ((ptData->ptFp= fopen(strFileName, "rb")) == NULL) { 40. fprintf(stderr, "can't open %sn", strFileName); 41. return -1; 42. } 43. 44. /* 3.獲得jpg信息頭并設(shè)置解壓參數(shù)并判斷是否為JPEG格式文件 */ 45. if (!IsJpg(ptData, strFileName)) { 46. printf("file is not jpg ...n"); 47. return -1; 48. } 49. 50. 51. 52. /* 默認(rèn)尺寸為原尺寸 */ 53. ptData->tInfo.scale_num = 1; 54. ptData->tInfo.scale_denom = 1; 55. /* 4. 啟動(dòng)解壓:jpeg_start_decompress */ 56. jpeg_start_decompress(&ptData->tInfo); 57. 58. 59. /* 解壓完成后可以通過(guò)tInfo中的成員獲得圖像的某些信息 */ 60. ptData->iWidth= ptData->tInfo.output_width; 61. ptData->iHeight = ptData->tInfo.output_height; 62. ptData->iBpp = ptData->tInfo.output_components*8; 63. /* 計(jì)算一行的數(shù)據(jù)長(zhǎng)度 */ 64. iRowSize = ptData->iWidth * ptData->tInfo.output_components; 65. pucbuffer = malloc(iRowSize); 66. ptData->iRgbSize= iRowSize * ptData->iHeight; 67. ptData->pucRgbData = malloc(ptData->iRgbSize); 68. 69. /* pucHelp指向ptData->pucRgbData首地址 */ 70. pucHelp = ptData->pucRgbData; 71. /* 5.循環(huán)調(diào)用jpeg_read_scanlines來(lái)一行一行地獲得解壓的數(shù)據(jù) */ 72. while (ptData->tInfo.output_scanline < ptData->tInfo.output_height) 73. { 74. /* 調(diào)用jpeg_read_scanlines得到的時(shí)候會(huì)存到pucbuffer中 */ 75. jpeg_read_scanlines(&ptData->tInfo, &pucbuffer, 1); 76. /* 將數(shù)據(jù)一行行讀到緩沖區(qū)中 */ 77. memcpy(pucHelp,pucbuffer,iRowSize); 78. pucHelp += iRowSize; 79. } 80. free(pucbuffer); 81. /* 6.完成讀取 */ 82. jpeg_finish_decompress(&ptData->tInfo); 83. /* 7.釋放jpeg_compress_struct結(jié)構(gòu)體 */ 84. jpeg_destroy_decompress(&ptData->tInfo); 85. return 0; 86. }
2.3 PNG圖像處理
2.3.1 PNG文件格式和libpng編譯
跟JPEG文件格式一樣,PNG也是一種使用了算法壓縮后的圖像格式,與JPEG不同,PNG使用從LZ77派生的無(wú)損數(shù)據(jù)壓縮算法。對(duì)于PNG文件格式,也有相應(yīng)的開源工具libpng。
libpng庫(kù)可從官網(wǎng)上下載最新的源代碼:
http://www.libpng.org/pub/png/libpng.html
在使用libpng之前,我們先要交叉編譯libpng的庫(kù)文件和頭文件并存到開發(fā)板的文件系統(tǒng)中。以下是libpng的編譯過(guò)程:
解壓并進(jìn)入文件目錄
tar xzf libpng-1.6.37.tar.gz cd libpng-1.6.37/
交叉編譯
./configure --prefix=/work/projects/libpng-1.6.37/tmp/ --host=arm-linux make make install
將編譯出來(lái)的頭文件和庫(kù)文件拷貝到交叉編譯器的相應(yīng)目錄下
cd /work/projects/libpng-1.6.37/tmp/include cp * /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include cd /work/projects/libpng-1.6.37/tmp/lib cp *so* -d /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
將編譯出來(lái)的頭文件和庫(kù)文件拷貝到開發(fā)板文件系統(tǒng)的相應(yīng)目錄下
cd /work/projects/libpng-1.6.37/tmp/lib cp *.so* /work/nfs_root/fs_mini_mdev_new/lib/ -d
2.3.2 libpng接口函數(shù)的解析和使用
libpng的使用方法可以參考解壓包中的使用說(shuō)明libpng-manual.txt和例程example.c。libjpeg的使用步驟簡(jiǎn)單總結(jié)如下:
分配和初始化兩個(gè)與libpng相關(guān)的結(jié)構(gòu)體png_ptr,info_ptr
A. png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
參數(shù)2,3,4分別是用戶自定義的錯(cuò)誤處理函數(shù),若無(wú),則填NULL。
B. info_ptr = png_create_info_struct(png_ptr);
設(shè)置錯(cuò)誤返回點(diǎn)
setjmp(png_jmpbuf(png_ptr));
當(dāng)出現(xiàn)錯(cuò)誤時(shí),libpng將會(huì)自動(dòng)調(diào)用返回到這個(gè)點(diǎn)。在這個(gè)點(diǎn)我們可以進(jìn)行一些清理工作。如果在調(diào)用png_create_read_struct時(shí)沒(méi)有設(shè)置自定義的錯(cuò)誤處理函數(shù),這一步是必須要做的。
指定源文件
png_init_io(png_ptr, fp);
參數(shù)1是步驟1中分配的png_ptr結(jié)構(gòu)體,參數(shù)2是需要解析的PNG文件的文件句柄。
獲取PNG圖像的信息
A. 解析圖片數(shù)據(jù)信息
png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
該函數(shù)會(huì)把所有的圖片數(shù)據(jù)解碼到info_ptr數(shù)據(jù)結(jié)構(gòu)中。至于轉(zhuǎn)化為什么格式,由參數(shù)png_transforms決定,它是一個(gè)整型參數(shù),可以使用libpng庫(kù)中定義的宏進(jìn)行傳參。這個(gè)參數(shù)相關(guān)的宏有很多,具體的可以參考庫(kù)中的相關(guān)文件的解析。
B.查詢圖像信息
此外,我們還可以通過(guò)png_get_image_width,png_get_image_height,png_get_color_type等函數(shù)獲得png圖像的寬度,高度,顏色類型等信息,更多的圖像信息獲取函數(shù)可以在文件pngget.c中找到。
將info_ptr中的圖像數(shù)據(jù)讀取出來(lái)
有兩種讀取PNG圖像信息的方法:
A. 一次性把所有的數(shù)據(jù)讀入內(nèi)存
png_read_image(png_ptr, row_pointers);
參數(shù)1是步驟1中分配的png_ptr,參數(shù)2是存放圖片數(shù)據(jù)的指針。
B. 也可以逐行讀取
row_pointers = png_get_rows(png_ptr, info_ptr);
參數(shù)1和參數(shù)2分別是步驟1中分配的png_ptr, info_ptr,返回值是每行數(shù)據(jù)的首地址。
參數(shù)1是步驟1中分配的png_ptr,參數(shù)2是存放圖片數(shù)據(jù)的指針。
銷毀內(nèi)存
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
2.3.3 使用libpng把png文件轉(zhuǎn)為rgb格式,在LCD上顯示
代碼清單2.3 1. /********************************************************************** 2. * 函數(shù)名稱: IsnotPng 3. * 功能描述:判斷是否為PNG文件 4. * 輸入?yún)?shù): ppFp - 文件句柄指針 5. strFileName - 文件名 6. * 返 回 值:0 - 是PNG格式 其他-不是PNG格式 7. ***********************************************************************/ 8. int IsnotPng(FILE **ppFp, const char *strFileName) 9. { 10. char strCheckHeader[8]; 11. *ppFp= fopen(strFileName, "rb"); 12. if (*ppFp== NULL) { 13. return -1; 14. } 15. /* 讀取PNG文件前8個(gè)字節(jié),使用庫(kù)函數(shù)png_sig_cmp即可判斷是否為PNG格式 */ 16. if (fread(strCheckHeader, 1, 8, *ppFp) != 8) 17. return -1; 18. return png_sig_cmp(strCheckHeader, 0, 8); 19. 20. } 21. 22. /********************************************************************** 23. * 函數(shù)名稱: DecodePng2Rgb 24. * 功能描述:把PNG文件解析為RGB888格式 25. * 輸入?yún)?shù): ptData - 內(nèi)含文件信息 26. * strFileName - 文件名 27. * 輸出參數(shù):PT_PictureData->pucRgbData - 內(nèi)含rgb數(shù)據(jù) 28. * 返 回 值:0 - 成功 其他-失敗 29. ***********************************************************************/ 30. static int DecodePng2Rgb(const char *strFileName, PT_PictureData ptData) 31. { 32. int i, j; 33. int iPos = 0; 34. png_bytepp pucPngData; 35. /* 0.判斷該文件是否為PNG格式 */ 36. if (IsnotPng(&ptData->ptFp, strFileName)) { 37. printf("file is not png ...n"); 38. return -1; 39. } 40. 41. /* 1.分配和初始化兩個(gè)與libpng相關(guān)的結(jié)構(gòu)體png_ptr,info_ptr */ 42. ptData->ptPngStrPoint = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 43. ptData->ptPngInfoPoint= png_create_info_struct(ptData->ptPngStrPoint); 44. 45. /* 2.設(shè)置錯(cuò)誤的返回點(diǎn) */ 46. setjmp(png_jmpbuf(ptData->ptPngStrPoint)); 47. rewind(ptData->ptFp); //等價(jià)fseek(fp, 0, SEEK_SET); 48. 49. /* 3.指定源文件 */ 50. png_init_io(ptData->ptPngStrPoint, ptData->ptFp); 51. 52. /* 4.獲取PNG圖像數(shù)據(jù)信息和通道數(shù),寬度,高度等 53. * 使用PNG_TRANSFORM_EXPAND宏做參數(shù)的作用是根據(jù)通道數(shù)的不同, 54. * 將PNG圖像轉(zhuǎn)換為BGR888或ABGR8888格式*/ 55. png_read_png(ptData->ptPngStrPoint, ptData->ptPngInfoPoint, PNG_TRANSFORM_EXPAND, 0); 56. ptData->iChannels = png_get_channels(ptData->ptPngStrPoint, ptData->ptPngInfoPoint); 57. ptData->iWidth = png_get_image_width(ptData->ptPngStrPoint, ptData->ptPngInfoPoint); 58. ptData->iHeight = png_get_image_height(ptData->ptPngStrPoint, ptData->ptPngInfoPoint); 59. 60. 61. /* 5.將info_ptr中的圖像數(shù)據(jù)讀取出來(lái) */ 62. pucPngData = png_get_rows(ptData->ptPngStrPoint, ptData->ptPngInfoPoint); //也可以分別每一行獲取png_get_rowbytes(); 63. if (ptData->iChannels == 4) { //判斷是24位還是32位 64. ptData->iRawSize= ptData->iWidth * ptData->iHeight*4; //申請(qǐng)內(nèi)存先計(jì)算空間 65. ptData->pucRawData= (unsigned char*)malloc(ptData->iRawSize); 66. if (NULL == ptData->pucRawData) { 67. printf("malloc rgba faile ...n"); 68. png_destroy_read_struct(&ptData->ptPngStrPoint, &ptData->ptPngInfoPoint, 0); 69. fclose(ptData->ptFp); 70. return -1; 71. } 72. /* 從pucPngData里讀出實(shí)際的RGBA數(shù)據(jù)出來(lái) 73. * 源數(shù)據(jù)為ABGR格式*/ 74. for (i = 0; i < ptData->iHeight; i++) 75. for (j = 0; j < ptData->iWidth * 4; j += 4) { 76. ptData->pucRawData[iPos++] = pucPngData[i][j + 3]; 77. ptData->pucRawData[iPos++] = pucPngData[i][j + 2]; 78. ptData->pucRawData[iPos++] = pucPngData[i][j + 1]; 79. ptData->pucRawData[iPos++] = pucPngData[i][j + 0]; 80. } 81. 82. /* 將得到的RGBA轉(zhuǎn)換為RGB888格式 */ 83. if(RgbaToRgb(ptData)!=0) 84. return -1; 85. 86. } 87. else if (ptData->iChannels == 3 ) { //判斷顏色深度是24位還是32位 88. ptData->iRgbSize= ptData->iWidth * ptData->iHeight*3; //申請(qǐng)內(nèi)存先計(jì)算空間 89. ptData->pucRgbData = (unsigned char*)malloc(ptData->iRgbSize); 90. if (NULL == ptData->pucRgbData) { 91. printf("malloc rgba faile ...n"); 92. png_destroy_read_struct(&ptData->ptPngStrPoint, &ptData->ptPngInfoPoint, 0); 93. fclose(ptData->ptFp); 94. return -1; 95. } 96. /* 從pucPngData里讀出實(shí)際的RGB數(shù)據(jù) 97. * 源數(shù)據(jù)為BGR格式*/ 98. for (i = 0; i < ptData->iHeight; i ++) { 99. for (j = 0; j < ptData->iWidth*3; j += 3) { 100. ptData->pucRgbData[iPos++] = pucPngData[i][j+2]; 101. ptData->pucRgbData[iPos++] = pucPngData[i][j+1]; 102. ptData->pucRgbData[iPos++] = pucPngData[i][j+0]; 103. } 104. } 105. ptData->iBpp = 24;//轉(zhuǎn)化之后的格式為RGB888格式 106. } 107. else return -1; 108. 109. 110. /* 6:銷毀內(nèi)存 */ 111. png_destroy_read_struct(&ptData->ptPngStrPoint, &ptData->ptPngInfoPoint, 0); 112. fclose(ptData->ptFp); 113. 114. 115. return 0; 116. }
2.4 圖像調(diào)整
2.4.1 圖像的縮放
2.4.1.1 圖像縮放算法淺析
圖像縮放算法有很多種,這里參考網(wǎng)友"lantianyu520"所著的"圖像縮放算法"。
原理淺析
要理解這個(gè)圖像縮放算法的原理,最重要的是需要理解:對(duì)于圖像上的每一個(gè)像素點(diǎn),它縮放前后,相對(duì)于整個(gè)圖像的比例應(yīng)該是一樣的。
比如:
以一個(gè)長(zhǎng)度和寬度分別為200,100的長(zhǎng)方形為例,將其放大兩倍,那么縮放后的長(zhǎng)度和寬度為400,200。
為方便理解,我們建立一個(gè)笛卡爾坐標(biāo)系,把這個(gè)長(zhǎng)方形左下角的頂點(diǎn)放到坐標(biāo)(0,0)位置,四個(gè)點(diǎn)的坐標(biāo)分別為:(0,0),(0,100),(200,0),(200,100)。
假設(shè)此時(shí)對(duì)長(zhǎng)方形中的坐標(biāo)點(diǎn)(40,50),它的x坐標(biāo)相對(duì)于長(zhǎng)的比值是40/200=0.2,y坐標(biāo)相對(duì)于寬的比值是50/100=0.5,那么該點(diǎn)的變換后的坐標(biāo)Dx,Dy則應(yīng)滿足:Dx/400 = 5;Dy/200 = 0.5,這樣,縮放后的坐標(biāo)就可以算出來(lái)了。
根據(jù)上面的分析,設(shè)縮放前的像素點(diǎn)坐標(biāo)為(Sx,Sy),對(duì)應(yīng)的縮放后的像素點(diǎn)坐標(biāo)為(Dx,Dy),縮放前的圖像長(zhǎng)寬分別為Sw,Sh,縮放后的圖像長(zhǎng)寬分別為Dw,Dh,則有:
Sx/Dx = Sw/Dw,Sy/Dy = Sh/Dh
故有Sx = Dx * Sw/Dw,Sy = Dy * Sh/Dh,
2.4.1.2源碼編寫:圖像縮放算法
有了這個(gè)上面兩條等式后,圖像縮放算法的代碼就好理解了。
下面的函數(shù)實(shí)現(xiàn)了基于上述原理實(shí)現(xiàn)的圖像縮放算法:
代碼清單2.4 1. /********************************************************************** 2. * 函數(shù)名稱: PicZoom 3. * 功能描述: 近鄰取樣插值方法縮放圖片 4. * 注意該函數(shù)會(huì)分配內(nèi)存來(lái)存放縮放后的圖片,用完后要用free函數(shù)釋放掉 5. * "近鄰取樣插值"的原理請(qǐng)參考網(wǎng)友"lantianyu520"所著的"圖像縮放算法" 6. * 輸入?yún)?shù): ptPicData - 內(nèi)含縮放前后的圖像數(shù)據(jù) 7. * fSize - 縮放倍數(shù) 8. * 輸出參數(shù): ptPicData->pucZoomData,內(nèi)含縮放后的數(shù)據(jù) 9. * 返 回 值: 0 - 成功, 其他值 - 失敗 10. ***********************************************************************/ 11. int PicZoom(PT_PictureData ptPicData,float fSize) 12. { 13. ptPicData->iZoomWidth = ptPicData->iWidth * fSize; 14. ptPicData->iZoomHeight= ptPicData->iHeight* fSize; 15. unsigned long* pdwSrcXTable; 16. unsigned long x; 17. unsigned long y; 18. unsigned long dwSrcY; 19. unsigned char *pucDest; 20. unsigned char *pucSrc; 21. unsigned long dwPixelBytes = ptPicData->iBpp/8; 22. ptPicData->pucZoomData= malloc(sizeof(unsigned char) * ptPicData->iZoomWidth*ptPicData->iZoomHeight*ptPicData->iBpp/8); 23. pdwSrcXTable = malloc(sizeof(unsigned long) * ptPicData->iZoomWidth); 24. if (NULL == pdwSrcXTable){ 25. printf("malloc error!n"); 26. return -1; 27. } 28. 29. /* 這幾個(gè)for循環(huán)的本質(zhì)是Sx = Dx * Sw/Dw,Sy = Dy * Sh/Dh*/ 30. for (x = 0; x < ptPicData->iZoomWidth; x++){//生成表 pdwSrcXTable 31. /* 第一個(gè)for循環(huán)對(duì)應(yīng)x方向的坐標(biāo) 32. * pdwSrcXTable[x] 對(duì)應(yīng)Sx, 33. * x 對(duì)應(yīng)Dx, 34. * ptPicData->iWidth 對(duì)應(yīng)Sw 35. * ptPicData->iZoomWidth 對(duì)應(yīng) Dw*/ 36. pdwSrcXTable[x]=(x*ptPicData->iWidth/ptPicData->iZoomWidth); 37. } 38. 39. for (y = 0; y < ptPicData->iZoomHeight; y++){ 40. /* 第2個(gè)循環(huán)對(duì)應(yīng)y方向的坐標(biāo) 41. * dwSrcY 對(duì)應(yīng)Sy, 42. * y 對(duì)應(yīng)Dy, 43. * ptPicData->iHeight 對(duì)應(yīng)Sh 44. * ptPicData->iZoomHeight 對(duì)應(yīng) Dh*/ 45. dwSrcY = (y * ptPicData->iHeight / ptPicData->iZoomHeight); 46. /* 根據(jù)這些可算得各像素點(diǎn)的RGB數(shù)據(jù)存放的地址 */ 47. pucDest = ptPicData->pucZoomData + y*ptPicData->iZoomWidth*3; 48. pucSrc = ptPicData->pucRgbData + dwSrcY*ptPicData->iWidth*3; 49. 50. /* 最后拷貝數(shù)據(jù) */ 51. for (x = 0; x iZoomWidth; x++){ 52. memcpy(pucDest+x*dwPixelBytes, pucSrc+pdwSrcXTable[x]*dwPixelBytes, dwPixelBytes); 53. } 54. } 55. 56. free(pdwSrcXTable); 57. return 0; 58. }
2.4.2 圖像的旋轉(zhuǎn)
2.4.2.1 圖像旋轉(zhuǎn)算法淺析
這里的圖像旋轉(zhuǎn)算法原理參考網(wǎng)友"落葉的思維"所著的"圖像旋轉(zhuǎn)算法與實(shí)現(xiàn)"
原理淺析
這個(gè)旋轉(zhuǎn)算法的原理的關(guān)鍵點(diǎn)有兩個(gè):
原圖像是以圖像的左下角為原點(diǎn)建立笛卡爾坐標(biāo)系的,而旋轉(zhuǎn)一般是以圖像的中心作為旋轉(zhuǎn)點(diǎn)旋轉(zhuǎn)的。
因此為了便于轉(zhuǎn)換,我們先約定兩個(gè)坐標(biāo)系,一個(gè)是以圖像左下角為原點(diǎn)建立的坐標(biāo)系,稱為坐標(biāo)系A(chǔ),這也是原圖像的坐標(biāo)系。一個(gè)是以圖像中心為原點(diǎn)建立的坐標(biāo)系,稱為坐標(biāo)系B。
由此,可以知道這個(gè)旋轉(zhuǎn)算法的步驟:先將坐標(biāo)系A(chǔ)下的坐標(biāo)轉(zhuǎn)換為坐標(biāo)系B下的坐標(biāo),然后在坐標(biāo)系B下進(jìn)行圖像的旋轉(zhuǎn)。
在坐標(biāo)系B下,我們假設(shè)點(diǎn)(x0,y0)距離原點(diǎn)的距離為r,點(diǎn)與原點(diǎn)之間的連線與x軸的夾角為b,旋轉(zhuǎn)的角度為a,旋轉(zhuǎn)后的點(diǎn)為(x1,y1), 如下圖所示。
那么有以下結(jié)論:
x0=rcosb;y0=rsinb
x1 = rcos(b-a) = rcosbcosa+rsinbsina=x0cosa+y0sina;
y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa;
最后,由于我們顯示圖像的RGB數(shù)據(jù)還是要在坐標(biāo)系A(chǔ)下獲取的,我們最后只需要將坐標(biāo)系B下的x1,y1轉(zhuǎn)換回坐標(biāo)系A(chǔ)下的坐標(biāo)就可以了。
旋轉(zhuǎn)后的圖像的長(zhǎng)和寬會(huì)發(fā)生變化,因此要計(jì)算新圖像的長(zhǎng)和寬。
由幾何關(guān)系可知,新圖像的長(zhǎng)和寬分別是旋轉(zhuǎn)后,對(duì)角坐標(biāo)相見后的最大值
2.4.2.2 源碼編寫:圖像旋轉(zhuǎn)算法
代碼清單2.5 1. #define PI 3.1415926535 2. //角度到弧度轉(zhuǎn)化 3. #define RADIAN(angle) ((angle)*PI/180.0) 4. 5. 6. 7. 8. 9. typedef struct ConcernCoor { 10. int iLTx;// left top x 11. int iLTy;//left top y 12. int iLBx;//left bottom x 13. int iLBy;//left bottom y 14. int iRTx;//right top x 15. int iRTy;//right top y 16. int iRBx;// right bottom x 17. int iRBy;// right bottom y 18. }T_ConcernCoor, *PT_ConcernCoor; 19. 20. 21. /********************************************************************** 22. * 函數(shù)名稱: max 23. * 功能描述:比較兩個(gè)參數(shù),返回較大值 24. * 輸入?yún)?shù):x,y均為int型 25. * 輸出參數(shù): 無(wú) 26. * 返 回 值: x,y中的較大值 27. ***********************************************************************/ 28. static int max(int x,int y){ 29. return x>y?x:y; 30. } 31. /********************************************************************** 32. * 函數(shù)名稱: PicRotate 33. * 功能描述: 旋轉(zhuǎn)圖片 34. * 注意該函數(shù)會(huì)分配內(nèi)存來(lái)存放縮放后的圖片,用完后要用free函數(shù)釋放掉 35. * 參考網(wǎng)友"落葉的思維"所著的"圖像旋轉(zhuǎn)算法與實(shí)現(xiàn)" 36. * 輸入?yún)?shù): ptPicData - 內(nèi)含圖片的象素?cái)?shù)據(jù) 37. * fAngle - 旋轉(zhuǎn)角度,0<=angle<=360 38. * 輸出參數(shù): ptPicData->pucRotateData,內(nèi)含旋轉(zhuǎn)后的rgb數(shù)據(jù) 39. * 返 回 值: 0 - 成功, 其他值 - 失敗 40. ***********************************************************************/ 41. int PicRotate(PT_PictureData ptPicData,float fAngle) 42. { 43. int i ,j; 44. T_ConcernCoor tConCor,tRonCor; 45. //原圖像每一行去除偏移量的字節(jié)數(shù) 46. //int iSrcLineSize = bitCount * srcW / 8; 47. int iSrcLineSize = ptPicData->iBpp* ptPicData->iZoomWidth / 8; 48. int iDesLineSize; 49. int iX;//旋轉(zhuǎn)后的x坐標(biāo) 50. int iY; //旋轉(zhuǎn)后的y坐標(biāo) 51. 52. /* 將坐標(biāo)系A(chǔ)下的坐標(biāo)轉(zhuǎn)換為坐標(biāo)系B下的坐標(biāo), 53. * 用于計(jì)算旋轉(zhuǎn)后的圖像的寬和高 54. * tConCor用于存放坐標(biāo)系B下旋轉(zhuǎn)前的坐標(biāo) 55. * tRonCor用于存放坐標(biāo)系B下旋轉(zhuǎn)后的坐標(biāo)*/ 56. tConCor.iLTx = -ptPicData->iZoomWidth/2; tConCor.iLTy = ptPicData->iZoomHeight/2; 57. tConCor.iRTx = ptPicData->iZoomWidth/2; tConCor.iRTy = ptPicData->iZoomHeight/2; 58. tConCor.iLBx = -ptPicData->iZoomWidth/2;tConCor.iLBy = -ptPicData->iZoomHeight/2; 59. tConCor.iRBx = ptPicData->iZoomWidth/2;tConCor.iRBy = -ptPicData->iZoomHeight/2; 60. 61. 62. /* 計(jì)算坐標(biāo)系B下旋轉(zhuǎn)后的坐標(biāo) */ 63. double sina = sin(RADIAN(fAngle)); 64. double cosa = cos(RADIAN(fAngle)); 65. tRonCor.iLTx =tConCor.iLTx * cosa + tConCor.iLTy * sina; 66. tRonCor.iLTy = -tConCor.iLTx * sina + tConCor.iLTy * cosa; 67. tRonCor.iRTx =tConCor.iRTx * cosa + tConCor.iRTy * sina; 68. tRonCor.iRTy = -tConCor.iRTx * sina + tConCor.iRTy * cosa; 69. tRonCor.iLBx = tConCor.iLBx * cosa + tConCor.iLBy * sina; 70. tRonCor.iLBy = -tConCor.iLBx * sina + tConCor.iLBy * cosa; 71. tRonCor.iRBx = tConCor.iRBx * cosa + tConCor.iRBy * sina; 72. tRonCor.iRBy = -tConCor.iRBx * sina + tConCor.iRBy * cosa; 73. 74. 75. /* 計(jì)算旋轉(zhuǎn)后圖像寬和高 */ 76. ptPicData->iRotateWidth = max(abs(tRonCor.iRBx - tRonCor.iLTx),abs(tRonCor.iRTx - tRonCor.iLBx)); 77. ptPicData->iRotateHeight = max(abs(tRonCor.iRBy - tRonCor.iLTy),abs(tRonCor.iRTy - tRonCor.iLBy)); 78. 79. /* 像素信息要保證3字節(jié)對(duì)齊,否則數(shù)據(jù)有可能出錯(cuò)*/ 80. iDesLineSize = ((ptPicData->iRotateWidth* ptPicData->iBpp+ 23) / 24) * 3 ; 81. /* 分配旋轉(zhuǎn)后的空間,注意這里要用旋轉(zhuǎn)后的寬和高 */ 82. ptPicData->pucRotateData = malloc(iDesLineSize * ptPicData->iRotateHeight); 83. if(NULL == ptPicData->pucRotateData){ 84. printf("malloc errorn"); 85. return -1; 86. } 87. 88. /* 通過(guò)新圖像的坐標(biāo),計(jì)算對(duì)應(yīng)的原圖像的坐標(biāo)* 89. * i,j坐標(biāo)就是對(duì)應(yīng)的坐標(biāo)系B下的x1,y1*/ 90. for (i = 0; i < ptPicData->iRotateHeight; i++){ 91. for (j = 0; j < ptPicData->iRotateWidth; j++){ 92. /* 坐標(biāo)系B下的x,y1坐標(biāo),經(jīng)過(guò)逆運(yùn)算轉(zhuǎn)換得到iX,iY,這兩個(gè)值對(duì)應(yīng)x0,y0 */ 93. iX = (j - ptPicData->iRotateWidth / 2)*cos(RADIAN(360 - fAngle)) + (-i + ptPicData->iRotateHeight / 2)*sin(RADIAN(360 - fAngle)); 94. iY = -(j - ptPicData->iRotateWidth / 2)*sin(RADIAN(360 - fAngle)) + (-i + ptPicData->iRotateHeight / 2)*cos(RADIAN(360 - fAngle)); 95. /*如果這個(gè)坐標(biāo)不在原圖像內(nèi),則不賦值*/ 96. if (iX > ptPicData->iZoomWidth / 2 || iX < -ptPicData->iZoomWidth / 2 || iY > ptPicData->iZoomHeight / 2 || iY < -ptPicData->iZoomHeight / 2){ 97. continue; 98. } 99. /* 再將坐標(biāo)系B下的x0,y0坐標(biāo),轉(zhuǎn)換為坐標(biāo)系A(chǔ)下的坐標(biāo) */ 100. int iXN = iX + ptPicData->iZoomWidth / 2; 101. int iYN = abs(iY - ptPicData->iZoomHeight / 2); 102. /* 值拷貝*/ 103. memcpy(&ptPicData->pucRotateData[i * iDesLineSize + j * 3],&ptPicData->pucZoomData[iYN * iSrcLineSize + iXN * 3],3); 104. } 105. } 106. return 0; 107. } 審核編輯 黃昊宇
-
Linux
+關(guān)注
關(guān)注
87文章
11304瀏覽量
209503
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論