不要照抄!不要照抄!不要照抄!
首先需要用到老師給的JpegDecoder和jpeglib(需要自己生成),
使用VS的命令行來生成jpeglib,具體步驟爲
使用libjpeg源代碼實現讀取jpeg格式圖片,生成.lib方法如下:(轉自)
1. 首先去官網http://www.ijg.org/files/下載源碼,下載的是jpegsr9a.zip。
2. 解壓後放到E盤根目錄,“E:\jpeg-9a\”下會有很多文件。
3. 將“jconfig.vc”改成“jconfig.h”
4. 將“makefile.vc”中第12行
!include <win32.mak>
改成 !include <C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\win32.mak>
(就是你電腦裏面的win32.mak文件的路徑,如果沒有就網上下一個就好)
5.之後進VS的開發人員命令提示,cd到你的jpeg-9a目錄,如E:\jpeg-9a
6. 定位到E:\jpeg-9a。
在命令行中輸入 cd jpeg-9a
7. 輸入” nmake -f makefile.vc” 生成所需要的libjpeg.lib函數庫。
8. 使用時,將“jconfig.h”、“jmorecfg.h”、“jpeglib.h”、“libjpeg.lib”四個文件拷貝到對應的文件夾內。
9. libjpeg.lib是用c語言開發的,如果在C++程序裏使用,需要用extern "C" { }包含一下。如下:
extern "C"
{
#include "jpeglib.h"
}
10. 在“解決方案資源管理器”中“屬性頁“的”連接器-輸入-附加依賴項”內,增加“libjpeg.lib” 我的工程叫JPG,內部除了MFC框架、jpeglib和jpegdecoder相關文件之外還有自己寫的MYDIB、MYJPG類 分別用於存儲BMP、JPG格式的文件。
MYJPG.cpp
#include "stdafx.h"
#include "MYDIB.h"
#include "MYJPG.h"
#include "math.h"
#include "JpegDecoder.h"
#include "jconfig.h"
#include "jmorecfg.h"
extern "C"
{
#include "jpeglib.h"
}
MYJPG::MYJPG()
{
Width = Height = 0;
myJPGdata = NULL;
}
MYJPG::~MYJPG()
{
if (myJPGdata)
delete myJPGdata;
Width = Height = 0;
myJPGdata = NULL;
}
void MYJPG::ReadJPG(const CString &fileName)
{
FILE *fp = _tfopen(fileName, _T("rb"));
if (fp == NULL)
{
AfxMessageBox(_T("read jpg error"));
return;
}
JpegDecoder temp(fp);
Width = temp.GetWidth();
Height = temp.GetHeight();
if (myJPGdata)
delete myJPGdata;
myJPGdata = new unsigned char[Width * Height * 4];
temp.GetJPEGBuffer(Width, Height, &myJPGdata);
}
void MYJPG::WriteToJPG(const CString &fileName)
{
/* This struct contains the JPEG compression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
* It is possible to have several such structures, representing multiple
* compression/decompression processes, in existence at once. We refer
* to any one struct (and its associated working data) as a "JPEG object".
*/
unsigned char *temp = new unsigned char[Width*Height * 3];
int count = 0;
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
temp[count++] = myJPGdata[(i*Width + j) * 4 + 2];
temp[count++] = myJPGdata[(i*Width + j) * 4 + 1];
temp[count++] = myJPGdata[(i*Width + j) * 4];
}
}
int nChannel = 3;
int nQuality = 80;
struct jpeg_compress_struct cinfo;
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* (see the second half of this file for an example). But here we just
* take the easy way out and use the standard error handler, which will
* print a message on stderr and call exit() if compression fails.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
FILE *outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo); /* Now we can initialize the JPEG compression object. */
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
/* Here we use the library-supplied code to send compressed data to a
* stdio stream. You can also write your own code to do something else.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to write binary files.
*/
if ((outfile = fopen(fileName, "wb")) == NULL)
{
fprintf(stderr, "can't open %s\n", fileName);
return;
}
jpeg_stdio_dest(&cinfo, outfile);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in:
*/
cinfo.image_width = Width; /* image width and height, in pixels */
cinfo.image_height = Height;
cinfo.input_components = nChannel; /* # of color components per pixel */
if (nChannel == 1)
{
cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
}
else if (nChannel == 3)
{
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
}
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
*/
jpeg_set_defaults(&cinfo);
// Now you can set any non-default parameters you wish to.
// Here we just illustrate the use of quality (quantization table) scaling:
jpeg_set_quality(&cinfo, nQuality, TRUE); /* limit to baseline-JPEG values */
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter, so that we don't have to keep track ourselves.
* To keep things simple, we pass one scanline per call; you can pass
* more if you wish, though.
*/
row_stride = Width * nChannel; /* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height)
{
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = &temp[cinfo.next_scanline * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
delete temp;
temp = NULL;
/* After finish_compress, we can close the output file. */
fclose(outfile);
/*
CFile JPGFile;
VERIFY(JPGFile.Open(fileName, CFile::modeCreate | CFile::modeWrite));
try
{
JPGFile.Write(myJPGdata, Width*Height * 4);
}
catch (CException* pe)
{
pe->Delete();
AfxMessageBox(_T("write error"));
JPGFile.Close();
return;
}
JPGFile.Close();
*/
}
void MYJPG::WriteToBMP(const CString &fileName)
{
MYDIB *tmpdib = new MYDIB;
int w = Width;
int h = Height;
LONG size = h*((w * 3 + 3) / 4 * 4);
tmpdib->myBMPdata = new unsigned char[size];
int count = 0;
for (int i = 0; i < h; i++)
{
int ii = h - i - 1;
for (int j = 0; j < w; j++)
{
tmpdib->myBMPdata[count++] = myJPGdata[(ii*w + j) * 4];
tmpdib->myBMPdata[count++] = myJPGdata[(ii*w + j) * 4 + 1];
tmpdib->myBMPdata[count++] = myJPGdata[(ii*w + j) * 4 + 2];
}
while (count % 4)
{
tmpdib->myBMPdata[count++] = 0;
}
}
tmpdib->myBMPfileheader.bfType = 0x4D42;
tmpdib->myBMPfileheader.bfSize = 14 + 40 + size;
tmpdib->myBMPfileheader.bfReserved1 = 0;
tmpdib->myBMPfileheader.bfReserved2 = 0;
tmpdib->myBMPfileheader.bfOffBits = 14 + 40;
tmpdib->myBMPinfoheader.biSize = 40;
tmpdib->myBMPinfoheader.biWidth = Width;
tmpdib->myBMPinfoheader.biHeight = Height;
tmpdib->myBMPinfoheader.biPlanes = 1;
tmpdib->myBMPinfoheader.biBitCount = 24;
tmpdib->myBMPinfoheader.biCompression = 0;
tmpdib->myBMPinfoheader.biSizeImage = 14 + 40 + size;
tmpdib->myBMPinfoheader.biXPelsPerMeter = 0;
tmpdib->myBMPinfoheader.biYPelsPerMeter = 0;
tmpdib->myBMPinfoheader.biClrUsed = 0;
tmpdib->myBMPinfoheader.biClrImportant = 0;
tmpdib->myBMPrgbquad = NULL;
CFile BMPFile;
VERIFY(BMPFile.Open(fileName, CFile::modeCreate | CFile::modeWrite));
try
{
//BMPFile.Write(&tmpdib->myBMPfileheader, sizeof(tmpdib->myBMPfileheader));
BMPFile.Write(&tmpdib->myBMPfileheader.bfType, sizeof(tmpdib->myBMPfileheader.bfType));
BMPFile.Write(&tmpdib->myBMPfileheader.bfSize, sizeof(tmpdib->myBMPfileheader.bfSize));
BMPFile.Write(&tmpdib->myBMPfileheader.bfReserved1, sizeof(tmpdib->myBMPfileheader.bfReserved1));
BMPFile.Write(&tmpdib->myBMPfileheader.bfReserved2, sizeof(tmpdib->myBMPfileheader.bfReserved2));
BMPFile.Write(&tmpdib->myBMPfileheader.bfOffBits, sizeof(tmpdib->myBMPfileheader.bfOffBits));
//BMPFile.Write(&tmpdib->myBMPinfoheader, sizeof(tmpdib->myBMPinfoheader));
BMPFile.Write(&tmpdib->myBMPinfoheader.biSize, sizeof(tmpdib->myBMPinfoheader.biSize));
BMPFile.Write(&tmpdib->myBMPinfoheader.biWidth, sizeof(tmpdib->myBMPinfoheader.biWidth));
BMPFile.Write(&tmpdib->myBMPinfoheader.biHeight, sizeof(tmpdib->myBMPinfoheader.biHeight));
BMPFile.Write(&tmpdib->myBMPinfoheader.biPlanes, sizeof(tmpdib->myBMPinfoheader.biPlanes));
BMPFile.Write(&tmpdib->myBMPinfoheader.biBitCount, sizeof(tmpdib->myBMPinfoheader.biBitCount));
BMPFile.Write(&tmpdib->myBMPinfoheader.biCompression, sizeof(tmpdib->myBMPinfoheader.biCompression));
BMPFile.Write(&tmpdib->myBMPinfoheader.biSizeImage, sizeof(tmpdib->myBMPinfoheader.biSizeImage));
BMPFile.Write(&tmpdib->myBMPinfoheader.biXPelsPerMeter, sizeof(tmpdib->myBMPinfoheader.biXPelsPerMeter));
BMPFile.Write(&tmpdib->myBMPinfoheader.biYPelsPerMeter, sizeof(tmpdib->myBMPinfoheader.biYPelsPerMeter));
BMPFile.Write(&tmpdib->myBMPinfoheader.biClrUsed, sizeof(tmpdib->myBMPinfoheader.biClrUsed));
BMPFile.Write(&tmpdib->myBMPinfoheader.biClrImportant, sizeof(tmpdib->myBMPinfoheader.biClrImportant));
if (tmpdib->myBMPrgbquad != NULL)
BMPFile.Write(tmpdib->myBMPrgbquad, sizeof(tmpdib->myBMPrgbquad)*pow(2, tmpdib->myBMPinfoheader.biBitCount));
BMPFile.Write(tmpdib->myBMPdata, tmpdib->myBMPinfoheader.biSizeImage);
}
catch (CException* pe)
{
pe->Delete();
AfxMessageBox(_T("write error"));
BMPFile.Close();
return;
}
BMPFile.Close();
delete tmpdib;
tmpdib = NULL;
}
#pragma once
class MYJPG
{
public:
int Width;//寬
int Height;//高
//int Channel;//1 Grey 3 RGB
unsigned char *myJPGdata;//真實圖像數據
public:
MYJPG();
~MYJPG();
void ReadJPG(const CString &fileName);
void WriteToJPG(const CString &fileName);
void WriteToBMP(const CString &fileName);
};
MYDIB和上次實驗3類似,基本沒什麼改動就增加了輸出到JPG
之後和MYJPG中相同輸出到JPG文件中
JPGView.cpp:
// JpgView.cpp: CJpgView 類的實現
//
#include "stdafx.h"
// SHARED_HANDLERS 可以在實現預覽、縮略圖和搜索篩選器句柄的
// ATL 項目中進行定義,並允許與該項目共享文檔代碼。
#ifndef SHARED_HANDLERS
#include "Jpg.h"
#endif
#include "JpgDoc.h"
#include "JpgView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CJpgView
IMPLEMENT_DYNCREATE(CJpgView, CView)
BEGIN_MESSAGE_MAP(CJpgView, CView)
// 標準打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CJpgView::OnFilePrintPreview)
ON_WM_CONTEXTMENU()
ON_WM_RBUTTONUP()
ON_COMMAND(ID_FILE_OPEN, &CJpgView::OnFileOpen)
ON_COMMAND(ID_FILE_SAVE_AS, &CJpgView::OnFileSaveAs)
END_MESSAGE_MAP()
// CJpgView 構造/析構
CJpgView::CJpgView()
{
// TODO: 在此處添加構造代碼
mydib = NULL;
myjpg = NULL;
}
CJpgView::~CJpgView()
{
if (mydib)
{
delete mydib;
mydib = NULL;
}
if (myjpg)
{
delete myjpg;
myjpg = NULL;
}
}
BOOL CJpgView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此處通過修改
// CREATESTRUCT cs 來修改窗口類或樣式
return CView::PreCreateWindow(cs);
}
// CJpgView 繪圖
void CJpgView::OnDraw(CDC* pDC)
{
CJpgDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此處爲本機數據添加繪製代碼
unsigned char red, blue, green;
if (myjpg)
{
int myheight = myjpg->Height;
int mywidth = myjpg->Width;
for (int i = 0; i < myheight; i++)
{
for (int j = 0; j < mywidth; j++)
{
blue = *(myjpg->myJPGdata + (mywidth*i + j) * 4);
green = *(myjpg->myJPGdata + (mywidth*i + j) * 4 + 1);
red = *(myjpg->myJPGdata + (mywidth*i + j) * 4 + 2);
pDC->SetPixelV(10 + j, 10 + i, RGB(red, green, blue));
}
}
}
else if (mydib)
{
int myheight = mydib->myBMPinfoheader.biHeight;
int mywidth = mydib->myBMPinfoheader.biWidth;
int GetBitNum(int num);
int bitnum = GetBitNum(mydib->myBMPinfoheader.biBitCount);
int k = 0;
int count = 0;
unsigned char temp = *(mydib->myBMPdata);
unsigned char color;
unsigned gethigh, shl;
if (bitnum == 2)
{
gethigh = 0x80;
shl = 1;
}
else if (bitnum == 16)
{
gethigh = 0xf0;
shl = 4;
}
else if (bitnum == 256)
{
gethigh = 0xff;
shl = 8;
}
if (bitnum == 2 || bitnum == 16 || bitnum == 256)
{
for (int i = 0; i < myheight; i++)
{
for (int j = 0; j < mywidth; j++)
{
k += shl;
color = (temp & gethigh) >> (8 - shl);
red = mydib->myBMPrgbquad[color].rgbRed;
green = mydib->myBMPrgbquad[color].rgbGreen;
blue = mydib->myBMPrgbquad[color].rgbBlue;
pDC->SetPixelV(10 + j, 10 + myheight - i, RGB(red, green, blue)); // 數組左上角爲(0,0) 圖片左下角座標爲(0,0)
temp <<= shl;
if (k == 8)
{
count++;
temp = *(mydib->myBMPdata + count);
k = 0;
}
}
if (k > 0)count++;
while (count % 4)count++;
temp = *(mydib->myBMPdata + count);
k = 0;
}
}
else
{
for (int i = 0; i < myheight; i++)
{
for (int j = 0; j < mywidth; j++)
{
blue = mydib->myBMPdata[count++];
green = mydib->myBMPdata[count++];
red = mydib->myBMPdata[count++];
pDC->SetPixelV(10 + j, myheight - (10 + i), RGB(red, green, blue)); // 數組左上角爲(0,0) 圖片左下角座標爲(0,0)
}
while (count % 4)count++;
}
}
}
}
// CJpgView 打印
void CJpgView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
AFXPrintPreview(this);
#endif
}
BOOL CJpgView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默認準備
return DoPreparePrinting(pInfo);
}
void CJpgView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加額外的打印前進行的初始化過程
}
void CJpgView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印後進行的清理過程
}
void CJpgView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
ClientToScreen(&point);
OnContextMenu(this, point);
}
void CJpgView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}
// CJpgView 診斷
#ifdef _DEBUG
void CJpgView::AssertValid() const
{
CView::AssertValid();
}
void CJpgView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CJpgDoc* CJpgView::GetDocument() const // 非調試版本是內聯的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CJpgDoc)));
return (CJpgDoc*)m_pDocument;
}
#endif //_DEBUG
// CJpgView 消息處理程序
void CJpgView::OnFileOpen()
{
// TODO: 在此添加命令處理程序代碼
CString filter;
filter = "所有文件(*.bmp,*.jpg)|*.bmp;*.jpg| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg||";
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, filter, NULL);
if (dlg.DoModal() == IDOK)
{
if (mydib)
{
delete mydib;
mydib = NULL;
}
if (myjpg)
{
delete myjpg;
myjpg = NULL;
}
CString fileName = dlg.GetPathName();
if (fileName.Find(_T(".bmp")) >= 0 || fileName.Find(_T(".BMP")) >= 0)
{
mydib = new MYDIB;
mydib->ReadBMP(fileName);
}
if (fileName.Find(_T(".jpg")) >= 0 || fileName.Find(_T(".JPG")) >= 0)
{
myjpg = new MYJPG;
myjpg->ReadJPG(fileName);
}
}
Invalidate();
}
void CJpgView::OnFileSaveAs()
{
// TODO: 在此添加命令處理程序代碼
if (!mydib && !myjpg)return;
CString filter;
filter = "所有文件(*.bmp,*.jpg)|*.bmp;*.jpg| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg||";
CFileDialog dlg(FALSE, NULL, NULL, OFN_HIDEREADONLY, filter, NULL);
if (dlg.DoModal() == IDOK)
{
CString fileName = dlg.GetPathName();
if (fileName.Find(_T(".bmp")) >= 0 || fileName.Find(_T(".BMP")) >= 0)
{
if (mydib)
{
mydib->WriteToBMP(fileName);
}
else if (myjpg)
{
myjpg->WriteToBMP(fileName);
}
}
if (fileName.Find(_T(".jpg")) >= 0 || fileName.Find(_T(".JPG")) >= 0)
{
if (myjpg)
{
myjpg->WriteToJPG(fileName);
}
else if (mydib)
{
mydib->WriteToJPG(fileName);
}
}
}
Invalidate();
}