Как правильно создать эскиз с помощью C #? - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть консольное приложение, написанное с использованием C# поверх платформы Core .NET 2.2.

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

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

// This method accepts FileObject and returns a task
// The generated task will write the file as is to the default storage
// Then it'll create a thumbnail of that images and store it to the default storage
public async Task ProcessImage(FileObject file, int thumbnailWidth = 250)
{
    // The name of the full-size image
    string filename = string.Format("{0}{1}", file.ObjectId, file.Extension);

    // The name along with the exact path to the full-size image
    string path = Path.Combine(file.ContentId, filename);

    // Write the full-size image to the storage
    await Storage.CreateAsync(file.Content, path)
                 .ContinueWith(task =>
    {
        // Reset the stream to the beginning since this will be the second time the stream is read
        file.Content.Seek(0, SeekOrigin.Begin);

        // Create original Image
        Image image = Image.FromStream(file.Content);

        // Calulate the height of the new thumbnail
        int height = (thumbnailWidth * image.Height) / image.Width;

        // Create the new thumbnail
        Image thumb = image.GetThumbnailImage(thumbnailWidth, height, null, IntPtr.Zero);

        using (MemoryStream thumbnailStream = new MemoryStream())
        {
            // Save the thumbnail to the memory stream
            thumb.Save(thumbnailStream, image.RawFormat);

            // The name of the new thumbnail
            string thumbnailFilename = string.Format("thumbnail_{0}", filename);

            // The name along with the exact path to the thumbnail
            string thumbnailPath = Path.Combine(file.ContentId, thumbnailFilename);

            // Write the thumbnail to storage
            Storage.CreateAsync(thumbnailStream, thumbnailPath);
        }

        // Dispose the file object to ensure the Stream is disposed
        file.Dispose();
        image.Dispose();
        thumb.Dispose();
    });
}

Вот мой FileObject при необходимости

public class FileObject : IDisposable
{
    public string ContentId { get; set; }
    public string ObjectId { get; set; }
    public ContentType ContentType { get; set; }
    public string Extension { get; set; }
    public Stream Content { get; set; }
    private bool IsDisposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (IsDisposed)
            return;

        if (disposing && Content != null)
        {
            Content.Close();
            Content.Dispose();
        }

        IsDisposed = true;
    }
}

Приведенный выше код записывает правильное полноразмерное изображение в хранилищепривод.Он также записывает миниатюру в хранилище.Тем не менее, миниатюра всегда повреждена.Другими словами, сгенерированный файл миниатюр всегда записывается с 0 байтами.

Как правильно создать миниатюру из потока file.Content после записи того же потока в хранилище?

1 Ответ

0 голосов
/ 07 февраля 2019

Я выяснил причину проблемы.По какой-то причине строка thumb.Save(thumbnailStream, image.RawFormat); позиционирует thumbnailStream в конце, и при записи в хранилище ничего не записывается

Исправление этой проблемы - сброс позиции поиска после записи в поток, такой как

    using (MemoryStream thumbnailStream = new MemoryStream())
    {
        // Save the thumbnail to the memory stream
        thumb.Save(thumbnailStream, image.RawFormat);

        // Reset the seek position to the begining
        thumbnailStream.Seek(0, SeekOrigin.Begin);

        // The name of the new thumbnail
        string thumbnailFilename = string.Format("thumbnail_{0}", filename);

        // The name along with the exact path to the thumbnail
        string thumbnailPath = Path.Combine(file.ContentId, thumbnailFilename);

        // Write the thumbnail to storage
        Storage.CreateAsync(thumbnailStream, thumbnailPath);
    }

Я не уверен, какую выгоду получают, когда thumb.Save(...) не сбрасывает позицию в 0 после копирования в новый поток!Я просто чувствую, что так и должно быть, поскольку он всегда будет писать новый поток, не добавляя к существующему.

...