C # Bitmap.Save () дает общую ошибку GDI + с Format16BppIndexed и не работает данный метод [duplicate]

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

3
задан Michael IV 3 November 2014 в 20:47
поделиться

2 ответа

Я исправил некоторые из ваших ошибок (в основном неправильные размеры). Но он по-прежнему падает на b16bpp.Save(), потому что GDI + не поддерживает сохранение 16-битных изображений в оттенках серого .

Bitmap b16bpp;
private void GenerateDummy16bitImage()
{

    b16bpp = new Bitmap(IMAGE_WIDTH, IMAGE_HEIGHT, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);

    var rect = new Rectangle(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
    var bitmapData = b16bpp.LockBits(rect, ImageLockMode.WriteOnly, b16bpp.PixelFormat);
    // Calculate the number of bytes required and allocate them.
    var numberOfBytes = bitmapData.Stride * IMAGE_HEIGHT;
    var bitmapBytes = new short[IMAGE_WIDTH * IMAGE_HEIGHT];
    // Fill the bitmap bytes with random data.
    var random = new Random();
    for (int x = 0; x < IMAGE_WIDTH; x++)
    {
        for (int y = 0; y < IMAGE_HEIGHT; y++)
        {

            var i = ((y * IMAGE_WIDTH) + x); // 16bpp

            // Generate the next random pixel color value.
            var value = (short)random.Next(5);

            bitmapBytes[i] = value;         // GRAY
        }
    }
    // Copy the randomized bits to the bitmap pointer.
    var ptr = bitmapData.Scan0;
    Marshal.Copy(bitmapBytes, 0, ptr, bitmapBytes.Length);

    // Unlock the bitmap, we're all done.
    b16bpp.UnlockBits(bitmapData);

    b16bpp.Save("random.bmp", ImageFormat.Bmp);
    Debug.WriteLine("saved");
}

Объяснение моих изменений:

  • bitmapData.Stride уже IMAGE_WIDTH * BytesPerPixel, поэтому вам не нужно умножать на 2
  • , как вы объявили bitmapBytes как short[], он должен иметь размер изображения в пикселях, не входящих в байты
  • , что означает, что вам также не нужно умножать i на 2
  • , так как у вас есть изображение в градациях серого, у него нет синего, зеленого и красного каналов, но один 16-битный серый канал
  • Marshal.Copy занимает длину в «единицах массива» не в байтах

Всего вы пытались скопировать массив 8 раз в большую в растровое изображение.

6
ответ дан Community 18 August 2018 в 23:00
поделиться
  • 1
    Ну, на самом деле "сохранить в файл" часть была для целей отладки :) Мне действительно нужно использовать этот Bitmap внутри приложения. Цените свою помощь. Спасибо. – Michael IV 3 November 2014 в 21:57

Это работает для System.Drawing.Imaging.PixelFormat.Format16bppGrayScale:

    private static void SaveBmp(Bitmap bmp, string path)
    {
        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

        BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);

        var pixelFormats = ConvertBmpPixelFormat(bmp.PixelFormat);

        BitmapSource source = BitmapSource.Create(bmp.Width,
                                                  bmp.Height,
                                                  bmp.HorizontalResolution,
                                                  bmp.VerticalResolution,
                                                  pixelFormats,
                                                  null,
                                                  bitmapData.Scan0,
                                                  bitmapData.Stride * bmp.Height,
                                                  bitmapData.Stride);

        bmp.UnlockBits(bitmapData);


        FileStream stream = new FileStream(path, FileMode.Create);

        TiffBitmapEncoder encoder = new TiffBitmapEncoder();

        encoder.Compression = TiffCompressOption.Zip;
        encoder.Frames.Add(BitmapFrame.Create(source));
        encoder.Save(stream);

        stream.Close();
    }

    private static System.Windows.Media.PixelFormat ConvertBmpPixelFormat(System.Drawing.Imaging.PixelFormat pixelformat)
    {
        System.Windows.Media.PixelFormat pixelFormats = System.Windows.Media.PixelFormats.Default;

        switch (pixelformat)
        {
            case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                pixelFormats = PixelFormats.Bgr32;
                break;

            case System.Drawing.Imaging.PixelFormat.Format8bppIndexed:
                pixelFormats = PixelFormats.Gray8;
                break;

            case System.Drawing.Imaging.PixelFormat.Format16bppGrayScale:
                pixelFormats = PixelFormats.Gray16;
                break;
        }

        return pixelFormats;
    }
11
ответ дан Karsten 18 August 2018 в 23:00
поделиться
  • 1
    Этот ответ требует большего признания. После поиска в течение нескольких часов я наконец нашел человека, у которого есть ответ на сохранение изображений в оттенках серого 16bpp без необходимости внешней библиотеки, и у них есть только один голос. – Gorchestopher H 5 July 2017 в 19:27
  • 2
    Было бы полезно отметить, что для этого требуется импорт PresentationCore. – Nyerguds 10 January 2018 в 13:24
  • 3
    Кстати, перевод Format32bppArgb неверен. Bgr32 - формат без альфы. – Nyerguds 10 January 2018 в 13:27
  • 4
    Это делает именно то, что мне нужно. – Jacob Robbins 17 June 2018 в 16:47
Другие вопросы по тегам:

Похожие вопросы: