dポイントプレゼントキャンペーン実施中!

Visual C++6.0でjpgなどのカラーの画像を白黒にして
保存したいのですが、どうすればよいでしょうか?

日本語プログラミング言語「なでしこ」でソースを
組んでみたのですが、やはりインタプリタなので
速いとは言えず290x350の画像で30分程度かかってしまいます。

なでしこでは
画像を表示してその表示されている色を取得して
RGBの形式にし、それを下のURLを参考に
(r*30 + g*59 + b*11)/100しています。

VCでjpgなどを処理するにはどうすればよいでしょうか?


http://www.ne.jp/asahi/nagoya/ahomaro/builder/cp …

A 回答 (2件)

GDI+を利用すると、比較的簡単にJPEGファイルの読み書きができます。


使い方については以下のサイト等を参照して下さい。
http://lamoo.s53.xrea.com/develop/gdiplus/gdiplu …
http://www.kumei.ne.jp/c_lang/sdk4/sdk_335.htm
なおGDI+にはセキュリティ問題があるので、アプリを配布する際はその辺りに配慮する必要があります。

画像ファイルを読み込み、グレースケール画像をJPEGファイルに保存するサンプルは以下のような感じです。
動作確認はVC++.NET 2003(MFC7.1)で行いました。

//--------------------------------------------------
void Convert()
{
  // GDI+の初期化
  ULONG_PTR      gdiplusToken;
  GdiplusStartupInput gdiplusStartupInput;
  GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

  CBitmap*  pBmp = LoadImage(L"d:\\test.jpg");
  if (pBmp) {
    BITMAP    sBitmap;
    pBmp->GetBitmap(&sBitmap);
    DWORD  dwSize = (DWORD)(sBitmap.bmWidthBytes * sBitmap.bmHeight);
    BYTE*  pBuffer = new BYTE[dwSize];

    pBmp->GetBitmapBits(dwSize, pBuffer);

    int    nOffset  = 0;
    int    nVal  = 0;
    for (int j = 0; j < sBitmap.bmHeight; j++) {
      for (int i = 0;i < sBitmap.bmWidth; i++) {
        // pBuffer[nOffset]:青、pBuffer[nOffset + 1]:緑、pBuffer[nOffset + 2]:赤
        nVal = (pBuffer[nOffset] * 11 + pBuffer[nOffset + 1] * 59 + pBuffer[nOffset + 2] * 30) / 100;
        pBuffer[nOffset + 0] = (BYTE)nVal;
        pBuffer[nOffset + 1] = (BYTE)nVal;
        pBuffer[nOffset + 2] = (BYTE)nVal;
        nOffset += 4;  // 32bitカラーは1ピクセル=4バイト
      }
      nOffset = j * sBitmap.bmWidthBytes;
    }
    pBmp->SetBitmapBits(dwSize, pBuffer);
    SaveJpegImage(L"d:\\test-gr.jpg", *pBmp, 80);
    delete  pBuffer;
    delete  pBmp;
  }

  // GDI+の解放
  GdiplusShutdown(gdiplusToken);
}

//--------------------------------------------------
CBitmap* LoadImage(const WCHAR* szFileName)
{
  if (!szFileName) return NULL;

  CBitmap*   pBitmap = NULL;
  Bitmap*   pGdiBitmap = Bitmap::FromFile(szFileName);

  if (pGdiBitmap->GetLastStatus() == Ok) {
    HBITMAP   hBitmap = NULL;
    if (pGdiBitmap->GetHBITMAP(Color(0,0,0), &hBitmap) == Ok) {
      pBitmap = new CBitmap();
      pBitmap->Attach(hBitmap);
    }
  }
  return pBitmap;
}

//--------------------------------------------------
BOOL SaveJpegImage(const WCHAR* szFileName, const CBitmap& bmp, const int nQuality)
{
  if (!szFileName) return FALSE;

  // CLSIDの取得
  CLSID     clsid;
  GetEncoderClsid(L"image/jpeg", &clsid);
    
  // 品質指定
  EncoderParameters  encoderParams;
  encoderParams.Parameter[0].Guid        = EncoderQuality;
  encoderParams.Parameter[0].NumberOfValues  = 1;
  encoderParams.Parameter[0].Type        = EncoderParameterValueTypeLong;
  encoderParams.Parameter[0].Value      = (VOID*)&nQuality;
  encoderParams.Count              = 1;

  Bitmap    gdiBmp(bmp, NULL);
  if (gdiBmp.Save(szFileName, &clsid, &encoderParams) != Gdiplus::Ok) return FALSE;

  return TRUE;
}

//--------------------------------------------------
int GetEncoderClsid(const WCHAR* szFormat, CLSID* pClsid)
{
  UINT  nNum = 0;
  UINT  nSize = 0;
  ImageCodecInfo*    pImageCodecInfo = NULL;

  GetImageEncodersSize(&nNum, &nSize);
  if (nSize == 0) return -1;

  pImageCodecInfo = (ImageCodecInfo*)(malloc(nSize));
  if (!pImageCodecInfo) return -1;

  GetImageEncoders(nNum, nSize, pImageCodecInfo);

  for (UINT i = 0; i < nNum; ++i) {
    if (wcscmp(pImageCodecInfo[i].MimeType, szFormat) == 0) {
      *pClsid = pImageCodecInfo[i].Clsid;
      free(pImageCodecInfo);
      return i;
    }
  }

  free(pImageCodecInfo);
  return -1;
}
    • good
    • 0

ヘッダに書いてね。


LPPICTURE m_pJpeg;

BOOL CE_tikanDlg::ReadJpg(CString strJpgPathFileName)
{
// IPictureインターフェイスを初期化
m_pJpeg = NULL;
// JPEGファイルを読み込む
CFile fp;
BOOL bret = fp.Open( strJpgPathFileName, CFile::modeRead);
if( bret == FALSE) {
AfxMessageBox( "jpgがありません");
return FALSE;
}
DWORD dwSize = fp.GetLength();
// グローバル領域を確保
HGLOBAL h = ::GlobalAlloc( GMEM_MOVEABLE, dwSize);
if(h == NULL) {
fp.Close();
AfxMessageBox( "メモリがエラー");
return FALSE;
}
// 領域をロック
void *pBuf = ::GlobalLock( h);
if( pBuf == NULL) {
fp.Close();
::GlobalFree( h);
AfxMessageBox( "GlobalLock失敗");
return FALSE;
}
// ファイルの読み込み
if( fp.Read( pBuf, dwSize) != dwSize) {
fp.Close();
::GlobalUnlock( h);
::GlobalFree( h);
AfxMessageBox("読み込みエラー");
return FALSE;
}
// ファイルのクローズ
fp.Close();
::GlobalUnlock( h);

// IStreamを取得する
LPSTREAM pstm = NULL;
// グローバル領域からIStreamを作成
HRESULT hr =
::CreateStreamOnHGlobal(h, TRUE, &pstm);
if( SUCCEEDED(hr) == FALSE) {
return FALSE;
}

// IPictureのオブジェクトのアドレスを取得
hr = ::OleLoadPicture(pstm, dwSize, FALSE,
IID_IPicture, (LPVOID *)&m_pJpeg);
if( SUCCEEDED( hr) == FALSE || m_pJpeg == NULL)
{
pstm->Release();
AfxMessageBox( "IStream失敗");
return FALSE;
}
// IStreamオブジェクトを開放
pstm->Release();

// 以上までが、jpg読み込み

CPaintDC dc(this);
long hmWidth;
long hmHeight;
m_pJpeg->get_Width(&hmWidth);
m_pJpeg->get_Height(&hmHeight);
CSize size( hmWidth, hmHeight);

// HIMETRIC 単位をデバイス単位に変換
dc.HIMETRICtoDP(&size);


HBITMAP hBmp;
hBmp = CreateCompatibleBitmap(dc, size.cx, size.cy);

// 以上で BMPに変更


で、白黒変更は、自分、知らないので、たぶんここが参考になるっぽい

http://hpcgi1.nifty.com/MADIA/DelphiBBS/wwwlng.c …
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!