Использование WriteableBitmap для изменения пикселей изображения JPG - PullRequest
0 голосов
/ 16 мая 2018

Я довольно новичок в программировании на C # и WPF.В настоящее время я пытаюсь выяснить, как изменить изображение JPG, используя WriteableBitmap.Я думаю, что у меня есть общее представление о том, что происходит, но я наблюдаю странное поведение, которое я просто не понимаю.

Вот ситуация, основанная на примере кода ниже: если я объявлю WriteableBitmap с помощью конструктора, который в данный момент закомментирован (в строке 29), я могу изменить пиксели и нарисовать черную область с красным квадратом вэто с помощью показанного кода.Это мой рабочий тестовый пример для установки и записи пикселей.

Однако, если я закомментирую строку 29 и создам WriteableBitmap, используя вместо этого изображение JPG (как оно в настоящее время закодировано - см. Строку 31), само изображениезагружается нормально, но красный квадрат и черный квадрат, которые я пытаюсь перезаписать (и которые работали ранее), больше не появляются.

Может кто-нибудь объяснить, почему это происходит?Во втором методе я не объявляю значения для параметров dPiX и dPiY, и я не могу нигде указать PixelFormat BGRA32.Поскольку они доступны только для чтения, я не могу их изменять.Это источник моей проблемы?И если так, есть ли способ это исправить?

Я чувствую, что это нечто фундаментальное, что я просто упускаю из виду.Любое руководство будет с благодарностью.Заранее спасибо за ваше время.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Drawing;
using System.IO;

namespace AsciiArt
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //Test code to load a JPG and then write over top of it using writeable bitmaps
        private void SampleWriteableBitmap()
        {
            // Create a writeable bitmap (which is a valid WPF image source
            //WriteableBitmap wbmap = new WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgra32, null);

        WriteableBitmap wbmap = ConvertToBitmap("../../photos/Image1.JPG");

        //  Overwriting the image by making all pixels black -- a silly test I know.
        for (int x = 0; x < wbmap.PixelWidth; ++x)
        {
            for (int y = 0; y < wbmap.PixelHeight; ++y)
            {
                // apply pixels to bitmap
                //Colors are A, Red, Green, Blue.  A must be 255 to be opaque
                //                                                  A    R  G  B
                SetPixel(wbmap, x, y, System.Drawing.Color.FromArgb(255, 0, 0, 0));
            }
        }

        // and then creating a smaller block of a different color -- again as  a test.
        for (int x = 0; x < 20; ++x)
        {
            for (int y = 0; y < 20; ++y)
            {
                // apply pixels to bitmap
                //Colors are A, Red, Green, Blue.  A must be 255 to be opaque
                //                                                   A    R  G  B
                SetPixel(wbmap, x, y, System.Drawing.Color.FromArgb(255, 255, 0, 0));
            }
        }

        // Display some parameters for debugging...
        ByteReadData.Text = "wbmap.PixelHeight: " + wbmap.PixelHeight + "    wbmap.PixelWidth: " + 
            wbmap.PixelWidth + "   wbmap.Format: " + wbmap.Format.BitsPerPixel + " ---> " + 
            wbmap.PixelHeight * wbmap.PixelWidth * wbmap.Format.BitsPerPixel / 8 + "   wbmap.dpix: " + wbmap.DpiX + "   wbmap.dpiy: " + wbmap.DpiY;

        // set image source to the new bitmap
        convertedPhoto.Source = wbmap;
    }

    // function to convert a JPG or other file type to a Bitmap
    public WriteableBitmap ConvertToBitmap(string fileName)
    {
        BitmapImage bitmap = new BitmapImage(new Uri(fileName, UriKind.Relative));
        WriteableBitmap newbitmap = new WriteableBitmap(bitmap);

        return newbitmap;
    }

    public void SetPixel(WriteableBitmap wbm, int x, int y, System.Drawing.Color c)
    {
        if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1) return;
        if (y < 0 || x < 0) return;
        if (!wbm.Format.Equals(PixelFormats.Bgra32)) return;
        wbm.Lock();
        IntPtr buff = wbm.BackBuffer;
        int Stride = wbm.BackBufferStride;
        unsafe
        {
            byte* pbuff = (byte*)buff.ToPointer();
            int loc = y * Stride + x * 4;
            pbuff[loc] = c.B;
            pbuff[loc + 1] = c.G;
            pbuff[loc + 2] = c.R;
            pbuff[loc + 3] = c.A;
        }
        wbm.AddDirtyRect(new Int32Rect(x, y, 1, 1));
        wbm.Unlock();
    }

    public MainWindow()
    {
        InitializeComponent();

        SampleWriteableBitmap();
    }
}

}}

...