🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

Q&A

解決済

3回答

10955閲覧

Visual C++ で、HDC に表示された画像を PNG で保存したい

TAKASE_Hiroyuki

総合スコア21

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

0グッド

0クリップ

投稿2019/12/13 09:38

編集2019/12/13 20:53

#概要
いつも御世話になっております。Windows10 で Visual Studio 2019 の C++ を用いて、デクストップ・アプリを作りたいと考えています。以下に引用するようなコードで、次のような作業を行っています。

  1. PNGファイルを裏画面に Load する
  2. 裏画面に、正方形を作図する
  3. 裏画面を、表画面に表示する

このようにして表示した画面を、ふたたびPNGファイルに保存しようと考えています。「BMP画像をPNG画像に変換する」等の情報を参考にして、いろいろと考えているのですが、どうにもうまくいきません。

#現在のコード

C++

1 2LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 3{ 4 switch (message) 5 { 6 case WM_COMMAND: 7 { 8 int wmId = LOWORD(wParam); 9 switch (wmId) 10 { 11 case IDM_ABOUT: 12 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 13 break; 14 15 case IDM_SAVE: 16 // ここで画面を保存したい 17 break; 18 19 case IDM_EXIT: 20 DestroyWindow(hWnd); 21 break; 22 default: 23 return DefWindowProc(hWnd, message, wParam, lParam); 24 } 25 } 26 break; 27 case WM_PAINT: 28 { 29 RECT recDisp; 30 GetClientRect(hWnd, &recDisp); // クライアントを取得 31 int cx = recDisp.right; // クライアントのヨコ 32 int cy = recDisp.bottom; // クライアントのタテ 33 34 // PNGファイルを読み込む 35 CString filePath; 36 CImage* img = new CImage(); 37 filePath = L"sample.png"; 38 img->Load(filePath); 39 int width = img->GetWidth(); 40 int height = img->GetHeight(); 41 42 // ここから実際の描写 43 HDC hdc = GetDC(hWnd); 44 HDC mem = CreateCompatibleDC(hdc); //HDCを取得 45 HBITMAP bmp = CreateCompatibleBitmap(hdc, cx, cy); //HBITMAPを取得 46 HBITMAP obmp = (HBITMAP)SelectObject(mem, bmp); //HBITMAPを関連付ける 47 48 HPEN hpen = CreatePen(PS_SOLID, 5, RGB(0x00, 0x7f, 0xff)); 49 50 // 裏画面に描写する 51 FillRect(mem, &recDisp, br); 52 img->Draw(mem, 0, 0, cx, ( cx * height ) / width, 0, 0, width, height); 53 54 HPEN ohpen = (HPEN)SelectObject(mem, hpen); 55 56 MoveToEx(mem, 50, 50,NULL); 57 LineTo(mem, 150, 50); 58 LineTo(mem, 150, 150); 59 LineTo(mem, 50, 150); 60 LineTo(mem, 50, 50); 61 SelectObject(mem, ohpen); 62 DeleteObject(hpen); 63 64 TextOut(mem, 10, 10, wss.c_str(), (int)wss.length()); 65 66 // 表画面にコピー 67 PAINTSTRUCT ps; 68 BeginPaint(hWnd, &ps); 69 BitBlt(hdc, 0, 0, cx, cy, mem, 0, 0, SRCCOPY); 70 EndPaint(hWnd, &ps); 71 72 // あれこれ削除する。 73 SelectObject(mem, obmp); 74 DeleteObject(bmp); 75 DeleteDC(mem); 76 } 77 break; 78 79 case WM_DESTROY: 80 PostQuitMessage(0); 81 break; 82 83 default: 84 return DefWindowProc(hWnd, message, wParam, lParam); 85 } 86 return 0; 87} 88 89 90

#エラー表示
上のコードの状態では、エラーは表示されません。しかし、「BMP画像をPNG画像に変換する」に掲載されている次のコード

C++

1CLSID encoderClsid; 2Status stat; 3GetEncoderClsid(L"image/png", &encoderClsid); 4stat = image->Save(L"sample2.png", &encoderClsid, NULL);

を、冒頭の「// ここで画面を保存したい」の所に挿入すると、次のようなエラーが表示されます。

error C2065: 'Status': 定義されていない識別子です。

error C2146: 構文エラー: ';' が、識別子 'stat' の前に必要です。
warning C4551: 関数呼び出しに引数リストがありません。
error C3861: 'GetEncoderClsid': 識別子が見つかりませんでした
error C2065: 'image': 定義されていない識別子です。

#お願い

case IDM_SAVE:
// ここで画面を保存したい
break;

のところで、画像を保存するには、どのようにすればよろしいでしょうか。なお、そもそも、WM_PAINT でない場所で「画像を保存する」ということは可能なのだろうか、という疑問もあります。よろしく御回答くださいますよう、お願い申し上げます。

#追加
一番最後の「疑問」についてですが、
0. 画面に表示させたら、その内容を Bitmap 領域に保存しておく
(単なるコピー)。
0. 必要な場合に、そのBitmapをPNGに変換して保存する

という方法で可能かな、と思いました。

#追加その2
CImage で、あれこれ作業するよりも、openCV を使って作業した方が楽なのかなという気がしてきました。(しかし、OpenCV は、まだまったく使ったことがありません)。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

既にMFCのCImageクラスを利用しているのですから、これを使ってもPNGファイルで保存できます。

ご提示のコードのWM_PAINT中の処理でBitBltで画面にビットマップ転送していますが、この段階で描画したい内容がHBITMAP bmpに完成しているということですから、このHBITMAP bmpを利用し、CImageに一時的にAttachした後、CImage.SaveでPNGファイル指定して保存してしまえば良いです。

CImage Class - Microsoft Docs

C++

1// WM_PAINT中の処理 2...省略 3 // 表画面にコピー 4 PAINTSTRUCT ps; 5 BeginPaint(hWnd, &ps); 6 BitBlt(hdc, 0, 0, cx, cy, mem, 0, 0, SRCCOPY); 7 EndPaint(hWnd, &ps); 8 9 // C:\temp\sampleout.png にPNGファイルとして保存 10 const TCHAR outFileName[] = _T("C:/temp/sampleout.png"); 11 CImage imageForSave; 12 13 // HBITMAP bmp = CreateCompatibleBitmap(hdc, cx, cy); 14 // で作成したビットマップハンドルをアタッチ 15 imageForSave.Attach(bmp); 16 imageForSave.Save(outFileName, Gdiplus::ImageFormatPNG); 17 imageForSave.Detach(); 18 19 // あれこれ削除する。 20 SelectObject(mem, obmp); 21 DeleteObject(bmp); 22 DeleteDC(mem); 23 24...省略 25

Windows 7 (64ビット)上で、Visual Studio 2019 で動作確認しましたが、描画内容がPNGファイルで保存されました。

投稿2019/12/14 06:57

dodox86

総合スコア9256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TAKASE_Hiroyuki

2019/12/14 08:07

御回答いただき、ありがとうございました。 実際のところ、 CImage saveImage; saveImage.Attach(bmp); saveImage.Save(L"test.bmp"); saveImage.Save(L"test.jpg"); saveImage.Save(L"test.png"); saveImage.Detach(); このようにして、画像を保存することができました。 ありがとうございました。
guest

0

error C2065: 'Status': 定義されていない識別子です。

gdiplustypes.h を include しては如何かと。

投稿2019/12/14 01:15

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TAKASE_Hiroyuki

2019/12/14 01:41

御回答いただき、ありがとうございます。 Status については、どうやら解決したようです。 しかし、肝心の Save ができません。もう少し、頑張ってみます。
guest

0

ソースが一部しかないので推測ですが

C++

1#include <gdiplus.h> 2using namespace Gdiplus; 3

これがちゃんとヘッダなり、ソースに入っていないのではないでしょうか。StatusはMicrosoft Dev Centerのサイトに説明がありますが、GDI+で使用するenumです。
タイプミスも含めてチェックしてみてください。

GDI+を使うときにはほかにもいろいろお作法があります。それが足りないとビルドが通っても実行時にうまくいかなかったりしますので、そちらも合わせて調査されることをお勧めします。

投稿2019/12/14 00:23

KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TAKASE_Hiroyuki

2019/12/14 01:18

御回答いただき、ありがとうございます。 ソースをすべて示すには、どうすればよいのでしょうか。cpp ファイルだけでなく、リソースファイルもあるので、「どういう書き方をすればよいのか」にいつも悩んでいます。
KoichiSugiyama

2019/12/14 02:12

インクルードしているヘッダファイル部分の情報や、独自に定義しているヘッダファイル(*.h)があればそれも一緒に提示されると良いと思います。
TAKASE_Hiroyuki

2019/12/14 02:17

御回答いただき、ありがとうございました。 独自に定義しているヘッダファイルは、ありません。インクルードしているヘッダファイル部分は、以下のとおりです #include "framework.h" #include "BitBlt_CImage.h" #include "strconv.h" #include "atlimage.h" #include "gdiplus.h" #include <string> using namespace Gdiplus; using namespace std;
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問