Пиксельная манипуляция в CGBitmapContext зависит от суперпредставления представления?

Я столкнулся с чем-то действительно странным, когда манипулировал пикселями с помощью CGBitmapContext. В основном я изменяю альфа-значения PNG. У меня есть пример, где я могу успешно обнулить альфа-значение пикселя PNG, за исключением случаев, когда моим суперпредставлением ImageView является ImageView с изображением… Почему это так? Я не уверен, что это ошибка или что-то в контексте настроено неправильно.

Ниже приведен пример. Он успешно обнуляет альфа-значения, но когда вы предоставляете UIImageView суперпредставления изображение, оно работает неправильно. Пиксели, которые должны иметь альфа-ноль, слегка видны. Но когда вы удаляете изображение из UIImageView суперпредставления, значения Alpha обнуляются правильно, вы отлично видите белый фон за ним. Я пытался использовать несколько разных CGBlendModes, но, похоже, этого не происходит.

Вот ссылка на Dropbox для примера проекта, демонстрирующего это странное событие: https://www.dropbox.com/s/e93hzxl5ru5wnss/TestAlpha.zip

А вот код, скопированный / вставленный:

        // Create a Background ImageView
        UIImageView Background = new UIImageView(this.View.Bounds);
        // Comment out the below line to see the Pixels alpha values change correctly, UnComment the below line to see the pixel's alpha values change incorrectly.  Why is this?  
        // When Commented out, The pixels whose alpha value I set to zero become transparent and I can see the white background through the image.  
        // When Commented in, I SHOULD see the "GrayPattern.png" Image through the transparent pixels.  I can kind of see it, but for some reason I still see the dirt pixels who's alpha is set to zero!  Is this a bug?  Is the CGBitmapContext set up incorrectly?  
        Background.Image = UIImage.FromFile("GrayPattern.png");
        this.View.AddSubview(Background);



        UIImageView MyImageView = new UIImageView(UIScreen.MainScreen.Bounds);
        UIImage sourceImage = UIImage.FromFile("Dirt.png");
        MyImageView.Image = sourceImage;
        Background.AddSubview(MyImageView);


        CGImage image = MyImageView.Image.CGImage;
        Console.WriteLine(image.AlphaInfo);
        int width = image.Width;
        int height = image.Height;
        CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB();
        int bytesPerRow = image.BytesPerRow;
        int bytesPerPixel = bytesPerRow / width;
        int bitmapByteCount = bytesPerRow * height;
        int bitsPerComponent = image.BitsPerComponent;
        CGImageAlphaInfo alphaInfo = CGImageAlphaInfo.PremultipliedLast;

        // Allocate memory because the BitmapData is unmanaged
        IntPtr BitmapData = Marshal.AllocHGlobal(bitmapByteCount);

        CGBitmapContext context = new CGBitmapContext(BitmapData, width, height, bitsPerComponent, bytesPerRow, colorSpace, alphaInfo);
        context.SetBlendMode(CGBlendMode.Copy);
        context.DrawImage(new RectangleF(0, 0, width, height), image);



        UIImageView MyImageView_brush = new UIImageView(new RectangleF(0, 0, 100, 100));
        UIImage sourceImage_brush = UIImage.FromFile("BB_Brush_Rect_MoreFeather.png");
        MyImageView_brush.Image = sourceImage_brush;
        MyImageView_brush.Hidden = true;
        Background.AddSubview(MyImageView_brush);


        CGImage image_brush = sourceImage_brush.CGImage;
        Console.WriteLine(image_brush.AlphaInfo);
        int width_brush = image_brush.Width;
        int height_brush = image_brush.Height;
        CGColorSpace colorSpace_brush = CGColorSpace.CreateDeviceRGB();
        int bytesPerRow_brush = image_brush.BytesPerRow;
        int bytesPerPixel_brush = bytesPerRow_brush / width_brush;
        int bitmapByteCount_brush = bytesPerRow_brush * height_brush;
        int bitsPerComponent_brush = image_brush.BitsPerComponent;
        CGImageAlphaInfo alphaInfo_brush = CGImageAlphaInfo.PremultipliedLast;

        // Allocate memory because the BitmapData is unmanaged
        IntPtr BitmapData_brush = Marshal.AllocHGlobal(bitmapByteCount_brush);

        CGBitmapContext context_brush = new CGBitmapContext(BitmapData_brush, width_brush, height_brush, bitsPerComponent_brush, bytesPerRow_brush, colorSpace_brush, alphaInfo_brush);
        context_brush.SetBlendMode(CGBlendMode.Copy);
        context_brush.DrawImage(new RectangleF(0, 0, width_brush, height_brush), image_brush);


        for ( int x = 0; x < width_brush; x++ )
        {
            for ( int y = 0; y < height_brush; y++ )
            {

                int byteIndex_brush = (bytesPerRow_brush * y) + x * bytesPerPixel_brush;
                byte alpha_brush = GetByte(byteIndex_brush+3, BitmapData_brush);
                // Console.WriteLine("alpha_brush = " + alpha_brush);

                byte setValue = (byte)(255 - alpha_brush);
                // Console.WriteLine("setValue = " + setValue);

                int byteIndex = (bytesPerRow * y) + x * bytesPerPixel;

                SetByte(byteIndex+3, BitmapData, setValue);

            }
        }

        // Set the MyImageView Image equal to the context image, but I still see all top image, I dont' see any bottom image showing through.  
        MyImageView.Image = UIImage.FromImage (context.ToImage());


        context.Dispose();
        context_brush.Dispose();

        // Free memory used by the BitmapData now that we're finished
        Marshal.FreeHGlobal(BitmapData);
        Marshal.FreeHGlobal(BitmapData_brush);







    public unsafe byte GetByte(int offset, IntPtr buffer)
    {
        byte* bufferAsBytes = (byte*) buffer;
        return bufferAsBytes[offset];
    }


    public unsafe void SetByte(int offset, IntPtr buffer, byte setValue)
    {
        byte* bufferAsBytes = (byte*) buffer;
        bufferAsBytes[offset] = setValue;
    }   

Обновление Я нашел обходной путь (хотя его производительность довольно неприемлема для того, что я делаю) Обходным путем является просто получение изображения результата из моего кода выше, преобразование его в NSData, а затем преобразование NSData обратно в UIIMage. Волшебно изображение выглядит правильно! Этот обходной путь, однако, неприемлем для того, что я делаю, потому что буквально требуется 2 секунды, чтобы сделать это с моим изображением, и это слишком долго для моего приложения. Пара сотен мс было бы весело, но 2 секунды - это слишком долго для меня. Если это ошибка, надеюсь, она будет решена!

Вот обходной (плохая производительность) код. Просто добавьте этот код в конец кода выше (или скачайте мой проект dropbox, добавьте этот код в конец и запустите):

        NSData test = new NSData();
        test = MyImageView.Image.AsPNG();
        UIImage workAroundImage = UIImage.LoadFromData(test);
        MyImageView.Image = workAroundImage;

Вот фотографии до и после. До не обходится, После включает в себя обход.

Обратите внимание, что Серый не появляется полностью. Он покрыт чем-то светло-коричневым, как будто значение альфа не обнуляется.

Обратите внимание, что с помощью обходного пути вы можете видеть серый отлично и отчетливо, без светло-коричневого на нем вообще. Единственное, что я сделал, - конвертировал изображение в NSData, а затем снова в UIImage! Очень странно...

0 ответов

Другие вопросы по тегам