不要照抄!不要照抄!不要照抄!
首先需要用到老师给的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(); }