Создание миниатюр изображений с помощью C # - PullRequest
5 голосов
/ 27 марта 2012
@functions{

    public void GetThumbnailView(string originalImagePath, int height, int width)
    {
        //Consider Image is stored at path like "ProductImage\\Product1.jpg"

        //Now we have created one another folder ProductThumbnail to store thumbnail image of product.
        //So let name of image be same, just change the FolderName while storing image.
        string thumbnailImagePath = originalImagePath;
        originalImagePath = originalImagePath.Replace("thumb_", "");
        //If thumbnail Image is not available, generate it.
        if (!System.IO.File.Exists(Server.MapPath(thumbnailImagePath)))
        {
            System.Drawing.Image imThumbnailImage; 
            System.Drawing.Image OriginalImage = System.Drawing.Image.FromFile(Server.MapPath(originalImagePath));

            double originalWidth = OriginalImage.Width;
            double originalHeight = OriginalImage.Height;

            double ratioX = (double)width / (double)originalWidth;
            double ratioY = (double)height / (double)originalHeight;

            double ratio = ratioX < ratioY ? ratioX : ratioY; // use whichever multiplier is smaller

            // now we can get the new height and width
            int newHeight = Convert.ToInt32(originalHeight * ratio);
            int newWidth = Convert.ToInt32(originalWidth * ratio);

            imThumbnailImage = OriginalImage.GetThumbnailImage(newWidth, newHeight,
                         new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
            imThumbnailImage.Save(Server.MapPath(thumbnailImagePath), System.Drawing.Imaging.ImageFormat.Jpeg);

            imThumbnailImage.Dispose();
            OriginalImage.Dispose();
        }

    }

    public bool ThumbnailCallback() { return false; }

}

в другом вопросе stackowerflow я нашел этот код и он мне очень понравился, но при его использовании возникла проблема при создании миниатюрных изображений, как показано ниже:

Ошибка сервера в '/'Приложение.

Недостаточно памяти.Описание: во время выполнения текущего веб-запроса произошло необработанное исключение.Пожалуйста, просмотрите трассировку стека для получения дополнительной информации об ошибке и о том, где она возникла в коде.

Сведения об исключении: System.OutOfMemoryException: Недостаточно памяти.

Ошибка источника:

Строка 199: {

Строка 200: System.Drawing.ImageimThumbnailImage;

Строка 201: System.Drawing.Image OriginalImage = System.Drawing.Image.FromFile (Server.MapPath (originalImagePath.ToString ()));

Строка 202:

Строка 203: двойной оригиналWidth = OriginalImage.Width;

Исходный файл: c: \ Inetpub \ wwwroot \ Lokal \ Views \ Stok \ SatisRaporu.cshtml
Строка: 201

мое любопытство по поводу этой проблемы привело меня в исключениедетали и видел это:

    //
    // Summary:
    //     Creates an System.Drawing.Image from the specified file.
    //
    // Parameters:
    //   filename:
    //     A string that contains the name of the file from which to create the System.Drawing.Image.
    //
    // Returns:
    //     The System.Drawing.Image this method creates.
    //
    // Exceptions:
    //   System.OutOfMemoryException:
    //     The file does not have a valid image format.-or- GDI+ does not support the
    //     pixel format of the file.
    //
    //   System.IO.FileNotFoundException:
    //     The specified file does not exist.
    //
    //   System.ArgumentException:
    //     filename is a System.Uri.
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public static Image FromFile(string filename);

но все мои фотографии в этой папке имеют расширение ".jpg", так что мне кажется странным.если я не смогу создавать миниатюры из ".jpg", что еще я могу сделать?

Я действительно хочу узнать, пробовал ли кто-нибудь еще это на файлах ".jpg" и у него возникла проблема?и если не возникло никаких проблем, что я могу делать неправильно?

Небольшое примечание: я делаю это в представлении, используя синтаксис бритвы.Я немного знаю язык c # и улучшаю свои знания о нем каждый день.

Редактировать:

Как я вызываю функцию:

GetThumbnailView("../pics/thumb_" + (("0000000" + stocks.stockcode).Substring(("0000000" + stocks.stockcode).Length - 7, 7)) + ".jpg", 200, 200);

Ответы [ 2 ]

3 голосов
/ 27 марта 2012

Веб-сайт, над которым я работаю, создает свои эскизы, используя API-интерфейсы WPF вместо GDI +.Вам нужно добавить две ссылки на ваш проект, чтобы включить это: WindowsBase, PresentationFramework и PresentationCore.Вот базовый пример того, как код может быть использован:

try
{
    using (var input = File.Open(inputFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
    using (var thumb = File.Open(thumbFilename, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        Thumbnail(input, thumb, 200, 100);
    }
}
catch (MyException)
{
    File.Delete(thumbFilename);
}

Это помещает миниатюру в прямоугольник 200x100, сохраняя соотношение сторон.

(Реальный сайт не делает этогосовсем как выше. Что мы на самом деле делаем, это пытаемся сгенерировать наименьший миниатюра в обработчике POST загрузки файла. Мы используем поток памяти для хранения полученного миниатюры. Если миниатюра может быть сгенерирована правильно, мы сохраняем загрузку и маленький миниатюрув противном случае мы возвращаем клиенту сообщение об ошибке. Другие размеры эскизов создаются на лету и кэшируются.)

Вот код - обратите внимание, что я, возможно, немного испортил при преобразовании этого во что-то повторно используемое, новсе основные биты должны быть там.Обратите внимание, что он сохраняет все эскизы в формате JPEG, но допускает несколько форматов ввода, включая JPEG и PNG.Это может или не может быть хорошо для вас.

private static void Thumbnail(Stream source, Stream destination, int maxWidth, int maxHeight)
{
    int width = 0, height = 0;
    BitmapFrame frame = null;
    try
    {
        frame = BitmapDecoder.Create(source, BitmapCreateOptions.None, BitmapCacheOption.None).Frames[0];
        width = frame.PixelWidth;
        height = frame.PixelHeight;
    }
    catch
    {
        throw new MyException("The image file is not in any of the supported image formats.");
    }

    if (width > AbsoluteLargestUploadWidth || height > AbsoluteLargestUploadHeight)
        throw new MyException("This image is too large");

    try
    {
        int targetWidth, targetHeight;
        ResizeWithAspect(width, height, maxWidth, maxHeight, out targetWidth, out targetHeight);

        BitmapFrame targetFrame;
        if (frame.PixelWidth == targetWidth && frame.PixelHeight == targetHeight)
            targetFrame = frame;
        else
        {
            var group = new DrawingGroup();
            RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
            group.Children.Add(new ImageDrawing(frame, new Rect(0, 0, targetWidth, targetHeight)));
            var targetVisual = new DrawingVisual();
            var targetContext = targetVisual.RenderOpen();
            targetContext.DrawDrawing(group);
            var target = new RenderTargetBitmap(targetWidth, targetHeight, 96, 96, PixelFormats.Default);
            targetContext.Close();
            target.Render(targetVisual);
            targetFrame = BitmapFrame.Create(target);
        }

        var enc = new JpegBitmapEncoder();
        enc.Frames.Add(targetFrame);
        enc.QualityLevel = 80;
        enc.Save(destination);
    }
    catch
    {
        throw new MyException("The image file appears to be corrupt.");
    }
}

/// <summary>Generic helper to compute width/height that fit into specified maxima while preserving aspect ratio.</summary>
public static void ResizeWithAspect(int origWidth, int origHeight, int maxWidth, int maxHeight, out int sizedWidth, out int sizedHeight)
{
    if (origWidth < maxWidth && origHeight < maxHeight)
    {
        sizedWidth = origWidth;
        sizedHeight = origHeight;
        return;
    }

    sizedWidth = maxWidth;
    sizedHeight = (int) ((double) origHeight / origWidth * sizedWidth + 0.5);
    if (sizedHeight > maxHeight)
    {
        sizedHeight = maxHeight;
        sizedWidth = (int) ((double) origWidth / origHeight * sizedHeight + 0.5);
    }
}
1 голос
/ 27 марта 2012

Расширение файла на самом деле не имеет значения, это фактические байты изображения, которые имеют значение.Скорее всего, один из jpgs поврежден.Вы должны перехватить исключение OutOfMemory для каждого файла и обработать его соответствующим образом.

Поскольку вы пытаетесь создавать миниатюры, я предлагаю вам использовать изображение по умолчанию, если миниатюру не удается создать.Например, большинство веб-браузеров используют маленькую рамку с красным значком X, когда изображение повреждено или отсутствует.

См. Также: SO # 6506089 SO # 1108607 SO # 1644108 SO # 9237457

И для тех, кому интересно, почему выбрасывается OutOfMemoryException, см. Ответ на этот вопрос: Есть ли причина? Image.FromFile создает исключение OutOfMemoryException для недопустимого формата изображения?

...