【问题标题】:How to correctly resize/recompress image如何正确调整/重新压缩图像
【发布时间】:2014-01-15 05:29:42
【问题描述】:

过去 10 到 12 个小时,我一直在试图弄清楚如何在一个正在开发的 Windows 应用商店应用程序中正确地使下载的 Web 图像在尺寸和 C# 中的像素更小。

无论我做什么,我都会在最终图像上不断出现伪影,例如“半张图片”、灰色/同色区域等。就像流没有被正确刷新一样,尽管我相信已经这样做了(在下面的代码中没有这样做,因为它没有它也可以工作......)

这是我检索图像的方法 - 这部分有效,但包含在此处以确保所有信息都在此处(请参阅下面的代码):

  1. 获取图片的网址
  2. 使用 HttpWebRequest 获取响应
  3. 创建流以获取响应流
  4. 创建空的 StorageFile 并打开以供写入
  5. 将响应流复制到存储文件。
  6. 关闭一切

从那里,我需要执行以下操作:

  1. 确定大小(例如使用 BitmapDecoder)
  2. 如果图像的宽度超过一定数量(例如 700 像素),则必须调整其大小。
  3. 无论如何,文件总是太大,需要进一步压缩
  4. 图像需要保存为 jpg,图像质量设置为中/半高设置

我已经尝试了很多事情,包括使用 BitmapEncoder/BitmapDecoder 搞乱了很多事情,但无论如何我仍然得到半处理的图像。

有人可以帮我找到压缩和调整图像大小的正确方法吗?

我当前状态下的代码:

using (var response = await HttpWebRequest.CreateHttp(internetUri).GetResponseAsync())
{
    using (var stream = response.GetResponseStream())
    {
        var imageFolder = await localFolder.CreateFolderAsync(
               CachedImagesFolderEndFolderPath, CreationCollisionOption.OpenIfExists);

        string fileName = string.Format("{0}.jpg", 
               Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));

        var file = await imageFolder.CreateFileAsync(fileName, 
               CreationCollisionOption.ReplaceExisting);

        using (var filestream = await file.OpenStreamForWriteAsync())
        {
            await stream.CopyToAsync(filestream);
        }
    }
}

【问题讨论】:

  • 你也可以发布一个代码来处理你的图像吗?
  • 您已经向我们展示了有效的代码。不工作的代码怎么办?
  • 我不是网络专家,但为什么不使用 Image 类呢?它可以从流和文件中加载,并且可以用于调整大小(=使用图形类,drawImage)......并以所需的格式保存。 msdn.microsoft.com/en-us/library/…msdn.microsoft.com/en-us/library/…
  • 当有回复时我似乎没有收到电子邮件:-( 但是,我现在已经搞砸了很多,我会用答案更新我的帖子。基本部分是我需要让所有设置正确,并在我重新打开流之前关闭带有图像的源文件和目标文件的流。所以现在我分两步做,但希望我会优化这个......
  • @StefanDK 答案应该作为答案发布,而不是编辑到问题中。我已将您的解决方案作为答案发布。

标签: c# image-processing compression windows-store-apps image-resizing


【解决方案1】:

以下解决方案由StefanDKthis edit中提供:

看来我以前的解决方案的问题是我没有正确关闭流并且我没有正确的设置。

该解决方案基本上包含了这些文章中的元素:

从代码的主要部分,我对需要下载、调整大小和压缩的每个图像进行这些调用:

主要代码

请注意,我很清楚分配字符串值然后再次设置它的“非最佳实践”。这是尚未微调的原型代码。

var img = await ArticleStorage.GetLocalImageAsync(src);
img = await ArticleStorage.ResizeAndCompressLocalImage(img);

ArticleStorage 中方法的源代码

public const string CachedImagesFolderFullPath = "ms-appdata:///local/cache/";
public const string CachedImagesFolderEndFolderPath = "cache";
public const string OfflinePhotoImgPath = "ms-appx:///Assets/OfflinePhoto.png";
public const int MaximumColumnWidth = 700;

public static async Task<string> GetLocalImageAsync(string internetUri)
{
    if (string.IsNullOrEmpty(internetUri))
    {
        return null;
    }

    // Show default image if local folder does not exist
    var localFolder = ApplicationData.Current.LocalFolder;
    if (localFolder == null)
    {
        return OfflinePhotoImgPath;
    }

    // Default to offline photo
    string src = OfflinePhotoImgPath;

    try
    {
        using (var response = await HttpWebRequest.CreateHttp(internetUri)
                                                  .GetResponseAsync())
        {
            using (var stream = response.GetResponseStream())
            {
                // New random filename (e.g. x53fjtje.jpg)
                string fileName = string.Format("{0}.jpg",
                    Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));

                var imageFolder = await localFolder.CreateFolderAsync(
                    CachedImagesFolderEndFolderPath, 
                    CreationCollisionOption.OpenIfExists);

                var file = await imageFolder.CreateFileAsync(fileName, 
                    CreationCollisionOption.ReplaceExisting);

                // Copy bytes from stream to local file 
                // without changing any file information
                using (var filestream = await file.OpenStreamForWriteAsync())
                {
                    await stream.CopyToAsync(filestream);

                    // Send back the local path to the image 
                    // (including 'ms-appdata:///local/cache/')
                    return string.Format(CachedImagesFolderFullPath + "{0}", 
                         fileName);
                }
            }
        }
    }
    catch (Exception)
    {
        // Is implicitly handled with the setting 
        // of the initilized value of src
    }

    // If not succesfull, return the default offline image
    return src;
}

public static async Task<string> ResizeAndCompressLocalImage(string imgSrc)
{
    // Remove 'ms-appdata:///local/cache/' from the path ... 
    string sourcepathShort = imgSrc.Replace(
                                 CachedImagesFolderFullPath,
                                 string.Empty);

    // Get the cached images folder
    var folder = await ApplicationData.Current
                          .LocalFolder
                          .GetFolderAsync(
                               CachedImagesFolderEndFolderPath);

    // Get a new random name (e.g. '555jkdhr5.jpg')
    var targetPath = string.Format("{0}.jpg",
                          Path.GetFileNameWithoutExtension(
                              Path.GetRandomFileName()));

    // Retrieve source and create target file
    var sourceFile = await folder.GetFileAsync(sourcepathShort);
    var targetFile = await folder.CreateFileAsync(targetPath);

    using (var sourceFileStream = await sourceFile.OpenAsync(
                   Windows.Storage.FileAccessMode.Read))
    {
        using (var destFileStream = await targetFile.OpenAsync(
                   FileAccessMode.ReadWrite))
        {
            // Prepare decoding of the source image
            BitmapDecoder decoder = await BitmapDecoder.CreateAsync(
                                              sourceFileStream);

            // Find out if image needs resizing
            double proportionWidth = (double)decoder.PixelWidth /
                                     LayoutDimensions.MaximumColumnWidth;

            double proportionImage = decoder.PixelHeight / 
                                     (double)decoder.PixelWidth;

            // Get the new sizes of the image whether it is the same or should be resized
            var newWidth = proportionWidth > 1 ? 
                           (uint)(MaximumColumnWidth) : 
                           decoder.PixelWidth;

            var newHeight = proportionWidth > 1 ? 
                            (uint)(MaximumColumnWidth * proportionImage) : 
                            decoder.PixelHeight;

            // Prepare set of properties for the bitmap
            BitmapPropertySet propertySet = new BitmapPropertySet();

            // Set ImageQuality
            BitmapTypedValue qualityValue = new BitmapTypedValue(0.75, 
                                                    PropertyType.Single);
            propertySet.Add("ImageQuality", qualityValue);

            //BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(
                                            destFileStream, decoder);
            BitmapEncoder enc = await BitmapEncoder.CreateAsync(
                                          BitmapEncoder.JpegEncoderId, 
                                          destFileStream, propertySet);

            // Set the new dimensions
            enc.BitmapTransform.ScaledHeight = newHeight;
            enc.BitmapTransform.ScaledWidth = newWidth;

            // Get image data from the source image
            PixelDataProvider pixelData = await decoder.GetPixelDataAsync();

            // Copy in all pixel data from source to target
            enc.SetPixelData(
                decoder.BitmapPixelFormat,
                decoder.BitmapAlphaMode,
                decoder.PixelWidth, 
                decoder.PixelHeight, 
                decoder.DpiX, 
                decoder.DpiY, 
                pixelData.DetachPixelData()
                );

            // Make the encoder process the image
            await enc.FlushAsync();

            // Write everything to the filestream 
            await destFileStream.FlushAsync();
        }
    }

    try
    {
        // Delete the source file
        await sourceFile.DeleteAsync();
    }
    catch(Exception)
    {
    }

    // Return the new path 
    // including "ms-appdata:///local/cache/"
    return string.Format(CachedImagesFolderFullPath + "{0}", 
         targetPath);
}

【讨论】:

    猜你喜欢
    • 2017-05-16
    • 2014-11-23
    • 1970-01-01
    • 1970-01-01
    • 2021-01-28
    • 2017-02-21
    • 2012-07-30
    • 2022-01-06
    • 2018-06-15
    相关资源
    最近更新 更多