|
分類:[.NET 全般]
はじめまして。
Bitmap.LockBits() Bitmap.UnlockBits() を使って画像処理を行うクラスの作成を行っていたのですが、行き詰ってしまいました。
サイズの変更を行わない画像処理であれば問題ないのですが、
画像サイズを変える場合上手くいきません。
画像サイズの変更は、Bitmap.LockBits()で取得したBitmapDataインスタンスのWidth,Height,Strideを変更することで対応しようとしていますが、
自作の処理が終了し、描画に入った時に、以下の症状が発生します。
・元の画像より小さいピクセル数に変更した場合、画像の左上に縮小した画像が表示されるが、画像サイズは変わらない
・元の画像より大きいピクセル数に変更した場合、アプリケーションが終了する。(try〜catchでは捕まらない)
おそらく元のBitmapの大きさが変わっていないため、BitmapとBitmapDataのサイズが不整合を起こしているため発生するのだと思われますが、
BitmapのWidth,HeightはReadonlyのため、対応する方法の見当が付きません。
サイズが変わった場合は変更後のサイズのBitmapを作成し、そちらにコピーするという方法も考えましたが、
出来るのであれば同じBitmapのインスタンスで対応できるのが希望です。
無理、もしくはここを直せばいける、というアドバイスを頂けないでしょうか?
環境
# Windows Vista
# Visual Studio 2008 (C#)
途中に以下の4つのクラスが現われますが、枝葉だと思われますので省かせて頂きました。
NoSizeChangeFilter/SizeChangeFilter/Filter (コメントアウトしているため実際の処理はしてない)
SizeInfo (Width,Height,Stride等を保持するだけ)
public class Manager :IDisposable
{
private Bitmap _bmp;
private BitmapData _bmpData;
private Int32 _width;
private Int32 _height;
private Int32 _stride;
private Int32 _size;
private Int32 _pixelSize = 3;
private Int32 _byteShiftRed = 2;
private Int32 _byteShiftGreen = 1;
private Int32 _byteShiftBlue = 0;
//Format24bppRgbのみ対応
public Manager(Bitmap bmp)
{
_width = bmp.Width;
_height = bmp.Height;
_bmp = bmp;
// Lock
Rectangle rect = new Rectangle(0, 0, _width, _height);
_bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
_stride = _bmpData.Stride;
_size = _stride * _height;
}
#region Dispose
public void Dispose()
{
// Unlock
if ((_bmp != null) && (_bmpData != null))
_bmp.UnlockBits(_bmpData);
}
#endregion
#region フィルタ適用
public void ApplyFilter(List<Filter> filters)
{
if (filters.Count == 0)
return;
// ポインタ取得
IntPtr ptr = _bmpData.Scan0;
// 全Byteを格納する配列作成
byte[] rgbBytes = new byte[_size];
// 配列に全データをコピー
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbBytes, 0, _size);
foreach (var i in filters)
{
if (i == null)
continue;
if (i is NoSizeChangeFilter)
{
//サイズ変更なしフィルタの適用
//キャスト
var f = i as NoSizeChangeFilter;
//フィルタ適用
//f.Apply(this, rgbValues);
}
else if (i is SizeChangeFilter)
{
//サイズ変更ありフィルタの適用
//キャスト
var f = i as SizeChangeFilter;
//変更前の情報を保持
var olfInfo = new SizeInfo(this);
//変更後のサイズを算出
Size newSize = f.ApplyedSize(this);
Int32 newStride = newSize.Width * _pixelSize;
//Strideを4Byte単位に調節
newStride += (newStride % 4 == 0) ? (0) : (4 - newStride % 4);
//サイズ変更
_bmpData.Width = newSize.Width;
_bmpData.Height = newSize.Height;
_bmpData.Stride = newStride;
//メンバ更新
_width = newSize.Width;
_height = newSize.Height;
_stride = _bmpData.Stride;
_size = _stride * _height;
//新しいサイズの配列作成
var newBytes = new Byte[_size];
////フィルタ適用
//f.Apply(this, rgbValues, newValue, olfInfo);
//配列の差し替え
rgbBytes = newBytes;
}
}
// 反映後のデータをbmpのポインタにコピーしなおす
System.Runtime.InteropServices.Marshal.Copy(rgbBytes, 0, ptr, _size);
}
#endregion
}
|