XMU 数字图像处理实验4 VC/VS MFC 编写JPEG图象读/写程序

来源:互联网 发布:淘宝女鞋推荐 编辑:程序博客网 时间:2024/06/04 19:36

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

首先需要用到老师给的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 onceclass MYJPG{public:int Width;//宽int Height;//高//int Channel;//1 Grey 3 RGBunsigned 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// CJpgViewIMPLEMENT_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_HANDLERSAFXPrintPreview(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_HANDLERStheApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);#endif}// CJpgView 诊断#ifdef _DEBUGvoid 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();}



 
原创粉丝点击