在 IronPython 中使用 Bitmap.LockBits 和 Marshal.Copy 未按预期更改图像

发布于 2024-08-27 05:39:52 字数 2378 浏览 5 评论 0原文

我编写了以下 IronPython 代码:

import clr
clr.AddReference("System.Drawing")
from System import *
from System.Drawing import *
from System.Drawing.Imaging import *

def NoWorko(bitmap):
    bmData = bitmap.LockBits(Rectangle(0, 0, bitmap.Width, bitmap.Height), 
        ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)

    total_bytes = (bmData.Stride) * bmData.Height
    rgbValues = Array.CreateInstance(Byte, total_bytes)
    Runtime.InteropServices.Marshal.Copy(bmData.Scan0, rgbValues, 0, total_bytes)
    for i in rgbValues:
        i = 255 - i

    #The following line doesn't appear to actually copy the bits back
    Runtime.InteropServices.Marshal.Copy(rgbValues, 0, bmData.Scan0, total_bytes)
    bitmap.UnlockBits(bmData)

originalImage = Bitmap("Test.bmp")
newPic = NoWorko(originalImage)
newPic.Save("New.bmp")

这是我对此 MSDN 代码示例的解释: http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx除了我保存更改后的位图而不是在表单中显示它。

代码运行,但是新保存的位图是原始图像的精确副本,没有发生任何更改的迹象(它应该创建红色色调)。谁能告诉我我的代码有什么问题吗?

我使用的图像只是我在 Paint 中创建的 24bpp 位图(它只是一个大的白色矩形!),使用 IronPython 2.6 并在 Windows 7 (x64) 上使用已安装 .Net Framework 3.5 SP1。

更新

有人指出我在尝试向白色图像添加红色色调时的愚蠢行为 - 所以现在代码只是反转颜色。我已经在许多图像上尝试过此操作,但似乎没有任何效果。

但是,以下(非常相似)C# 程序:

public static void Main(string[] args)
        {
            Bitmap bitmap = new Bitmap("nTest.jpg");
            BitmapData bmData = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), 
                    ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int total_bytes = (bmData.Stride) * bmData.Height;
            byte[] rgbValues = new byte[total_bytes];

            Marshal.Copy(bmData.Scan0, rgbValues, 0, total_bytes);

            for(int i = 0; i < total_bytes; i++)
            {
                rgbValues[i] = (byte)(255 - rgbValues[i]);
            }

            Marshal.Copy(rgbValues, 0, bmData.Scan0, total_bytes);
            bitmap.UnlockBits(bmData);

            bitmap.Save("nNew.jpg");

        }

适用于我尝试过的所有图像。

调用有关。

Runtime.InteropServices.Marshal.Copy(rgbValues, 0, bmData.Scan0, ​​bytes)

我不确定,但这似乎与导致问题的 IPY 中的

I have written the following IronPython code:

import clr
clr.AddReference("System.Drawing")
from System import *
from System.Drawing import *
from System.Drawing.Imaging import *

def NoWorko(bitmap):
    bmData = bitmap.LockBits(Rectangle(0, 0, bitmap.Width, bitmap.Height), 
        ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)

    total_bytes = (bmData.Stride) * bmData.Height
    rgbValues = Array.CreateInstance(Byte, total_bytes)
    Runtime.InteropServices.Marshal.Copy(bmData.Scan0, rgbValues, 0, total_bytes)
    for i in rgbValues:
        i = 255 - i

    #The following line doesn't appear to actually copy the bits back
    Runtime.InteropServices.Marshal.Copy(rgbValues, 0, bmData.Scan0, total_bytes)
    bitmap.UnlockBits(bmData)

originalImage = Bitmap("Test.bmp")
newPic = NoWorko(originalImage)
newPic.Save("New.bmp")

Which is my interpretation of this MSDN code sample: http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx except that I am saving the altered bitmap instead of displaying it in a Form.

The code runs, however the newly saved bitmap is an exact copy of the original image with no sign of any changes having occurred (it's supposed to create a red tint). Could anyone advise what's wrong with my code?

The image I'm using is simply a 24bpp bitmap I created in Paint (it's just a big white rectangle!), using IronPython 2.6 and on Windows 7 (x64) with .Net Framework 3.5 SP1 installed.

Update

My foolishness has been pointed out in trying to add a red tint to a white image - so now the code simply inverts the colours. I've tried this on a number of images, but it just doesn't seem to have any effect.

However, the following (very similar) C# program:

public static void Main(string[] args)
        {
            Bitmap bitmap = new Bitmap("nTest.jpg");
            BitmapData bmData = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), 
                    ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int total_bytes = (bmData.Stride) * bmData.Height;
            byte[] rgbValues = new byte[total_bytes];

            Marshal.Copy(bmData.Scan0, rgbValues, 0, total_bytes);

            for(int i = 0; i < total_bytes; i++)
            {
                rgbValues[i] = (byte)(255 - rgbValues[i]);
            }

            Marshal.Copy(rgbValues, 0, bmData.Scan0, total_bytes);
            bitmap.UnlockBits(bmData);

            bitmap.Save("nNew.jpg");

        }

Worked on all the images I've tried.

I'm not sure, but it seems to be something to do with the call to:

Runtime.InteropServices.Marshal.Copy(rgbValues, 0, bmData.Scan0, bytes)

in IPY that is causing the problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

策马西风 2024-09-03 05:39:52

我不懂Python,所以我不知道

for i in rgbValues[::3]: 
        i = 255 

应该如何工作。但如果它实际上将每个第三个字节设置为 255,则会遇到两个问题:

  1. 您不能通过将其红色分量设置为 255 来为白色赋予红色色调,因为它已经具有该值。你必须减少蓝色和绿色成分。
  2. 当格式为 24bpp 时(它可以适用于 32bpp),您无法编写尝试立即更改位图所有像素的代码。您必须逐行扫描。

I don't know Python, so I have no idea how

for i in rgbValues[::3]: 
        i = 255 

is supposed to work. But provided that it actually sets each third byte to 255 you have two problems:

  1. You cannot give the color white a red tint by setting it's red component to 255, since it already has that value. You have to decrease the blue and green components instead.
  2. You cannot write code that tries to alter all the pixels of a bitmap at once, when your format is 24bpp (it would work with 32bpp). You must do it scan line by scan line.
雨的味道风的声音 2024-09-03 05:39:52

感谢 danbystrom 让我去检查一下——当我确信我做对了时,我的 for 循环语法完全混淆了。正确的语法应该是:

for y in range(bmData.Height):
    for x in range(bmData.Width):
        rgbValues[(bmData.Stride * y) + (3 * x) +2] = 255

D'oh!但这只是表明让其他人质疑你在做什么的好处:)

Thanks to danbystrom for making me go and check this - it was my for loop syntax that was all mixed up, when I was certain I'd got it right. The correct syntax should have been:

for y in range(bmData.Height):
    for x in range(bmData.Width):
        rgbValues[(bmData.Stride * y) + (3 * x) +2] = 255

D'oh! But it just goes to show the benefit of having other people question what you're doing :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文