• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            唐吉訶德

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              5 Posts :: 75 Stories :: 3 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(2)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            您可以到www.ijg.org網站下載libjpeg的源碼, IJG JPEG Library就是jpeg壓縮庫,是以源碼的形式提供給軟件開發人員的,當然在軟件包里也有編譯好的庫文件,我們這里就只用到其中的libjpeg.lib,jconfig.h,jmorecfg.h,jpeglib.h這幾個文件,下面我就介紹一下怎樣在自己的程序里嵌入圖像壓縮功能。

              一、建立編譯環境

              所謂建立編譯環境,其實非常簡單,就是把上面提到的4個文件拷貝到你的項目文件夾下,把libjpeg.lib添加到你的項目中,然后在你完成壓縮功能的那個文件里加入#include "jpeglib.h",需要注意的是,libjpeg.lib是用c語言開發的,如果要用在你的C++程序里,需要用到extern "C",如下:

            // TestLibjpeg.cpp : Defines the entry point for the console application.
            //

            #include "stdafx.h"
            #include "memory.h"
            extern "C" {
             #include "jpeglib.h"
            }

              二、壓縮步驟

              1、申請并初始化jpeg壓縮對象,同時要指定錯誤處理器

             struct jpeg_compress_struct jcs;

             // 聲明錯誤處理器,并賦值給jcs.err域
              struct jpeg_error_mgr jem;
              jcs.err = jpeg_std_error(&jem);

              jpeg_create_compress(&jcs);

              2、指定壓縮后的圖像所存放的目標文件,注意,目標文件應以二進制模式打開

             f=fopen("03.jpg","wb");
              if (f==NULL)
              {
                delete [] data;
                delete [] pDataConv;
                return 0;
              }
              jpeg_stdio_dest(&jcs, f);

              3、設置壓縮參數,主要參數有圖像寬、高、色彩通道數(1:索引圖像,3:其他),色彩空間(JCS_GRAYSCALE表示灰度圖,JCS_RGB表示彩色圖像),壓縮質量等,如下:

              jcs.image_width = nWidth;    // 為圖的寬和高,單位為像素
              jcs.image_height = nHeight;
              jcs.input_components = 1;   // 在此為1,表示灰度圖, 如果是彩色位圖,則為3
              jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度圖,JCS_RGB表示彩色圖像

              jpeg_set_defaults(&jcs);
             jpeg_set_quality (&jcs, 80, true);

            需要注意的是,jpeg_set_defaults函數一定要等設置好圖像寬、高、色彩通道數計色彩空間四個參數后才能調用,因為這個函數要用到這四個值,調用jpeg_set_defaults函數后,jpeglib庫采用默認的設置對圖像進行壓縮,如果需要改變設置,如壓縮質量,調用這個函數后,可以調用其它設置函數,如jpeg_set_quality函數。其實圖像壓縮時有好多參數可以設置,但大部分我們都用不著設置,只需調用jpeg_set_defaults函數值為默認值即可。

              4、上面的工作準備完成后,就可以壓縮了,壓縮過程非常簡單,首先調用jpeg_start_compress,然后可以對每一行進行壓縮,也可以對若干行進行壓縮,甚至可以對整個的圖像進行一次壓縮,壓縮完成后,記得要調用jpeg_finish_compress函數,如下:

              jpeg_start_compress(&jcs, TRUE);

              JSAMPROW row_pointer[1];   // 一行位圖
              int row_stride;      // 每一行的字節數

              row_stride = jcs.image_width;  // 如果不是索引圖,此處需要乘以3

              // 對每一行進行壓縮
              while (jcs.next_scanline < jcs.image_height) {
                   row_pointer[0] = & pDataConv[jcs.next_scanline * row_stride];
                   jpeg_write_scanlines(&jcs, row_pointer, 1);
              }

              jpeg_finish_compress(&jcs);

              5、最后就是釋放壓縮工作過程中所申請的資源了,主要就是jpeg壓縮對象,由于在本例中我是直接用的局部變量,所以只需調用jpeg_destroy_compress這個函數即可,如下:

             jpeg_destroy_compress(&jcs);

              三、解壓縮步驟
              解壓縮步驟與壓縮步驟非常相似,只是解壓縮對象為jpeg_decompress_struct類型,步驟如下:
              1、聲明并初始化解壓縮對象,同時制定錯誤信息管理器
             struct jpeg_decompress_struct cinfo;
             struct jpeg_error_mgr jerr;

             cinfo.err = jpeg_std_error(&jerr);
             jpeg_create_decompress(&cinfo);
              2、打開jpg圖像文件,并指定為解壓縮對象的源文件
             FILE *f = fopen(strSourceFileName,"rb");
             if (f==NULL)
             {
              printf("Open file error!\n");
              return;
             }
             //
             jpeg_stdio_src(&cinfo, f);
              3、讀取圖像信息
             jpeg_read_header(&cinfo, TRUE);
              4、根據圖像信息申請一個圖像緩沖區
             data = new BYTE cinfo.image_width*cinfo.image_height*cinfo.num_components];
              5、開始解壓縮
             jpeg_start_decompress(&cinfo);

             JSAMPROW row_pointer[1];
             while (cinfo.output_scanline < cinfo.output_height)
             {
              row_pointer[0] = &data[(cinfo.output_height - cinfo.output_scanline-1)*cinfo.image_width*cinfo.num_components];
              jpeg_read_scanlines(&cinfo,row_pointer ,
                 1);
             }
             jpeg_finish_decompress(&cinfo);
              6、釋放資源
             jpeg_destroy_decompress(&cinfo);

             fclose(f);

              好了,利用IJG JPEG Library進行圖像壓縮就介紹到這里,希望對大家有所幫助,實例代碼已經實現了圖像的壓縮和解壓縮的全部功能

            Embedded VC

            Jpeg圖像處理程序和代碼(使用Indepedent JPEG Group的JpegLib)

            用Independent JPEG Group發行的JpegLib進行Jpeg圖像的讀取與保存。
                    這里只加了一個簡單的處理示例——負片。其他的處理可以用與這個類似的方法,有了處理的算法對像素數據進行操作。或者加上鼠標事件的處理來完成繪畫功能等等,這里主要是對JPEG文件進行操作的部分。
                    注意:程序中的CTScreenBuffer并未使用,原因是使用它加載后有段內存沒有釋放,加上BMP數據本來就比較好處理,所以自己寫一段,將BMP數據加上頭信息就可以CreateDIBSection了。
                    保存的默認質量Q=85,大家在使用時可以按照要求改變。

            詳細的使用方法以及JpegLib庫


            MacintoshM 2006-05-14, 11:38
            詳細的使用方法:

            1.系統需求
              Microsoft eMbedded Visual C++ 4.0 + Pocket PC 2003 SDK
              Pocket PC的JpegLib庫(在本帖的附件中)
            2.背景
              Jpeg庫的由以下兩個文件配置:jconfig.h和jmorecfg.h。一般使用時是不需要改變jmorecfg.h的,但這樣可能在Pocket PC中運行時遇到問題,所以這里還是對jmorecfg.h進行了修改。下面將討論這個修改,以使這個庫在Pocket PC上正常使用。不過這里能夠下載的附件已經做好了這個修改。

            3.將JpegLib引入Pocket PC
              jmorecfg.h文件含有與Embedded Visual Studio沖突的定義.需要做以下修改:

            (1)代碼:

            #ifndef XMD_H                       
            typedef long INT32;
            #endif


            改為:

            #if !defined(XMD_H) && !defined(_BASETSD_H_)
            typedef long INT32;
            #endif


            (2)代碼:

            #ifdef NEED_FAR_POINTERS
            #define FAR  far
            #else
            #define FAR
            #endif


            用下面的ifdef代替

            #ifndef FAR
            ....
            #endif

            4.使用JpegLib加載Jpeg圖片
              在前面的附件的程序中,已經有這個程序的框架,這里不再贅述。只講主要的部分。
              (1)加載Jpeg圖片的函數:
              void CImageView::LoadImage(const CString &strFileName)
            {
                    FILE * pFile;
                    struct jpeg_error_mgr jerr;
                    struct jpeg_decompress_struct cinfo;
                    int i,start;
                    start=0;
                   
                    if ((pFile = _tfopen(strFileName, _T("rb")) == NULL) {
                            CString strError;
                            strError.Format(_T("無法打開文件 '%s'", strFileName);
                            AfxMessageBox(strError);
                    }
                   
                    cinfo.err = jpeg_std_error(&jerr);
                    jpeg_create_decompress(&cinfo);
                    jpeg_stdio_src(&cinfo, pFile);
                    jpeg_read_header(&cinfo, TRUE);
                    jpeg_start_decompress(&cinfo);
                    nRowSize = cinfo.output_width * cinfo.output_components;
                    Width=cinfo.output_width;
                    Height=cinfo.output_height;

                    if(bmpLoaded)
                    {
                            delete bmpBuffer;
                    }
                    bmpBuffer=new BYTE[(Height+1)*Width*3]; //這里多申請一行,是因為在模擬器執行時,會出現無法加載的錯誤,但在機器上正常

                    bmpLoaded=TRUE;

                    pBuffer = (*cinfo.mem->alloc_sarray)
                            ((j_common_ptr) &cinfo, JPOOL_IMAGE, nRowSize, 1);
                    while(cinfo.output_scanline < cinfo.output_height)
                    {
                            jpeg_read_scanlines(&cinfo, pBuffer, 1);

                            start=nRowSize*cinfo.output_scanline;
                            for(i=0;i<nRowSize;i++)
                            {
                                    bmpBuffer[start+i]=pBuffer[0]Idea [I];
                            }       
                    }

                    CreateBitmap();
                   
                    jpeg_finish_decompress(&cinfo);
                    jpeg_destroy_decompress(&cinfo);
                    fclose(pFile);

            }

                (2)將加載后的像素數據建立一個HBITMAP對象的函數
                注意這里沒有使用CSTScreenBuffer,因為在我實驗時,用這個函數加載后,內存資源沒有釋放,這樣每加載一幅圖或做一次處理,就會多消耗幾兆內存,Pocket PC內存很快就會被耗盡。所以這里將像素數據加上頭信息就可以CreateDIBSection了。
                void CImageView::CreateBitmap()
            {
                    int m_nCorrectedWidth,m_nWidth,m_nHeight;

                    m_nCorrectedWidth = ( ( Width + 3 ) / 4 ) * 4;
                    m_nWidth = Width;
                    m_nHeight = Height;

                    DIBINFO  dibInfo;
                    BGRColor *m_pBuffer;

                    dibInfo.bmiHeader.biBitCount = 24;
                    dibInfo.bmiHeader.biClrImportant = 0;
                    dibInfo.bmiHeader.biClrUsed = 0;
                    dibInfo.bmiHeader.biCompression = 0;
                    dibInfo.bmiHeader.biHeight = m_nHeight;
                    dibInfo.bmiHeader.biPlanes = 1;
                    dibInfo.bmiHeader.biSize = 40;
                    dibInfo.bmiHeader.biSizeImage = m_nCorrectedWidth*m_nHeight*3;
                    dibInfo.bmiHeader.biWidth = m_nCorrectedWidth;
                    dibInfo.bmiHeader.biXPelsPerMeter = 3780;
                    dibInfo.bmiHeader.biYPelsPerMeter = 3780;
                    dibInfo.bmiColors[0].rgbBlue = 0;
                    dibInfo.bmiColors[0].rgbGreen = 0;
                    dibInfo.bmiColors[0].rgbRed = 0;
                    dibInfo.bmiColors[0].rgbReserved = 0;

                    HDC hDC = ::GetDC(NULL);

                    if(m_hBitmap)
                    {
                            :eleteObject(m_hBitmap);
                            m_hBitmap=0;
                    }
                    m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*)dibInfo, DIB_RGB_COLORS, (void**)&m_pBuffer, NULL, 0);
                   
                    ::ReleaseDC(NULL,hDC);

                    int nPosition = 0;
                    int nDataPosition = 0;

                    for (int y=0; y<Height; y++) {
                            nPosition = m_nCorrectedWidth*(m_nHeight-y-1);
                            nDataPosition = Width*3*y;
                            for (int x=0; x<Width; x++) {
                                    m_pBuffer[nPosition].m_R = bmpBuffer[nDataPosition++];
                                    m_pBuffer[nPosition].m_G = bmpBuffer[nDataPosition++];
                                    m_pBuffer[nPosition].m_B = bmpBuffer[nDataPosition++];
                                    nPosition++;
                            }
                    }

            }
                (3)在繪畫函數中,這里是OnDraw(),加入如下代碼:
                if (m_hBitmap)
                    {
                        CDC memDc;
                            VERIFY(memDc.CreateCompatibleDC(&dc));
                        HBITMAP hOldBitmap = (HBITMAP)::SelectObject(memDc.GetSafeHdc(), m_hBitmap);
                            VERIFY(dc.BitBlt(-LeftTop.x, -LeftTop.y, Width, Height, &memDc, 0, 0, SRCCOPY));
                        ::SelectObject(memDc.GetSafeHdc(), hOldBitmap);
                            VERIFY( memDc.DeleteDC() );
                    }

            5.使用JpegLib庫保存Jpeg圖片
                這里是一種實現方法:
               void CImageView::SaveImage(const CString &strFileName)
            {       
                    int nQuality=85; //保存質量Q值為85

                    if(!::WriteRGBBytesIntoJpegFile(strFileName,Width,Height,nQuality,bmpBuffer))
                    {
                            ::AfxMessageBox(GetJpegWriterError());
                    }
            }

            其他的更詳細內容的看例程中的其他消息處理函數就可以了。

            1.問題的由來
                Jpeg圖片在圖像處理領域已經用的相當廣泛了。但在編程領域,尤其是嵌入式編程領域使用的還不是很廣。主要的原因是Jpeg的數據結構和算法遠較bmp復雜,非圖像算法的專業人士,通常是無法理解這些的。(我有個同事,他曾經花了半個月,研究過Jpeg的原理,還為此在team內部舉辦了一個講座,講了足足有一個小時,令眾人對之仰慕萬分,但他卻說,僅得皮毛,未得要害。從此我對Jpeg的原理近而遠之。)
                近來,因工作需要,要在wince平臺下,為程序添加Jpeg支持。一般來說,此類問題最容易的解決方案是使用OS提供的相關庫,畢竟現在不支持Jpeg的OS幾乎沒有。但在wince下這里出了個問題。目前絕大多數的wince設備是wince 4.X或5.X的,不過碰巧在圖像處理這塊,5.X和4.X的方法是不一樣的。4.X提供的方法在IMGDECMP.DLL中,而5.X提供的方法在Imaging.DLL中,而且不止是鏈接庫不同,庫的接口也是完全兩樣的。因此,如果軟件采用OS提供的相關庫的話,在這里就要準備兩套接口,非常的麻煩。況且,我們的軟件不僅要在wince下部署,將來還打算推廣到其他的平臺,因此這種方案顯然是不太好的。
                這時我想到了JpegLib。JpegLib是Independent JPEG Group——一個非Jpeg官方組織推出的Jpeg庫。這是個開源免費的庫,支持多種平臺和編譯器,你可以在www.ijg.org中獲得它的最新版本。在PC上它的效率比不了intel的Jpeg庫,因為后者進行了匯編優化。但在wince上應該和系統庫的效率相當。事實上如果查看系統的版權信息的話,Microsoft在wince中也使用了這個庫。RISC的芯片也基本沒有匯編優化的問題。
                網上的中文資料以以下兩篇文章最為詳盡。
                http://mobile.winfans.net/ccs/forums/516/PrintPost.aspx (文獻A)
                http://blog.csdn.net/zhao3728/archive/2007/08/22/1754877.aspx (文獻B)
                所以我的這篇文章主要作為補遺之用。

            2.編譯JpegLib庫
                文獻A和B都是使用現成的JpegLib庫,這樣的庫只在特定的平臺下才能用,完全體現不出JpegLib的優勢。所以掌握編譯JpegLib庫的方法,是很有必要的。
                JpegLib庫源代碼的組成
                1)makefile。JpegLib庫中有很多文件名為makefile的文件。它的后綴名表示它所用于的平臺或用途。隨便打開一個,就可以看到JpegLib庫源代碼的組成。
                2)makefile中LIBSOURCES變量所代表的文件是JpegLib的核心算法部分。
                3)makefile中SYSDEPSOURCES變量所代表的文件是JpegLib中負責內存分配的部分。這部分是系統相關的,所以根據需要選用一個就行了。
                4)makefile中APPSOURCES變量所代表的文件是JpegLib中提供諸如命令行壓縮Jpeg之類的功能的部分,實際上就是一些小工具。不過在編譯JpegLib庫時,不要將之添加到工程中。
                5)makefile中INCLUDES變量所代表的文件是源代碼中用到的頭文件。不是所有的頭文件都被核心算法部分使用到,因此有些頭文件在編譯JpegLib庫時,是不必要的,當然將之添加到工程中也不會出錯。
                6)makefile中DOCS變量所代表的文件是一些文檔、測試用例之類的東西。其中最有用的是example.c,文獻A和B的示例最重要的部分,就來自這里。
                7)jconfig。JpegLib庫中還有很多和makefile類似的jconfig,這是針對不同平臺的類型聲明。在使用時,應根據需要,將適當的jconfig文件的后綴名改為h。
                以上這些內容更詳細的說明見JpegLib庫的文檔,以及
                http://blog.csdn.net/axlrosek/archive/2007/03/29/1545496.aspx
                VC:不同版本的VC、EVC都差不多,參照文獻A的步驟修改相關文件,然后新建一個空工程,然后打開JpegLib中的makefile.vc文件,將2)和3)、5)、7)中的文件添加到工程中。將生成文件的類型定為lib就行了。此外,還需要針對調用的情況選擇適當的運行時庫,否則可能會出LNK2005錯誤。

            3.使用JpegLib庫
                JpegLib庫的使用參照文獻A和B,以及example.c就可以了。但文獻A的示例是有問題的。
                bmpBuffer[start+i]=pBuffer[0];
            應改為
                bmpBuffer[start+i]=pBuffer[0][i];
                jpeg_read_scanlines(&cinfo, pBuffer, 1)執行之后,掃描線的內容被放到pBuffer[0],而不是pBuffer中,用memcpy將掃描線的內容轉移到其他的緩沖區就行了,無需用循環語句。

            4.流輸入的Jpeg的處理
                上面的示例處理的都是從文件讀入的Jpeg,在現實中,還存在流輸入的Jpeg。在很多PC游戲中,程序的數據都被集中起來放入一個大文件之中,最典型的當屬暴雪的mpq文件。當這些文件被讀入內存時,就形成了字節流形式的文件。將之存為臨時文件,然后再用之前的方法,顯然是笨方法。這時可以采用jpeg_arr_src函數來替換jpeg_stdio_src函數。
                這一點還可以參考以下文檔,不過該文針對的好像是舊版本,使用時要注意。
                http://blog.china.com/u/060803/5544/200608/15355.html

            posted on 2011-02-22 16:32 心羽 閱讀(1717) 評論(0)  編輯 收藏 引用 所屬分類: 圖片處理
            国产精品成人无码久久久久久 | 中文字幕亚洲综合久久菠萝蜜| 色婷婷噜噜久久国产精品12p| 亚洲国产另类久久久精品小说| 国产精品日韩欧美久久综合| 久久嫩草影院免费看夜色| 亚洲日本va中文字幕久久| 久久久免费观成人影院| 色播久久人人爽人人爽人人片AV| 国产精品内射久久久久欢欢| 青青草原综合久久大伊人导航| 精品久久久无码人妻中文字幕| 久久亚洲天堂| 国产精品久久久久久久久| 日韩人妻无码精品久久免费一| 伊人久久综合精品无码AV专区| 亚洲国产精品久久久久婷婷软件| 久久夜色精品国产网站| 久久精品国产亚洲Aⅴ蜜臀色欲| 91亚洲国产成人久久精品网址| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 久久亚洲AV成人出白浆无码国产| 久久99久久成人免费播放| 国内精品久久久久久麻豆| 久久综合噜噜激激的五月天| 久久人人青草97香蕉| 午夜精品久久久久久久无码| 国产Av激情久久无码天堂| 欧美一区二区精品久久| 国产精品伊人久久伊人电影| 国产精品久久国产精品99盘| 久久夜色精品国产欧美乱| 漂亮人妻被中出中文字幕久久| 久久久精品久久久久久| 久久久精品人妻无码专区不卡| 久久国产精品一区| 久久人人爽人人澡人人高潮AV| 看全色黄大色大片免费久久久 | 91精品观看91久久久久久| 久久久青草青青亚洲国产免观| 欧美激情精品久久久久|