dc.PlgBlt()変形後の表示画像の保存


hannya  2011-12-23 14:55:07  No: 73064  IP: 192.*.*.*

おせわになっています
WindowsXp  VS  C++6.0です
現状は描画した像を保存できるのは  dc.PlgBlt()の前の状態の像です
dc.PlgBlt()で表示した状態の像を保存するにはどうしたら良いでしょうか
現行コードは以下のとおりです
if( !transfindex) dc.BitBlt(0, 0, m_imageSiH, m_imageSiV, &memDC, 0, 0, SRCCOPY);
else dc.PlgBlt(points, &memDC, 0, 0, m_imageSiH, m_imageSiV, CBitmap(), 0, 0);//平行四辺形移行

if( stilImage )//== 1 saving the final still image

  m_imageD_F_Name.Format("KolamImages\\%s-N.jpg", m_strFileTitle); 
  memDC.SaveJPEG(m_imageD_F_Name);   //saveImage 
  stilImage = 0;  // OFF save image
}

編集 削除
gak  2011-12-26 18:16:28  No: 73065  IP: 192.*.*.*

> dc.PlgBlt()で表示した状態の像を保存するにはどうしたら良いでしょうか
以下、ヤマ勘に依る回答。


if( stilImage )//== 1 saving the final still image

    m_imageD_F_Name.Format("KolamImages\\%s-N.jpg", m_strFileTitle); 
//  memDC.SaveJPEG(m_imageD_F_Name);  //saveImage
    if (transfindex) {
        // points で指定された菱形領域に外接する矩形を求める
        std::vector<LONG> horz, vert;
        for (int i=0; i < 3; ++i) {
            horz.push_back(points[i].x);
            vert.push_back(points[i].y);
        }
        std::sort(horz.begin(), horz.end());
        std::sort(vert.begin(), vert.end());
        CRect rect(horz[0], vert[0], horz[2] + (horz[1] - horz[0]), vert[2] + (vert[1] - vert[0]));
        // allocate buffer
        CBitmap bitmap;
        bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
        // save image
        CBitmap *prev = memDC.SelectObject(&bitmap);
        memDC.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, rect.left, rect.top, SRCCOPY);
        memDC.SaveJPEG(m_imageD_F_Name);  //saveImage
        memDC.SelectObject(prev);
    }
    else {
        memDC.SaveJPEG(m_imageD_F_Name);  //saveImage
    }
    stilImage = 0; // OFF save image
}

編集 削除
hannya  2011-12-26 18:46:46  No: 73066  IP: 192.*.*.*

ありがとうございました
思ったより結構な量のコードです。
はい  試行します
アニメーション(本来この機能があればそれとは別に)
すこしづつ描いては  このSAVEをしてアニメーションの駒像を作っています
ですので
この部分を関数にしたいのですが
その関数内で  memDCは共通に働かないでしょうか?

編集 削除
gak  2011-12-27 01:47:34  No: 73067  IP: 192.*.*.*

> // points で指定された菱形領域に外接する矩形を求める
>  :
> CRect rect(horz[0], vert[0], horz[2] + (horz[1] - horz[0]), vert[2] + (vert[1] - vert[0]));
あーごめん。この処理じゃダメだ。一部ケースにしか対応できてない…
後述の様に(机上だけで組んでるコードなので未だ間違っている可能性あるが)修正。

> その関数内で  memDCは共通に働かないでしょうか?
今一日本語として旨く意味が理解できなかった。けど「イメージ保存する処理を共通関数化したい」のだと”推察して”回答する。

後、先にも言った通りかなりヤマ勘で書いている。
例えば CMemDC というクラスはhannyaさんのオリジナルクラス(VS2008sp1以降のMFCにもCMemDCという名のクラスは存在するが恐らく別物)だと思われる。
なので、hannyaさんが示されたコードから「CMemDCはこんな使い方するクラスなんだろうなぁ」とか勝手に想像して書いている。
そういう訳なんで、このコードそのままをhannyaさんのソースに持っていっても動くかどうかは不明。hannyaさんの方で適切に修正を加える等してください。
また、この回答がhannyaさんが望んでいるモノとはズレている可能性もある。その場合はスルーして。


void saveImage(CDC *pdc, int x, int y, int width, int height, LPCTSTR filepath) {
    CRect rect(x, y, x + width, y + height);
    rect.NormalizeRect();
    CMemDC mem;
    mem.CreateCompatibleDC(pdc);
    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap(pdc, rect.Width(), rect.Height());
    // save image
    CBitmap *prev = mem.SelectObject(&bitmap);
    mem.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, rect.left, rect.top, SRCCOPY);
    mem.SaveJPEG(filepath);
    mem.SelectObject(prev);
}

void CChildView::OnPaint() {
      :

    if( !transfindex) dc.BitBlt(0, 0, m_imageSiH, m_imageSiV, &memDC, 0, 0, SRCCOPY);
    else dc.PlgBlt(points, &memDC, 0, 0, m_imageSiH, m_imageSiV, CBitmap(), 0, 0);//平行四辺形移行

    if( stilImage )//== 1 saving the final still image
    {
        m_imageD_F_Name.Format("KolamImages\\%s-N.jpg", m_strFileTitle); 
        if (transfindex) {
            // points で指定された菱形領域に外接する矩形を求める
            const POINT 4th = {
                points[1].x + points[2].x - points[0].x,
                points[1].y + points[2].y - points[0].y
            }
            CRect rect(
                min(points[0].x, min(points[1].x, min(points[2].x, 4th.x))),
                min(points[0].y, min(points[1].y, min(points[2].y, 4th.y))),
                max(points[0].x, max(points[1].x, max(points[2].x, 4th.x))),
                max(points[0].y, max(points[1].y, max(points[2].y, 4th.y)))
            );
            saveImage(&dc, rect.left, rect.top, rect.Width(), rect.Height(), m_imageD_F_Name);
        }
        else {
            saveImage(&memDC, 0, 0, m_imageSiH, m_imageSiV, m_imageD_F_Name);
        }
        stilImage = 0; // OFF save image
    }
}

編集 削除
hannya  2011-12-29 09:31:23  No: 73068  IP: 192.*.*.*

ありがとうございます
実装しました  結果コンパイル時で  
mem.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, rect.left, rect.top, SRCCOPY);の  'dc' : 定義されていないと出ました。

そこで  &pdc  としたんですが  再度
'BitBlt' : 5 番目の引数を 'class CDC ** ' から 'class CDC *' に変換できません。 (新しい機能 ; ヘルプを参照)     指示された型は関連がありません; 変換には reinterpret_cast、 C スタイル キャストまたは関数スタイルのキャストが必要です
とでました。  如何でしょうか?

また  保存域は 描画の際に調整し  傾斜部は削れることを前提にして、
// points で指定された菱形領域に外接する矩形を求め
ないで  元の 0,0, m_imageSiH,m_imageSiV  とすると  すくし簡単になると思いますので  それで  コードを作ると
如何でしょうか?

編集 削除
hannya  2011-12-29 17:13:40  No: 73069  IP: 192.*.*.*

void CChildView::saveImage(short transfindex, short iik)
{  //iik はアニメ用の通し番号
   POINT plgpnts[3] = { m_imageSiV/7, 0,  m_imageSiV/7 +LONG(m_imageSiH*2/sqrt(3.0) +0.5), 0,  m_imageSiV/7 -LONG(m_imageSiV/sqrt(3.0) +0.5), m_imageSiV }; //五角形変形  下左傾き 
   CPaintDC dc(this); // Screen用のメモリ設定か?  for painting
   CMemDC memDC;  //描画用の不可視なメモリか?
  if( !transfindex) dc.BitBlt(0, 0, m_imageSiH, m_imageSiV, &memDC, 0, 0, SRCCOPY);//Screenに表示する
  else dc.PlgBlt(plgpnts, &memDC, 0, 0, m_imageSiH, m_imageSiV, CBitmap(), 0, 0);//描画用メモリから平行変形でScreenに表示する      
  m_imageD_F_Name.Format("KolamImages\\%s-%03d.jpg", m_strFileTitle,iik); 
  memDC.SaveJPEG(m_imageD_F_Name);//描画用メモリをSavwする
} //endof CChildView::saveImage
上記では(平行変形の像はSaveされない。(領域は元のm_imageSiH, m_imageSiVで良い)
そのためには  助言の  
 saveImage(&dc, rect.left, rect.top, rect.Width(), rect.Height(), m_imageD_F_Name);

のようにdcの領域・像をSaveしないといけないことを理解しました。
さらに助言をお願いします

編集 削除
gak  2012-01-05 13:13:41  No: 73070  IP: 192.*.*.*

> mem.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, rect.left, rect.top, SRCCOPY);の  'dc' : 定義されていないと出ました。
mem.BitBlt(0, 0, rect.Width(), rect.Height(), pdc, rect.left, rect.top, SRCCOPY);
に修正。

> ないで  元の 0,0, m_imageSiH,m_imageSiV  とすると  すくし簡単になると思いますので  それで  コードを作ると
この辺りは hannya さんの望む値を設定すれば良いかと。「菱形領域に外接する矩形」は”例”に過ぎず、此れに執着する必要は無し。

編集 削除
hannya  2012-01-17 10:08:13  No: 73071  IP: 192.*.*.*

ありがとうございます
1:体調くずしており  返事を遅れたことすみません。
2:
  if( transfindex) 
  {
//memDC.SaveJPEG(m_imageD_F_Name); 
saveImagePlg(&dc, 0, 0, m_imageSiH, m_imageSiV, m_imageD_F_Name);           
としたのですが  以前変形前の保存です
さらに実装を検査します

Headerには
void saveImagePlg(CDC *pdc, int x, int y, int width, int height, LPCTSTR filepath);
を入れてある

void saveImagePlg(CDC *pdc, int x, int y, int width, int height, LPCTSTR filepath) {
のままだと  クラスに保存されていないとでるので

///*HexgonTransformedImageSave
void CChildView::saveImagePlg(CDC *pdc, int x, int y, int width, int height, LPCTSTR filepath) 
{
    CRect rect(x, y, x + width, y + height);
    rect.NormalizeRect();
    CMemDC mem;
    mem.CreateCompatibleDC(pdc);
    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap(pdc, rect.Width(), rect.Height());
    // save image
    CBitmap *prev = mem.SelectObject(&bitmap);
    mem.BitBlt(0, 0, rect.Width(), rect.Height(), pdc, rect.left, rect.top, SRCCOPY);
    mem.SaveJPEG(filepath);
    mem.SelectObject(prev);
としたのですが
実行できないでいます

現行の
memDC.SaveJPEG(m_imageD_F_Name);//描画用メモリをSavwする
は  
// MemDC.cpp: implementation of the CMemDC class.
の中の
BOOL CMemDC::SaveJPEG(LPCTSTR lpszPathName, int quality)
{
を使っているようです。

よろしく  ご助言おねがいします

編集 削除
hannya  2012-01-17 16:23:05  No: 73072  IP: 192.*.*.*

追加情報  現行の
// MemDC.cpp: implementation of the CMemDC class.
には以下の関数があります  よろしく    ご助言をねがいます

BOOL CMemDC::SaveJPEG(LPCTSTR lpszPathName, int quality)
{
  JPEG_CORE_PROPERTIES jcprops = {0};

  TRY

    if (ijlInit(&jcprops) != IJL_OK)
    {
      TRACE("Cannot initialize Intel JPEG library\n");
      AfxThrowUserException();
    }

    CSize imageSize = GetBitmapSize();
    jcprops.DIBBytes = (BYTE*)m_pDIBits;
    jcprops.DIBWidth = imageSize.cx;
    jcprops.DIBHeight = -imageSize.cy;
    jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.DIBWidth, jcprops.DIBChannels);
    jcprops.DIBChannels = 3;
    jcprops.DIBColor = IJL_BGR;

    jcprops.JPGFile = lpszPathName;
    jcprops.JPGWidth = imageSize.cx;
    jcprops.JPGHeight = imageSize.cy;

    jcprops.JPGThumbWidth = 100;
    jcprops.JPGThumbHeight = 75;

    jcprops.jquality = quality;

    if (ijlWrite(&jcprops, IJL_JFILE_WRITEWHOLEIMAGE) != IJL_OK)
    {
      TRACE("Cannot write image data to %s file\n", jcprops.JPGFile);
      AfxThrowUserException();
    }
    
    if (ijlFree(&jcprops) != IJL_OK)
    {
      TRACE("Cannot free Intel(R) JPEG library");
    }

  CATCH_ALL(e)

    ijlFree(&jcprops);
    return FALSE;

  END_CATCH_ALL
  
  return TRUE;
}

// MemDC.h: interface for the CMemDC class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MEMDC_H__218E8F1E_92A2_483A_AE5B_C4A475CA4F7E__INCLUDED_)
#define AFX_MEMDC_H__218E8F1E_92A2_483A_AE5B_C4A475CA4F7E__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CMemDC : public CDC
{
public:
// Attributes
  BITMAPINFO m_bitmapInfo;
  void* m_pDIBits;

  CBitmap* m_pMemBitmap;
  CBitmap* m_pOldBitmap;

public:
  CMemDC();
  virtual ~CMemDC();

  BOOL ReleaseMem();

  BOOL CreateCompatibleBitmap(CDC* pDC, int nWidth, int nHeight);
  BOOL CreateDIBitmap(int nWidth, int nHeight);

  CSize GetBitmapSize();

//  int StretchDIBits(CDC* pDC, int XDest, int YDest, int nDestWidth, int nDestHeight, int XSrc, int YSrc, int nSrcWidth, int nSrcHeight, DWORD dwRop);

  BOOL LoadJPEG(LPCTSTR lpszPathName);
  BOOL LoadBMP(LPCTSTR lpszPathName);
  
  BOOL LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName);
  BOOL LoadImage(LPCSTR lpszPathName);

  BOOL SaveJPEG(LPCTSTR lpszPathName, int quality = 100); // changed for animation, from int quality = 75);
  BOOL SaveBMP(LPCTSTR lpszPathName);
};

#endif // !defined(AFX_MEMDC_H__218E8F1E_92A2_483A_AE5B_C4A475CA4F7E__INCLUDED_)

編集 削除
gak  2012-01-17 18:17:24  No: 73073  IP: 192.*.*.*

saveImagePlg() を以下の様にしてみたらどうなるだろう。

void CChildView::saveImagePlg(CDC *pdc, int x, int y, int width, int height, LPCTSTR filepath) 
{
    CRect rect(x, y, x + width, y + height);
    rect.NormalizeRect();
    CMemDC mem;
    mem.CreateCompatibleBitmap(pdc, rect.Width(), rect.Height());
    // save image
    mem.BitBlt(0, 0, rect.Width(), rect.Height(), pdc, rect.left, rect.top, SRCCOPY);
    mem.SaveJPEG(filepath);
}

今回の質問の”解答”は hannya さんが今見ているsource codeの中に多分在る。逆に言えば、其のsource codeを見れない者では回答が困難。そういう類の質問だと思われる。
なので、回答する側としても”曖昧な回答””勘に頼った信頼性の低い回答”しか付け難い。


> ご助言をねがいます
一般的な助言をさせて頂くならば、今は機能を実装する事を優先するよりはsource code内でやっている内容を理解する事に時間を割いた方が最終的にplusになると思う。
# こういうBBSで↑の様な助言に価値があるのかは疑問に思っている。それでも、現状だとsourceの理解を深める事を優先するのが最良の選択肢だと思われる

編集 削除
hannya  2012-01-19 18:50:06  No: 73074  IP: 192.*.*.*

助言ありがとうございます
結果報告します  残念ながら  関数を直したのですが、
まったく実行して  画像保存ファイルがまったく  出ませんでした。

///*HexgonTransformedImageSave
void CChildView::saveImagePlg(CDC *pdc, int x, int y, int width, int height, LPCTSTR filepath) 
{
    CRect rect(x, y, x + width, y + height);
    rect.NormalizeRect();
    CMemDC mem;
 //   mem.CreateCompatibleDC(pdc);
 //   CBitmap bitmap;
 //   bitmap.CreateCompatibleBitmap(pdc, rect.Width(), rect.Height());
    mem.CreateCompatibleBitmap(pdc, rect.Width(), rect.Height());
    // save image
//    CBitmap *prev = mem.SelectObject(&bitmap);
//   mem.BitBlt(0, 0, rect.Width(), rect.Height(), pdc, rect.left, rect.top, SRCCOPY);
  POINT plgpnts[3] = { m_imageSiV/7, 0,  m_imageSiV/7 +LONG(m_imageSiH*2/sqrt(3.0) +0.5), 0,  m_imageSiV/7 -LONG(m_imageSiV/sqrt(3.0) +0.5), m_imageSiV }; //下左傾き 
  mem.PlgBlt(plgpnts, pdc, 0, 0, m_imageSiH, m_imageSiV, CBitmap(), 0, 0);//平行四辺形変形      
    mem.SaveJPEG(filepath);
//   mem.SelectObject(prev);
}//endof saveImagePlg

OnPaintの中で

iani = 0; //save animation image number  
m_imageD_F_Name.Format("KolamImages\\%s-a%03d.jpg", m_strFileTitle, iani++); 
if( !transfindex)  memDC.SaveJPEG(m_imageD_F_Name);
else if( transfindex) 
{
  POINT plgpnts[3] = { m_imageSiV/7, 0,  m_imageSiV/7 +LONG(m_imageSiH*2/sqrt(3.0) +0.5), 0,  m_imageSiV/7 -LONG(m_imageSiV/sqrt(3.0) +0.5), m_imageSiV }; //下左傾き 
  dc.PlgBlt(plgpnts, &memDC, 0, 0, m_imageSiH, m_imageSiV, CBitmap(), 0, 0);//平行四辺形変形      
  saveImagePlg(&dc, 0, 0, m_imageSiH, m_imageSiV, m_imageD_F_Name); //平行四辺形変形}

とあります
変形しないときは  保存されるのですが  変形時は無保存です。
コードを勉強していますが  なかなか(還暦すぎては  言い訳でごめん)
いま  ひとつ  助言をおねがいしたい

編集 削除
gak  2012-01-20 18:25:37  No: 73075  IP: 192.*.*.*

他所で出た CMemDC の全体ソースも見てみたけどさ…
> CMemDC mem;
> mem.CreateCompatibleBitmap(pdc, rect.Width(), rect.Height());
> mem.BitBlt(0, 0, rect.Width(), rect.Height(), pdc, rect.left, rect.top, SRCCOPY);
> mem.SaveJPEG(filepath);
で旨く動かない理由が俺には判らない。机上からソース見ているだけの俺にはサッパリ判らない。

> 画像保存ファイルがまったく  出ませんでした。
どの箇所(関数)で処理が失敗しているかDebugしてみたらどう? そうすれば原因も判ってくるだろう。

> 今回の質問の”解答”は hannya さんが今見ているsource codeの中に多分在る。
hannya さんが持っているソースコードに対して「CreateCompatibleBitmap」若しくは「CreateDIBitmap」という単語を検索してみたら?
多分「CMemDC」の実際の使用例が出てくる。

編集 削除