Создать новое изображение в файловой системе из System.Drawing.Image?

Хорошо, извините, это, вероятно, нубский вопрос, но я немного застрял.

Итак, что я делаю (в моем приложении asp.net), загружаю изображение из файловой системы:

System.Drawing.Image tempImage;
tempImage = System.Drawing.Image.FromFile(HttpContext.Server.MapPath(originalPath));

Затем я делаю некоторые изменения размера:

tempImage = my awesomeResizingFunction(tempImage, newSize);

и намерены сохранить его в файловой системе в другом месте, используя это:

string newPath = "/myAwesomePath/newImageName.jpg";
tempImage.Save(newPath);

и я получаю эту ошибку:

"A generic error occurred in GDI+."

Я знаю, что изображение «в порядке», потому что я могу записать его в браузер и увидеть изображение с измененным размером, я получаю сообщение об ошибке только при попытке сохранить его. Я новичок и застрял, я делаю это совершенно неправильно? (Ну, я думаю, это очевидно, но вы понимаете, что я имею в виду...)


person onekidney    schedule 04.08.2009    source источник


Ответы (3)


Пожалуйста, попробуйте этот код... Я использовал тот же код для изменения размера изображения и его сохранения. если у вас возникнут какие-либо проблемы, пожалуйста, дайте мне знать.

System.Drawing.Bitmap bmpOut = new System.Drawing.Bitmap(NewWidth, NewHeight);
    System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmpOut);
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
    g.FillRectangle(System.Drawing.Brushes.White, 0, 0, NewWidth, NewHeight);
    g.DrawImage(new System.Drawing.Bitmap(fupProduct.PostedFile.InputStream), 0, 0, NewWidth, NewHeight);
    MemoryStream stream = new MemoryStream();
    switch (fupProduct.FileName.Substring(fupProduct.FileName.IndexOf('.') + 1).ToLower())
    {
        case "jpg":
            bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
            break;
        case "jpeg":
            bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
            break;
        case "tiff":
            bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Tiff);
            break;
        case "png":
            bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
            break;
        case "gif":
            bmpOut.Save(stream, System.Drawing.Imaging.ImageFormat.Gif);
            break;
    }
    String saveImagePath = Server.MapPath("../") + "Images/Thumbnail/" + fupProduct.FileName.Substring(fupProduct.FileName.IndexOf('.'));
    bmpOut.Save(saveImagePath);

где fupProduct — идентификатор управления загрузкой файлов.

person Muhammad Akhtar    schedule 05.08.2009
comment
Вы можете улучшить это, используя Path.GetExtension вместо IndexOf('.'), хотя вам придется немного изменить переключатель msdn.microsoft.com/en-us/library/ - person RichardOD; 29.09.2009
comment
Важно отметить (msdn.microsoft.com/en-us/library/system .drawing.aspx) › Классы в пространстве имен System.Drawing не поддерживаются для использования в службах Windows или ASP.NET. - person Marc Gravell; 16.10.2009

Вы уверены, что originalPath и newPath указывают на разные файлы? Когда вы используете Image.FromFile, файл остается заблокированным до тех пор, пока вы не вызовете Dispose для изображения, что может привести к упомянутому вами исключению. Вместо этого вы можете загрузить изображение следующим образом:

Image tempImage = null;
using (FileStream fs = new FileStream(originalPath, FileMode.Open, FileAccess.Read))
{
    tempImage = Image.FromStream(fs);
}
...

Этот подход гарантирует, что файл будет закрыт в конце используемого блока.

person Thomas Levesque    schedule 04.08.2009

Возможно ли, что исходный поток, поддерживающий исходное изображение, был закрыт? Если поток позади растрового изображения был закрыт, вы начинаете получать ошибки GDI+. Я часто сталкивался с этим, когда мы добавили обработку изображений на наш сайт.

Если вы откроете объект Bitmap в отладчике Visual Studio, увидите ли вы исключения вместо значений свойств? Если да, то проблема не в операции сохранения, а в том, что уровень GDI+ потерял способность обрабатывать объект, и точка.

Я обнаружил, что мне нужно отслеживать потоки памяти, принадлежащие моим растровым изображениям, и хранить их все вместе. Изменение размера изображения привело к созданию нового MemoryStream с новым растровым изображением.

В итоге я создал этот простой класс (обрезав некоторые дополнительные свойства, которые здесь не нужны):

public class UploadedImage : IDisposable
{
    private Bitmap _img = null;
    private Stream _baseStream = null;


    /// <summary>
    /// The image object.  This must always belong to BaseStream, or weird things can happen.
    /// </summary>
    public Bitmap Img
    {
        [DebuggerStepThrough]
        get { return _img; }
        [DebuggerStepThrough]
        set { _img = value; }
    }

    /// <summary>
    /// The stream that stores the image.  This must ALWAYS belong to Img, or weird things can happen.
    /// </summary>
    public Stream BaseStream
    {
        [DebuggerStepThrough]
        get { return _baseStream; }
        [DebuggerStepThrough]
        set { _baseStream = value; }
    }

    [DebuggerStepThrough]
    public void Dispose()
    {
        if (Img != null)
            Img.Dispose();

        if (BaseStream != null)
            BaseStream.Close();

        _attached = false;
    }
}

Теперь я имел дело с изображениями, загруженными на наш веб-сайт, и обнаружил, что, когда Asp.Net перерабатывает поток, прикрепленный к запросу, все операции с изображениями начинают внезапно прерываться. Итак, мое решение, независимо от того, был ли это лучший способ сделать это или нет, состояло в том, чтобы скопировать данные из потока загрузки в мой собственный MemoryStream, загрузить изображение из него и вставить оба в этот контейнер. И где бы я ни создавал новый образ из старого, я всегда сохранял поток и образ вместе.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: мне также интересно посмотреть, как вы изменяете размер изображения. Это фрагмент того, как я сделал наш:

temp = new Bitmap(newWidth, newHeight, PIXEL_FORMAT);
temp.SetResolution(newHorizontalRes, newVerticalRes);
gr = Graphics.FromImage(temp);

//
// This copies the active frame from 'img' to the new 'temp' bitmap.
// Also resizes it and makes it super shiny.  Sparkle on, mr image dude.
// 
Rectangle rect = new Rectangle(0, 0, newWidth, newHeight);
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.SmoothingMode = SmoothingMode.HighSpeed;
gr.PageUnit = GraphicsUnit.Pixel;
gr.DrawImage(img, rect);

//
// Image copied onto the new bitmap.  Save the bitmap to a fresh memory stream.
//
retval = new UploadedImage();
retval.BaseStream = (Stream)(new MemoryStream());

temp.Save(retval.BaseStream, ImageFormat.Jpeg);
retval.Img = temp;
person Community    schedule 04.08.2009
comment
Важно отметить (msdn.microsoft.com/en-us/library/system .drawing.aspx) › Классы в пространстве имен System.Drawing не поддерживаются для использования в службах Windows или ASP.NET. - person Marc Gravell; 16.10.2009