DIB回転
-
勉強中
DIB回転
C言語習いたてです。質問の意図が不明でしたら大変申し訳ありません。
BitmapをDIB形式で読み込んで表示されることはできました。
以下のURLを参考にしました。
http://www.alpha-net.ne.jp/users2/uk413/vc/VCT_DIB.html
表示した画像を右に90度回転させたいのですが
・DWORD biWidth⇔DWORD biHeightを入れ替える
・DIB形式は左下から始まることに注意する
・領域外アクセスに注意する
上記は気にしてやっているつもりですが実行すると90度回転しますが
上のほうにゴミのようなものがついてしまいます。
なにか心当たりありますでしょうか?
情報不足で申し訳ありません。。
BitmapをDIB形式で読み込んで表示されることはできました。
以下のURLを参考にしました。
http://www.alpha-net.ne.jp/users2/uk413/vc/VCT_DIB.html
表示した画像を右に90度回転させたいのですが
・DWORD biWidth⇔DWORD biHeightを入れ替える
・DIB形式は左下から始まることに注意する
・領域外アクセスに注意する
上記は気にしてやっているつもりですが実行すると90度回転しますが
上のほうにゴミのようなものがついてしまいます。
なにか心当たりありますでしょうか?
情報不足で申し訳ありません。。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: DIB回転
縦と横は同じ大きさの画像でしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: DIB回転
その場合は、拡縮してやるとか隙間を埋めるとか結構面倒な事が必要となります。勉強中 さんが書きました:回答ありがとうございます。
サイズは異なります。
横と縦同じ大きさのBitmapの場合は正常に回転させることはできました。
あるいは、複数のブロックに分割するとかですね。これも面倒ですね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: DIB回転
今の現状コードを貼り付けてもらえますか?
codeタグを忘れないようにお願いします。 http://dixq.net/board/board.html
codeタグを忘れないようにお願いします。 http://dixq.net/board/board.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: DIB回転
もしかして、1ライン分のピクセルデータバイト数が4バイト境界に切り上げられるのを考慮していないとか?
-
勉強中
Re: DIB回転
回答ありがとうございます。確かに考慮していませんm(_ _)m
何故考慮しなければいけないのかと考えてしまう私の知識レベルです。
ちょっと長いですがコード添付します。
MFCで作成しております。変更を加えたViewと自分で追加したcppを添付します。
回転させているbitmapはペイントでサイズを96×35にして黄緑で塗り潰したものです。
何故考慮しなければいけないのかと考えてしまう私の知識レベルです。
ちょっと長いですがコード添付します。
MFCで作成しております。変更を加えたViewと自分で追加したcppを添付します。
回転させているbitmapはペイントでサイズを96×35にして黄緑で塗り潰したものです。
//------------------------------------------------------------------------
//-----------------ControlDrawView.cpp-----------------------------
BITMAPINFOHEADER BI = {0};
BITMAPFILEHEADER Header = {0};
UINT8 *Bits = {0};
UINT8 *BackUp = {0};
LONG BIW = 0;
LONG BIH = 0;
// CControlDrawView
IMPLEMENT_DYNCREATE(CControlDrawView, CView)
BEGIN_MESSAGE_MAP(CControlDrawView, CView)
// 標準印刷コマンド
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_COMMAND(ID_32771, &CControlDrawView::OnOpenFile)
ON_COMMAND(ID_32772, &CControlDrawView::Change_RGB)
ON_COMMAND(ID_32773, &CControlDrawView::OnRotate90)
END_MESSAGE_MAP()
// CControlDrawView コンストラクション/デストラクション
CControlDrawView::CControlDrawView()
{
// TODO: 構築コードをここに追加します。
}
CControlDrawView::~CControlDrawView()
{
}
BOOL CControlDrawView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを
// 修正してください。
return CView::PreCreateWindow(cs);
}
// CControlDrawView 描画
int flag = 0;
void CControlDrawView::OnDraw(CDC* pDC)
{
CControlDrawDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: この場所にネイティブ データ用の描画コードを追加します。
int pointx = 100;
int pointy = 100;
::StretchDIBits(pDC->GetSafeHdc(),pointx, pointy, BI.biWidth,BI.biHeight, \
0,0,BI.biWidth,BI.biHeight,Bits,(BITMAPINFO*)&BI,DIB_RGB_COLORS,SRCCOPY);
if (flag){
::StretchDIBits(pDC->GetSafeHdc(),pointx * 2, pointy * 2, BI.biWidth,BI.biHeight, \
0,0,BI.biWidth,BI.biHeight,Bits,(BITMAPINFO*)&BI,DIB_RGB_COLORS,SRCCOPY);
}
#if 0 //回転可能だがあとあと困るかも
if (flag) {
for(int i = 0; i < BIW; i++){
for(int j = 0; j < BIH; j++){
pDC->SetPixel(pointy + j, pointx + BIW -1-i,pDC->GetPixel(i,j));
}
}
}
#endif
}
// CControlDrawView 印刷
BOOL CControlDrawView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 既定の印刷準備
return DoPreparePrinting(pInfo);
}
void CControlDrawView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 印刷前の特別な初期化処理を追加してください。
}
void CControlDrawView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 印刷後の後処理を追加してください。
}
// CControlDrawView 診断
#ifdef _DEBUG
void CControlDrawView::AssertValid() const
{
CView::AssertValid();
}
void CControlDrawView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CControlDrawDoc* CControlDrawView::GetDocument() const // デバッグ以外のバージョンはインラインです。
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CControlDrawDoc)));
return (CControlDrawDoc*)m_pDocument;
}
#endif //_DEBUG
// CControlDrawView メッセージ ハンドラー
void CControlDrawView::OnOpenFile()
{
// TODO: ここにコマンド ハンドラー コードを追加します。
CFile Srcfile;
CFileDialog FileDialog(TRUE);
CString BmpFileName;
if(FileDialog.DoModal() == IDOK){
BmpFileName = FileDialog.GetPathName();
Srcfile.Open(BmpFileName, CFile::modeRead | CFile::shareDenyNone);
Srcfile.Read(&Header, sizeof(BITMAPFILEHEADER));
Srcfile.Read(&BI, sizeof(BITMAPINFOHEADER));
//ファイルサイズ分の領域を確保
Bits = (UINT8 *)malloc(BI.biSizeImage);
BackUp = (UINT8 *)malloc(BI.biSizeImage);
BIW = BI.biWidth;
BIH = BI.biHeight;
Srcfile.Read(Bits, BIW * BIH * 3);
Srcfile.Close();
this->RedrawWindow();
free(Bits);
free(BackUp);
}
}
void CControlDrawView::Change_RGB()
{
// TODO: ここにコマンド ハンドラー コードを追加します。
UINT8 ColorTemp;
for (int i = 0; i < BIW * BIH * 3; i+=3)
{
ColorTemp = Bits[i];
Bits[i] = Bits[i + 1];
Bits[i + 1] = Bits[i + 2];
Bits[i + 2] = ColorTemp;
}
this->RedrawWindow();
}
void CControlDrawView::OnRotate90()
{
// TODO: ここにコマンド ハンドラー コードを追加します。
int w, h;
unsigned char r = 0, g = 0, b = 0;
LONG tempsize = 0;
CopyBits(BackUp, Bits, BIW, BIH);
#if 1
tempsize = BI.biWidth;
BI.biWidth = BI.biHeight;
BI.biHeight = tempsize;
flag = 1;
for(w = 0; w < BI.biHeight; w++){
for(h = 0; h < BI.biWidth; h++){
GetRotateBits(w, h, BI.biHeight, BI.biWidth, &r, &g, &b);
SetBitmapBits(h, w, BI.biHeight, BI.biWidth, r, g, b);
//Bits[BIH * 3 * i + j * 3] = Bits[BIW * 3 * i + j * 3];
r = 0;
g = 0;
b = 0;
}
}
#endif
this->RedrawWindow();
}
//------------------------------------------------------------------------
//-----------------common.cpp----------------------------------------
#include "stdafx.h"
#include "math.h"
void CopyBits(UINT8 *src, UINT8 *dst, LONG Width, LONG Height)
{
int i, j;
for(i = 0; i < Width; i++){
for(j = 0; j < Height; j++){
src[Width * j * 3 + i * 3] = dst[Height * j * 3 + i * 3];
src[Width * j * 3 + i * 3 + 1] = dst[Height * j * 3 + i * 3 + 1];
src[Width * j * 3 + i * 3 + 2] = dst[Height * j * 3 + i * 3 + 2];
}
}
double x = cos(1.00);
}
void SetBitmapBits(int x, int y, LONG Width, LONG Height, UINT8 r,UINT8 g,UINT8 b)
{
Bits[(Height ) * y * 3 + (x ) * 3] = b;
Bits[(Height ) * y * 3 + (x ) * 3 + 1] = g;
Bits[(Height ) * y * 3 + (x ) * 3 + 2] = r;
}
// CDrawStudyView メッセージ ハンドラ
void GetRotateBits(int x, int y, LONG Width, LONG Height, UINT8* r,UINT8* g,UINT8* b)
{
*b = BackUp[(Width -1 - x) * 3 + y * Width * 3];
*g = BackUp[(Width -1 - x) * 3 + 1 + y * Width * 3];
*r = BackUp[(Width -1 - x) * 3 + 2 + y * Width * 3];
}
//------------------------------------------------------------------------
//-----------------common.h------------------------------------------
#ifndef _COMMMON_H
#define _COMMMON_H
typedef unsigned char UINT8;
extern BITMAPINFOHEADER BI;
extern BITMAPFILEHEADER Header;
extern UINT8 *Bits;
extern UINT8 *BackUp;
extern void CopyBits(UINT8 *src, UINT8 *dst, LONG Width, LONG Height);
extern void SetBitmapBits(int x, int y, LONG Width, LONG Height, UINT8 r,UINT8 g,UINT8 b);
extern void GetRotateBits(int x, int y, LONG Width, LONG Height, UINT8* r,UINT8* g,UINT8* b);
#endif //_COMMMON_H
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: DIB回転
すいません。明日また検討の上で回答しますね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: DIB回転
1ピクセルがBGRの3バイトで構成されているビットマップを前提とします。
#読み込み時にチェックしたほうが良いのでは。
サイズが96x35の場合、1ラインは96*3バイトで288バイトです。
288はちょうど4で割り切れるので、詰め物はありません。
ビットマップのイメージのサイズは288x35で10080バイトです。
サイズが35x96の場合、1ラインは35x3バイトで105バイトです。
4で割り切れないので切り上げて108バイトになります。
1ラインごとに3バイトの詰め物が入ります。
ビットマップのイメージのサイズは108x96で10368バイトになります。
縦横のサイズを入れ替えるときイメージ本体のサイズも変えなければなりません。
とうぜんピクセルデータの配置も変わります。
対応策はいくつかあります。
いずれもBITMAPINFOHEADERとイメージ本体を加工します。
#読み込み時にチェックしたほうが良いのでは。
サイズが96x35の場合、1ラインは96*3バイトで288バイトです。
288はちょうど4で割り切れるので、詰め物はありません。
ビットマップのイメージのサイズは288x35で10080バイトです。
サイズが35x96の場合、1ラインは35x3バイトで105バイトです。
4で割り切れないので切り上げて108バイトになります。
1ラインごとに3バイトの詰め物が入ります。
ビットマップのイメージのサイズは108x96で10368バイトになります。
縦横のサイズを入れ替えるときイメージ本体のサイズも変えなければなりません。
とうぜんピクセルデータの配置も変わります。
対応策はいくつかあります。
いずれもBITMAPINFOHEADERとイメージ本体を加工します。
- 回転の度に作り直す
- ビットマップファイル読み込み時に、詰め物バイトの影響を受けないサイズに調整する
※回転時に余白を考慮する必要あり - ビットマップファイル読み込み時に、1ピクセル4バイト(の倍数)のフォーマットに変換する
※回転時には何も考慮する必要なし