c# - 从多个 BitmapImage 创建 Tiff 文件

标签 c# bitmap uwp windows-10-universal tiff

背景:

我正在开发 Win 10 通用应用程序,有 BitmapImage 列表:

List<BitmapImage> ImagesList = new List<BitmapImage>();

每个列表项都是通过转换 byte[] 创建的至 BitmapImage通过这段代码:

 public async Task<BitmapImage> GetBitmapImage(byte[] array)
        {
            using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
            {
                using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
                {
                    writer.WriteBytes(array);
                    await writer.StoreAsync();
                }
                BitmapImage image = new BitmapImage();
                List<BitmapImage> ImagesList = new List<BitmapImage>();
                await image.SetSourceAsync(stream);
                return image;
            }
        }

问题:

如何将此列表转换为单个多页 Tiff 文件?

注意事项:

我找到了许多相关答案,例如 this但都是基于System.Drawing Windows 10 通用应用程序不支持的库,因此您可以在我的代码中看到,我正在使用 Windows.Ui.Xaml.Media.Imaging.BitmapImage对象而不是 System.Drawing.Bitmap获取图像。

最佳答案

How to convert this list to single multi-page Tiff file

在 UWP 应用中,我们可以使用 BitmapEncoder将 Tiff 图像文件编码为包含多个帧。 BitmapEncoder.SetPixelData方法可用于在一帧上设置像素数据,然后 BitmapEncoder.GoToNextFrameAsync可以异步提交当前帧数据并附加一个新的空帧进行编辑。因此,可以通过多张图像来创建 Tiff 图像。

假设我想从本地文件夹中的三个图像创建一个 Tiff 图像文件,我解码并从中读取像素数据并将其设置为 Tiff 图像。示例代码如下:

 private async void btnConvert_Click(object sender, RoutedEventArgs e)
 {
     StorageFolder localfolder = ApplicationData.Current.LocalFolder;
     StorageFile image1 = await localfolder.GetFileAsync("caffe1.jpg");
     StorageFile image2 = await localfolder.GetFileAsync("caffe2.jpg");
     StorageFile image3 = await localfolder.GetFileAsync("caffe3.jpg");
     StorageFile targettiff = await localfolder.CreateFileAsync("temp.tiff", CreationCollisionOption.ReplaceExisting);
     WriteableBitmap writeableimage1;
     WriteableBitmap writeableimage2;
     WriteableBitmap writeableimage3;
     using (IRandomAccessStream stream = await image1.OpenAsync(FileAccessMode.Read))
     {
         SoftwareBitmap softwareBitmap;
         BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
         softwareBitmap = await decoder.GetSoftwareBitmapAsync();
         writeableimage1 = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
         writeableimage1.SetSource(stream);
     }
     using (IRandomAccessStream stream = await image2.OpenAsync(FileAccessMode.Read))
     {
         SoftwareBitmap softwareBitmap;
         BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
         softwareBitmap = await decoder.GetSoftwareBitmapAsync();
         writeableimage2 = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
         writeableimage2.SetSource(stream);
     }
     using (IRandomAccessStream stream = await image3.OpenAsync(FileAccessMode.Read))
     {
         SoftwareBitmap softwareBitmap;
         BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
         softwareBitmap = await decoder.GetSoftwareBitmapAsync();
         writeableimage3 = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
         writeableimage3.SetSource(stream);
     }

     using (IRandomAccessStream ras = await targettiff.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
     {
         BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.TiffEncoderId, ras);
         var stream = writeableimage1.PixelBuffer.AsStream();
         byte[] buffer = new byte[stream.Length];
         await stream.ReadAsync(buffer, 0, buffer.Length);

         var stream2 = writeableimage2.PixelBuffer.AsStream();
         byte[] buffer2 = new byte[stream2.Length];
         await stream2.ReadAsync(buffer2, 0, buffer2.Length);

         var stream3 = writeableimage3.PixelBuffer.AsStream();
         byte[] buffer3 = new byte[stream3.Length];
         await stream3.ReadAsync(buffer3, 0, buffer3.Length);


         encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableimage1.PixelWidth, (uint)writeableimage1.PixelHeight, 96.0, 96.0, buffer);
         await encoder.GoToNextFrameAsync();
         encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableimage2.PixelWidth, (uint)writeableimage2.PixelHeight, 96.0, 96.0, buffer2);
         await encoder.GoToNextFrameAsync();
         encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableimage3.PixelWidth, (uint)writeableimage3.PixelHeight, 96.0, 96.0, buffer3);
         await encoder.FlushAsync();
     }
 }

temp.tiff 将成功创建。我不确定您是如何获得图像字节数组的,但是 BitmapImage不能直接写入或更新,你需要得到WriteableBitmap字节数组中的对象。如果您不知道如何获取 WriteableBitmap,请尝试引用以下代码或将 BitmapImage 保存到本地文件夹并使用我上面提供的代码。

public async Task<WriteableBitmap> SaveToImageSource(byte[] imageBuffer)
{             
    using (MemoryStream stream = new MemoryStream(imageBuffer))
    {
        var ras = stream.AsRandomAccessStream();
        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, ras);
        var provider = await decoder.GetPixelDataAsync();
        byte[] buffer = provider.DetachPixelData();
        WriteableBitmap ablebitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
        await ablebitmap.PixelBuffer.AsStream().WriteAsync(buffer, 0, buffer.Length);
        return ablebitmap;
    }           
}

更多详情请引用official sample .

关于c# - 从多个 BitmapImage 创建 Tiff 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41355922/

相关文章:

c# - 对Cookie进行加密编码

c# - 关于在 winphone 8.1 RT 中在 ContentDialogResult 中换行文本

flash - 如何只渲染一个 BitmapFilter 到 BMD?

c# - 如何在子页面上设置javascript?

image - 在黑莓中使用 Bitmap 还是 EncodedImage 更好?

java - SurfaceHolder导致闪烁

c++ - 如何在Windows Media Foundation中获取相机外部信息?

uwp - 如何访问 UWP 应用中的注册表项?

c# - 如何将现代 Windows 10 上下文菜单与 Win32 NotifyIcon 结合使用?

c# - NAUDIO多输入,单输出