c# - Image.Save(..)抛出GDI+异常,因为内存流已关闭




exception (12)

也许值得一提的是,如果C:\ Temp目录不存在,即使你的流仍然存在,它也会抛出这个异常。

我有一些我想保存为图像的二进制数据。 当我尝试保存图像时,如果用于创建图像的内存流在保存之前关闭,则会引发异常。 我这样做的原因是因为我动态创建图像,因此我需要使用内存流。

这是代码:

[TestMethod]
public void TestMethod1()
{
    // Grab the binary data.
    byte[] data = File.ReadAllBytes("Chick.jpg");

    // Read in the data but do not close, before using the stream.
    Stream originalBinaryDataStream = new MemoryStream(data);
    Bitmap image = new Bitmap(originalBinaryDataStream);
    image.Save(@"c:\test.jpg");
    originalBinaryDataStream.Dispose();

    // Now lets use a nice dispose, etc...
    Bitmap2 image2;
    using (Stream originalBinaryDataStream2 = new MemoryStream(data))
    {
        image2 = new Bitmap(originalBinaryDataStream2);
    }

    image2.Save(@"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}

有没有人有任何建议,我可以如何保存流关闭的图像? 我不能依靠开发人员记住在保存图像后关闭流。 事实上,开发人员没有IDEA认为图像是使用内存流生成的(因为它发生在其他地方的其他代码中)。

我很困惑:(


我得到这个错误,因为我正在执行的自动化测试,试图将快照存储到一个不存在的文件夹中。 在创建文件夹后,错误解决


GDI +发生一般性错误。 也可能由于不正确的保存路径 ! 花了我半天的时间来注意到这一点。 所以请确保您已经双击检查路径以保存图像。


对我来说,下面的代码与保存到MemoryStream的行上的A generic error occurred in GDI+ MemoryStream 。 代码在Web服务器上运行,并通过停止并启动运行该站点的应用程序池来解决该问题。

在GDI +中肯定有一些内部错误

    private static string GetThumbnailImageAsBase64String(string path)
    {
        if (path == null || !File.Exists(path))
        {
            var log = ContainerResolver.Container.GetInstance<ILog>();
            log.Info($"No file was found at path: {path}");
            return null;
        }

        var width = LibraryItemFileSettings.Instance.ThumbnailImageWidth;

        using (var image = Image.FromFile(path))
        {
            using (var thumbnail = image.GetThumbnailImage(width, width * image.Height / image.Width, null, IntPtr.Zero))
            {
                using (var memoryStream = new MemoryStream())
                {
                    thumbnail.Save(memoryStream, ImageFormat.Png); // <= crash here 
                    var bytes = new byte[memoryStream.Length];
                    memoryStream.Position = 0;
                    memoryStream.Read(bytes, 0, bytes.Length);
                    return Convert.ToBase64String(bytes, 0, bytes.Length);
                }
            }
        }
    }

您可以尝试创建另一个位图副本:

using (var memoryStream = new MemoryStream())
{
    // write to memory stream here

    memoryStream.Position = 0;
    using (var bitmap = new Bitmap(memoryStream))
    {
        var bitmap2 = new Bitmap(bitmap);
        return bitmap2;
    }
}

当我试图将图像保存到路径中时,它也出现在我的面前

C:\Program Files (x86)\some_directory

.exe没有执行以管理员身份运行,我希望这可能会帮助有同样问题的人。


复制位图。 您必须保持该流在位图的整个生命周期中保持打开状态。

绘制图像时:System.Runtime.InteropServices.ExternalException:在GDI中发生了一般性错误

    public static Image ToImage(this byte[] bytes)
    {
        using (var stream = new MemoryStream(bytes))
        using (var image = Image.FromStream(stream, false, true))
        {
            return new Bitmap(image);
        }
    }

    [Test]
    public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
    {
        var imageBytes = File.ReadAllBytes("bitmap.bmp");

        var image = imageBytes.ToImage();

        image.Save("output.bmp");
    }

我遇到了同样的问题,但实际上原因是应用程序没有权限保存C上的文件。当我更改为“D:\ ..”时,照片已保存。


一个奇怪的解决方案,使我的代码工作。 在油漆中打开图像并将其保存为具有相同格式(.jpg)的新文件。 现在尝试使用这个新文件,它的工作原理。 它清楚地告诉你,该文件可能在某种程度上被破坏。 这只有在你的代码修复了所有其他错误时才有用


因为它是一个MemoryStream,所以你真的不需要关闭这个流 - 如果你不这样做,没有什么不好的,尽管显然这是一个很好的习惯来处理任何一次性的任何东西。 (有关这方面的更多信息,请参阅此问题 。)

但是,您应该处理位图 - 并且会为您关闭流。 基本上,一旦你给位图构造器一个流,它“拥有”流,你不应该关闭它。 正如该构造函数的文档所说:

您必须保持该流在Bitmap的生命周期中处于打开状态。

在处理位图时,我找不到任何有希望关闭流的文档,但您应该能够相当容易地进行验证。


当我从Citrix尝试时发生此错误。 映像文件夹在服务器中设置为C:\,对此我没有特权。 一旦图像文件夹被移动到共享驱动器,错误消失了。


你可以用这个:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

public class MyImageView extends View {

private static final int INVALID_POINTER_ID = -1;

    private Drawable mImage;
    private float mPosX;
    private float mPosY;

    private float mLastTouchX;
    private float mLastTouchY;
    private int mActivePointerId = INVALID_POINTER_ID;

    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;

    public MyImageView(Context context) {
        this(context, null, 0);
    mImage = getResources().getDrawable(R.drawable.imagename);

        mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
    }

    public MyImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);

        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: {
            final float x = ev.getX();
            final float y = ev.getY();

            mLastTouchX = x;
            mLastTouchY = y;
            mActivePointerId = ev.getPointerId(0);
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(pointerIndex);
            final float y = ev.getY(pointerIndex);

            // Only move if the ScaleGestureDetector isn't processing a gesture.
            if (!mScaleDetector.isInProgress()) {
                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;

                invalidate();
            }

            mLastTouchX = x;
            mLastTouchY = y;

            break;
        }

        case MotionEvent.ACTION_UP: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_CANCEL: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_POINTER_UP: {
            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            final int pointerId = ev.getPointerId(pointerIndex);
            if (pointerId == mActivePointerId) {
                // This was our active pointer going up. Choose a new
                // active pointer and adjust accordingly.
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mLastTouchX = ev.getX(newPointerIndex);
                mLastTouchY = ev.getY(newPointerIndex);
                mActivePointerId = ev.getPointerId(newPointerIndex);
            }
            break;
        }
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY);
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor);
        mImage.draw(canvas);
        canvas.restore();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));

            invalidate();
            return true;
        }
    }

}




c# image exception gdi+