System.Drawing.Image.Save выдает ExternalException: в GDI произошла общая ошибка

У меня есть функция, которая берет растровое изображение, копирует его часть и сохраняет как 8bpp tiff. Имя файла результирующего изображения уникально, и файл не существует, программа имеет разрешение на запись в целевую папку.

void CropImage(Bitmap map) {
        Bitmap croped = new Bitmap(200, 50);

        using (Graphics g = Graphics.FromImage(croped)) {
            g.DrawImage(map, new Rectangle(0, 0, 200, 50), ...);
        }

        var encoderParams = new EncoderParameters(2);
        encoderParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 8L);
        encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionNone);

        croped.Save(filename, tiffEncoder, encoderParams);
        croped.Dispose();
    }

Странно то, что эта функция хорошо работает на некоторых компьютерах (Win 7) и выдает System.Runtime.InteropServices.ExternalException: в исключении GDI на других компьютерах (в основном Win XP) произошла общая ошибка.

На всех компьютерах установлена ​​среда выполнения .NET 3.5 SP1.

Если я использую croped.Save(filename, ImageFormat.Tiff); вместо croped.Save(filename, tiffEncoder, encoderParams);, то это работает на всех компьютерах, но мне нужно сохранить Tiff в формате 8bpp.

Есть идеи, где может быть проблема?

Спасибо, Лукас


person Lukas Kabrt    schedule 10.01.2010    source источник
comment
может картинка еще не сохранена, а начинает утилизироваться?   -  person serhio    schedule 10.01.2010
comment
Есть ли машины с Windows XP, на которых он работает?   -  person SLaks    schedule 10.01.2010
comment
GDI+ был обновлен до версии 1.1 в Vista. Я так и не нашел никаких документов, описывающих изменения. Похоже, вы нашли один.   -  person Hans Passant    schedule 10.01.2010
comment
(ответ перемещен из OP в комментарий): SLaks: я тестировал его на двух компьютерах с Wn XP, и ни один из них не работал.   -  person Marc Gravell    schedule 11.01.2010
comment
Поскольку ваш код выглядит совершенно нормально... как насчет tiffEncoder... может быть проблема в нем?   -  person Dan Byström    schedule 11.01.2010
comment
Ты решил это? У меня похожая проблема stackoverflow.com/questions/10381768/   -  person Juan    schedule 30.04.2012
comment
@Lukas Kabrt Удалось ли вам найти причину этой проблемы и решение?   -  person UnhandledExcepSean    schedule 17.12.2013
comment
Нет, я не нашел решения.   -  person Lukas Kabrt    schedule 19.12.2013


Ответы (1)


GDI — это функция операционной системы Windows. Я столкнулся с похожими проблемами при работе с 16-битными файлами TIFF и прибегнул к другой библиотеке. См. раздел использование LibTIFF из c#.

Справка MSDN предполагает, что эта функция доступна, но тогда Windows выдает исключения «общая ошибка», когда вы пытаетесь скопировать растровое изображение в новое растровое изображение или сохранить его в файл или поток. Действительно, та же функциональность хорошо работает в Windows 7 (которая, кажется, имеет хорошую поддержку TIFF). См. Новые функции WIC в Windows 7.

Другое решение, которое я использовал, — сделать небезопасную копию в 8-битном формате. Таким образом, я смог сохранить файлы PNG (с палитрой). Я не пробовал это для TIFF.

       // part of a function taking a proprietary TIFF tile structure as input and saving it into the desired bitmap format
      // tile.buf is a byterarray, containing 16-bit samples from TIFF.

        bmp = new Bitmap(_tile_width, _tile_height, PixelFormat.Format8bppIndexed);
        System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
        BitmapData bmpData =bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,bmp.PixelFormat);
        int bytes = bmpData.Stride * bmp.Height;

        dstBitsPalette = (byte *)bmpData.Scan0;

        offset=0;


        for (offset = 0; offset < _tile_size; offset += 2)
        {
             dstBitsPalette[offset >> 1] = tile.buf[offset + 1];
        }

        // setup grayscale palette
        ColorPalette palette = bmp.Palette;
        for (int i = 0; i < 256; i++)
        {
            Color c = Color.FromArgb(i, i, i);
            palette.Entries[i] = c;
        }
        bmp.Palette = palette;
        bmp.UnlockBits(bmpData);

        return bmp;

    }
person Adriaan    schedule 04.02.2010