Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Exception при показе анимации GIF в PictureBox

297
26 марта 2010 года
koodeer
1.2K / / 02.05.2009
Обнаружил баг при показе анимированных файлов GIF в коммоненте PictureBox. В частности, при показе этого файла: "Dance.gif" (рис.1) выбрасывается исключение:
Цитата:
System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.



Пробовал так:

Код:
// цикл анимации воспроизводится один раз,
// затем происходит исключение
Bitmap bmp = new Bitmap("Dance.gif");
pictureBox1.Image = bmp;

// цикл анимации воспроизводится один раз,
// затем происходит исключение
Image img = Image.FromFile("Dance.gif");
pictureBox1.Image = img;


// если делать так, то исключение возникает моментально,
// на первом же кадре
pictureBox1.ImageLocation = "Dance.gif";
pictureBox1.Load();

Причём, если пробовать последним способом, то выкидывается окошко с сообщением об исключении в таком виде (рис. 2).

Вопрос: как перехватывать это исключение? Где, в каком месте? Пробовал даже так:
Код:
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    try
    {
        Application.Run(new Form1());
    }
    catch (Exception ex)
    {
        MessageBox.Show("Test");
    }
}

не помогает, исключение не перехватывается.
Как перехватить это исключение, чтобы моя программа не вылетала при показе некорректных джифок?

Гуглил. Похожий вопрос задаётся часто. Ответа не нашёл.


Другой вопрос: почему в PictureBox анимация воспроизводится медленнее, чем в WebBrowser? Из-за этого, вероятно, придётся показывать джифки в компоненте WebBrowser.


Используется VS2005, Framework 2.0.
5
26 марта 2010 года
hardcase
4.5K / / 09.08.2005
Довольно часто эта ошибка при работе с GIF происходит (сужу по выдаче гугла).
Вот ссылка на одно из решений.
297
26 марта 2010 года
koodeer
1.2K / / 02.05.2009
На этот ответ я натыкался. Не то. У меня не используются потоки Stream. Джифки открываются с харда. Большинство из них работают нормально, лишь эта глючит. По ходу выяснения вопроса нашёл в интернете и другие глючащие джифки. Вероятно, в них некорректно задан сам формат анимации.

Хотя вот сейчас в gif animator'е смотрел этот файлик - вроде всё нормально, ничего необычного.

Причём эти глючащие картинки нормально показываются во всех браузерах, в том числе и в компоненте WebBrowser. А просмотрщики картинок воспроизводят цикл анимации лишь один раз, потом она останавливется.

Но самое главное: я не могу перехватить исключение! Такое ощущение, что оно происходит в недрах GDI+.
5
26 марта 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: koodeer
Но самое главное: я не могу перехватить исключение! Такое ощущение, что оно происходит в недрах GDI+.


Судя по тому, что у тебя не прорисовываются контролы (прямоугольники), то это натурально падение подсистемы рендеринга. Такие же "конверты" бывают когда директХ падает. Предлагаю поставить сервиспаки и обновления на дотнет и винды.

297
26 марта 2010 года
koodeer
1.2K / / 02.05.2009
Что ж, так и сделаю.
8.2K
27 марта 2010 года
bagie2
299 / / 26.10.2008
koodeer
самое интересное, что первые два способа работают, а последний - экскепшн. надо бы кое что проверить...
8.2K
27 марта 2010 года
bagie2
299 / / 26.10.2008
а такой код тоже вызовет исключение?

 
Код:
ImageAnimator.Animate(Image.FromFile("Dance.gif"),
              delegate(object o, EventArgs a)
              {
                  pictureBox1.Image = new Bitmap((Bitmap)o);
              }
            );


Цитата:
Другой вопрос: почему в PictureBox анимация воспроизводится медленнее


внутри pictureBox используется как раз ImageAnimator а внутри ImageAnimator.Animate

 
Код:
...
                    animationThread = new Thread(new ThreadStart(ImageAnimator.AnimateImages50ms));
                    animationThread.Name = typeof(ImageAnimator).Name;
                    animationThread.IsBackground = true;
                    animationThread.Start();
...
8.2K
27 марта 2010 года
bagie2
299 / / 26.10.2008
или вообще попробуйте что-нибудь типа

Код:
public class ImageInfo
    {
        private bool animated;
        private int frame;
        private int frameCount;
        private int[] frameDelay;
        private bool frameDirty;
        private Image image;
        private const int PropertyTagFrameDelay = 0x5100;

        public bool Animated
        {
            get
            {
                return this.animated;
            }
        }

        public int Frame
        {
            get
            {
                return this.frame;
            }
            set
            {
                if (this.frame != value)
                {
                    if ((value < 0) || (value >= this.FrameCount))
                    {
                        throw new ArgumentException("InvalidFrame", "value");
                    }
                    if (this.Animated)
                    {
                        this.frame = value;
                        this.frameDirty = true;
                    }
                }
            }
        }

        public int FrameCount
        {
            get
            {
                return this.frameCount;
            }
        }

        public bool FrameDirty
        {
            get
            {
                return this.frameDirty;
            }
        }

        public Image Image
        {
            get
            {
                return this.image;
            }
        }

        public ImageInfo(Image image)
        {
            this.image = image;
            this.animated = ImageAnimator.CanAnimate(image);
            if (this.animated)
            {
                this.frameCount = image.GetFrameCount(FrameDimension.Time);
                PropertyItem propertyItem = image.GetPropertyItem(0x5100);
                if (propertyItem != null)
                {
                    byte[] buffer = propertyItem.Value;
                    this.frameDelay = new int[this.FrameCount];
                    for (int i = 0; i < this.FrameCount; i++)
                    {
                        this.frameDelay = ((buffer[i * 4] + (0x100 * buffer[(i * 4) + 1])) + (0x10000 * buffer[(i * 4) + 2])) + (0x1000000 * buffer[(i * 4) + 3]);
                    }
                }
            }
            else
            {
                this.frameCount = 1;
            }
            if (this.frameDelay == null)
            {
                this.frameDelay = new int[this.FrameCount];
            }
        }

        public int FrameDelay(int frame)
        {
            return this.frameDelay[frame];
        }

        public void UpdateFrame()
        {
            if (this.frameDirty)
            {
                if (this.image.SelectActiveFrame(FrameDimension.Time, this.Frame) != 0)
                    throw new System.Runtime.InteropServices.ExternalException();
                this.frameDirty = false;
            }
        }
    }


Код:
ImageInfo ii;

        private void Form1_Load(object sender, EventArgs e)
        {
            ii = new ImageInfo(Image.FromFile("Dance.gif"));
            if (ii.Animated)
                timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            ii.Frame = ii.Frame >= ii.FrameCount - 1 ? 0 : ii.Frame + 1;
            ii.UpdateFrame();
            if (pictureBox1.Image != null)
                pictureBox1.Image.Dispose();
            pictureBox1.Image = new Bitmap(ii.Image);
        }
297
31 марта 2010 года
koodeer
1.2K / / 02.05.2009
Цитата: bagie2
а такой код тоже вызовет исключение?


Увы, всё то же самое.


Цитата: bagie2
внутри pictureBox используется как раз ImageAnimator а внутри ImageAnimator.Animate


Ага, это интересно. Раньше как-то не задумывался, как это реализовано. Покопаюсь.


Цитата: bagie2
или вообще попробуйте что-нибудь типа


Попробовал. Исключение тоже возникает. Но весьма любопытно: выскакивает окошко с сообщением об ошибке в GDI+, но анимация при этом продолжается.
Но! Это исключение уже удаётся перехватить. При чём, что любопытно, оно происходит сразу же дважды.
Возникает оно в методе UpdateFrame() в строке

 
Код:
if (this.image.SelectActiveFrame(FrameDimension.Time, this.Frame) != 0)




Лишь после того, как этот компьютер получил свободный доступ к Интернету (раньше не было), и Винда обновилась по максимуму, всё заработало. Стали не нужны никакие ухищрения. Танцор, сцуко, наяривает и не думает вываливаться в эксепшн.

Мораль: обновления рулят!
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог