gpt4 book ai didi

c# - 如何有效裁剪 *indexed* 位图并获得 *indexed* 结果?

转载 作者:行者123 更新时间:2023-11-30 12:26:46 24 4
gpt4 key购买 nike

如果您是因为标题来到这里,您可能应该跳过问题直接找到答案。原来我的代码中有一个简单的错误。

我正在尝试专门处理索引图像,因为我的项目的主要部分涉及调色板交换。作为更大过程的一部分,我尝试了以下几行代码:

        Bitmap raw = ((Bitmap)i).Clone(region, PixelFormat.Format8bppIndexed);
byte transparent = (byte)(Array.FindIndex(raw.Palette.Entries, x => x.A < 128));
// Scan the bitmap for the first opaque pixel on each side
BitmapData bd = raw.LockBits(region, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

基本上,我想裁剪输入的指定区域,然后对图像的那部分进行低级操作。

转换成功(此时我可以验证它是一个索引位图,但它存储在控件中,因此类型信息丢失)。克隆调用似乎成功了。调试发现rawPixelFormat确实是PixelFormat.Format8bppIndexed(Bitmap)i也是这样.透明调色板索引的计算工作正常。但是随后 raw.LockBits 失败,提示参数无效。

更奇怪的是,如果我删除 .Clone 调用,raw.LockBits 将成功(但其余代码将做错事,因为源代码没有被裁剪)。

根据 this answer , 似乎带有参数的 Clone 产生了对原始数据的某种 View ,而不是实际复制它,因此没有适当的数据供 LockBits 锁定- 它不一定是连续的。但是我如何明确复制该区域?通常的 Graphics.DrawImage 方法不会直接起作用,因为所需的目标图像已编入索引,所以我无法为其获取 Graphics。

我真的必须在 RGB 模式下完成所有工作然后再转换回来吗?肯定有更优雅的东西

最佳答案

根据@Peter Duniho 的评论和一些进一步的测试和调试,我确定实际上我只是在代码中有一个错误。结论:.Clone() 方法工作得很好,正是这里所需要的:

Bitmap cropped = original.Clone(region, PixelFormat.Format8bppIndexed);

或者更笼统一点,

Bitmap cropped = original.Clone(region, original.PixelFormat);

其中 region 是所需的裁剪 Rectangle。我的代码的问题是,在随后的 LockBits 代码中,region 不正确 - 要锁定整个裁剪图像,我想要与 相同的宽度和高度>矩形,但 X 和 Y 为 (0, 0)。

经过更多测试后,我针对此处可能遇到的错误制定了以下注释:

  • 如果您尝试使用不适合 Bitmap 矩形的 region - 即 XY 为负数,或者 X + Width 超过了 BitmapWidth,或者 Y + Height 超出了 Bitmap 的高度 - 它不会被裁剪到原始 Bitmap 的边界,而是会发生异常。 负的宽度和高度值也是无效的

  • 如果 Bitmap.LockBitsregion 宽度为零、高度为零或不适合,它将引发 System.ArgumentException。消息只是“参数无效”。 无论哪种方式,因此您需要找出问题所在。

  • 如果 Bitmap.Cloneregion 宽度为零或高度为零,您将再次得到 System.ArgumentException,这次带有实际信息性错误消息。但是,如果它不适合,您将得到一个 System.OutOfMemoryException。这有点有趣,因为 0 的宽度和高度值显然得到了显式检查,但负值却没有。

所以也许我们应该使用一个小函数来防止这种情况,比如:

// Create a cropped `region` of the `original` Bitmap as a new bitmap,
// preserving the original pixel format. If negative Width or Height
// are provided for the clip region and `flipNegative` is set, the result
// is flipped accordingly.
public Bitmap crop(Bitmap original, Rectangle region, bool flipNegative) {
Rectangle bounds = new Rectangle(new Point(0, 0), original.Size);
if (region.Width == 0 || region.Height == 0) { return null; }

// Normalize width and height parameters,
// and track whether we might need to flip.
bool flipHorizontal = region.Width < 0;
bool flipVertical = region.Height < 0;
if (flipHorizontal)
{
region.X += region.Width;
region.Width = -region.Width;
}
if (flipVertical)
{
region.Y += region.Height;
region.Height = -region.Height;
}

// Ensure we have a valid clipping rectangle, and make the GDI call.
if (!region.IntersectsWith(bounds)) { return null; }
region.Intersect(bounds);
Bitmap result = original.Clone(region, original.PixelFormat);

// Flip the result as appropriate.
if (flipHorizontal && flipNegative)
{
result.RotateFlip(RotateFlipType.RotateNoneFlipX);
}
if (flipVertical && flipNegative)
{
result.RotateFlip(RotateFlipType.RotateNoneFlipY);
}
return result;
}

(我提供了 flipNegative 参数,因为可以想象,您可能想要任一语义。)

至于LockBits,这里没有必要,尽管它对于更底层的操作仍然有用。

关于c# - 如何有效裁剪 *indexed* 位图并获得 *indexed* 结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27596660/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com