XMU 數字圖像處理實驗4 VC/VS MFC 編寫JPEG圖象讀/寫程序

不要照抄!不要照抄!不要照抄!

首先需要用到老師給的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();
}










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章