FC2ブログ

ホーム > JPEGファイルフォーマット > JPEGファイルの読み込み

JPEGファイルの読み込み



今回は、JPEGファイルデコード「Independent JPEG Group」のライブラリを使用して、カラーの場合は24ビットDIBグレイスケールの場合は8ビットDIBを作成します。尚JPEGライブラリの扱いについては、前回の「libjpegのインストール」をご参照ください。




libjpegをインクルードするための定義です。

extern "C" {
#define XMD_H // 再定義エラーを防ぐ
#include "jpeglib.h"
}


前回の「libjpegのインストール」でダウンロードした「jpeg-8b」フォルダーから、以下のファイルを今回のプログラム本体を格納した「JpegFile.cpp」ファイルのあるフォルダーにコピーしておきます。

jpeg-8b」フォルダーからコピーするファイルです。

jpeglib.h
jconfig.h
jmorecfg.h


ビットマップバイト幅の算出マクロです。

//ビットマップバイト幅の算出マクロ
#ifndef WIDTHBYTES
#define WIDTHBYTES(bits) (((bits)+31)/32*4)
#endif//WIDTHBYTES


内部エラー修復のための構造体定義とエラー処理関数です。

#include <setjmp.h>

//JPEG拡張エラー構造体
struct my_error_mgr {
struct jpeg_error_mgr pub; //エラーメッセージ
jmp_buf setjmp_buffer; //ジャンプバッファ
};
typedef struct my_error_mgr * my_error_ptr;

//エラー処理関数
METHODDEF(void) my_error_exit (j_common_ptr cinfo)
{
//エラーポインタの取得
my_error_ptr myerr = (my_error_ptr) cinfo->err;

char buffer[JMSG_LENGTH_MAX];

//エラーメッセージの作成
(*cinfo->err->format_message) (cinfo, buffer);

//エラーメッセージの表示
// MessageBox(NULL,buffer,"JPEG Fatal Error",MB_ICONSTOP);

//ジャンプバッファで指定された位置に戻る
longjmp(myerr->setjmp_buffer, 1);
}


Jpegファイルを読み込むためのユーザー定義関数です。

//JPEGファイル読み込み関数
unsigned int _JpegReadFunc(void* io_ptr, unsigned char* buf, unsigned int size){
return ((CFile*)io_ptr)->Read(buf,(UINT)size);
}


まずは指定されたパス名のファイルを開いて、_JpegStreamIn関数を呼び出します。

//JPEGファイルの読み込み
HBITMAP __stdcall _LoadJPG(LPCTSTR lpszFileName)
{
if (!lpszFileName) return FALSE;
CFile infile;
if (!infile.Open(lpszFileName,CFile::modeRead)) return FALSE;
HBITMAP hBitmap=_JpegStreamIn(&infile);
infile.Close();
return hBitmap;
}


JPEGストリームを読み込んでDIBを作成します。

//JPEGストリームから24ビットDIBを読み出す
HBITMAP __stdcall _JpegStreamIn(CFile* infile)
{
ASSERT(AfxIsValidAddress(infile,sizeof(CFile),0));

//JPEGデコードオブジェクトの配置
struct jpeg_decompress_struct cinfo;

//JPEG内部で発生したエラーを処理する処理関数を定義する
struct my_error_mgr jerr; //JPEG拡張エラー構造体
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;

//これ以降の内部エラーはここに戻り、エラーとして返される
BITMAPINFO* pBmi=0;
if (setjmp(jerr.setjmp_buffer)) {
if (pBmi) delete[]pBmi;
jpeg_destroy_decompress(&cinfo);
return FALSE;
}

//JPEGデコードオブジェクトの初期化
jpeg_create_decompress(&cinfo);

//入力ストリームを設定する
jpeg_set_read_fn(&cinfo,infile,_JpegReadFunc);

//ファイルパラメータを読み込む
(void) jpeg_read_header(&cinfo, TRUE);

//デコード開始
(void) jpeg_start_decompress(&cinfo);

UINT width = cinfo.output_width; //画像幅
UINT height = cinfo.output_height; //画像高さ

//BITMAPINFO構造体の作成
DWORD dwSizeOfColorTable=(cinfo.out_color_components==1)? sizeof(RGBQUAD)*256:0;
DWORD dwSizeOfBitmapInfo=sizeof(BITMAPINFOHEADER)+dwSizeOfColorTable;
pBmi=(BITMAPINFO*)(new BYTE[dwSizeOfBitmapInfo]);
::ZeroMemory(pBmi,dwSizeOfBitmapInfo);
pBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmi->bmiHeader.biWidth = width;
pBmi->bmiHeader.biHeight = height;
pBmi->bmiHeader.biPlanes = 1;
pBmi->bmiHeader.biBitCount = 24;
//グレイスケールの場合は、256色カラーテーブルを作成します。
if (dwSizeOfColorTable){
pBmi->bmiHeader.biBitCount=8;
//グレイスケール用のカラーテーブルの作成
for(int i=0;i<256;i++)
pBmi->bmiColors[i].rgbBlue =
pBmi->bmiColors[i].rgbGreen=
pBmi->bmiColors[i].rgbRed =i;
}

//DIBSECTIONの作成
LPVOID pvBits;
HBITMAP hBitmap=::CreateDIBSection(0,pBmi,DIB_RGB_COLORS,&pvBits,0,0);
if (!hBitmap) {
if (pBmi) delete[]pBmi;
jpeg_destroy_decompress(&cinfo);
return FALSE;
}

//ラインバッファのバイト数を算出する
int row_stride = cinfo.output_width * cinfo.output_components;

//ビットマップバイト幅
DWORD widthBytes=WIDTHBYTES(width*pBmi->bmiHeader.biBitCount);

//ラインバッファの領域を確保する
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

//1行ごとに読み込む
BYTE r,g,b;
switch(cinfo.out_color_components){
case 1://グレイスケールの時
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
::CopyMemory((PBYTE)pvBits+widthBytes*(height-cinfo.output_scanline),buffer[0],width);
}
break;
case 3://カラーRGBの時
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
PBYTE src=(PBYTE)buffer[0];
PBYTE dst=(PBYTE)pvBits+widthBytes*(height-cinfo.output_scanline);
for (UINT j=0;j<width;j++){
r=*src++;
g=*src++;
b=*src++;
*dst++=b;
*dst++=g;
*dst++=r;
}
}

}
//デコード終了後の後片付け
if (pBmi){
delete[]pBmi;
pBmi=0;
}
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return hBitmap;
}


hBitmapの内容が、読み込んだJPEGファイルから作成したDIBのハンドルになります。

サンプルプログラム(VisualC++net2003ソリューション)JpegFileTest01.zip

上記のzipファイルをダウンロードして、前回の「libjpegのインストール」で作成した「jpeg-8b」フォルダーと「libJpeg」フォルダーがある同じフォルダー内にWinRAR等を使って解凍すると、「JpegFileTest01」と言う名のフォルダーが作成されます。



「JpegFileTest01」フォルダー内にある「JpegFileTest.sln」を開いて「F5」キーを押すと、ビルド確認のダイヤログが表示されるので「Yes」を選択してソリューションをビルドします。ビルドエラーが出てどうしてもlibjpegのビルドが上手くいかない方は、「JpegFileTest」プロジェクト内にある「JpegFile.cpp」ファイルを開いて、下記の赤字の行にあるコメントアウトを外して、フォルダー内にあるライブラリーファイルを直接読み込むようにします。修正後、再度「F5」キーでビルドしてみて下さい。

// JpegFile.cpp : implementation file
//


#include "stdafx.h"
#include "JpegFileTest.h"
#include "JpegFile.h"

extern "C" {
#define XMD_H // 再定義エラーを防ぐ
#include "jpeglib.h"
}
//#pragma comment(lib,"libjpeg") ←コメントアウトを外してください。
↓   ↓   ↓

#pragma comment(lib,"libjpeg") //修正後

ビルドが終わると、直ちにプログラムが自動起動してウィンドウが表示されます。ウィンドウのメニューで「ファイル」/「開く」を選択して、「ファイルを開く」ダイヤログを表示させます。



resフォルダー内の「rgb1951.jpg」を選択し、「開く」ボタンを押すと、下のような画像が表示されるか確認します。



グレイスケール画像の「rgb1951gray.jpg」の方も、下のような画像が表示されるか確認してください。



※IJGのJPEGライブラリーの中にあるReadMeファイルの文中に「IJGのJPEGライブラリーを使用する時はドキュメントのどこかに、IJGコードを使った事を認める表示が必要。」とあるので、サンプルプログラムではバージョン情報ダイヤログの下のほうに「This software is based in part on the work of the Independent JPEG Group」と表示するようにしました。





スポンサーサイト



コメント: 0

この記事へのコメント
ブログ著者にのみ知らせます。

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/28-4c99ae82
Listed below are links to weblogs that reference
JPEGファイルの読み込み from マルチメディアファイルフォーマット

Home > JPEGファイルフォーマット > JPEGファイルの読み込み

タグクラウド
ブロとも申請フォーム

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る