microsoft / Lumia-imaging-sdk

Lumia Imaging SDK is a comprehensive set of GPU/CPU imaging tools and effects that run on both mobile and desktop, with high speed and memory efficiency. Samples and extras code are included.
MIT License
75 stars 37 forks source link

Picture with rotation information is not correctly shown #5

Open nowheremanmail opened 8 years ago

nowheremanmail commented 8 years ago

Some pictures in JPG format with rotation information, are not correctly processed in QuickStart sample. Open quick start sample and select given image. You will see that image is not correctly processed. 20151114_205912000_ios

errorsample
atkulp commented 8 years ago

I can't even get the SDK to load properly on my phone (I get a missing component error at runtime). Did you have to do any troubleshooting? Is it the 10/Universal version? I'd love to figure out why it's not working for everyone. Thanks!

eliprand commented 8 years ago

The issue has been reported on StackOverflow Switching to CPU rendering fixes the issue. This is not a solution, but hopefully a clue for MSFT on how to fix it; We had to workaround this by loading the original twice. Obviously not ideal. Hoping for an update to sdk soon.

tskarman commented 8 years ago

This affects a variety of renderers. I encountered the problem (of EXIF rotation/orientation information being partially ignored) with WriteableBitmapRenderer and JpegRenderer.

When doing renderer.RenderOptions = RenderOptions.Cpu, the problem goes away. I assume that that can carry a performance penalty.

One consequence of that bug is that the aspect ratio is off. So the renderer assumes the oriented dimensions when laying out the render size. So non-square images look very off.

Is there any time frame for a bugfix release of the Lumia Imaging SDK?

BTW: Many thanks for this project, even though the 3.0 release has proven somewhat cumbersome (there is that other bug with it not working in the current Windows 10 Mobile emulators)

jamesmundy commented 8 years ago

We struggled with this as well on Windows Phone. Only applies to images with EXIF orientation tags. wp_ss_20160421_0001 wp_ss_20160421_0002

For now, we are using the following code to switch between GPU and CPU if the image contains Exif data:

   using (var image = await sourceFile.OpenStreamForReadAsync())
  {
    bool exifRotation = false;
    if (angleForRotation == 0)
    {
      exifRotation = false;
      var exif = ExifReader.ReadJpeg(image);
      switch (exif.Orientation)
      {
        case ExifOrientation.BottomLeft:
        case ExifOrientation.BottomRight:
        case ExifOrientation.TopLeft:
        case ExifOrientation.TopRight:
          exifRotation = true;
          break;
      }
    }

    image.Seek(0, SeekOrigin.Begin);
    using (var source = new RandomAccessStreamImageSource(image.AsRandomAccessStream()))
    {
      using (var scale = new ScaleEffect(source, scaleFactor))
      using (var rotation = scaleFactor < 1 ? new RotationEffect(scale, angleForRotation) : new RotationEffect(source, angleForRotation))
      using (var renderer = new JpegRenderer(rotation) { Quality = quality })
      {
        var info = await source.GetInfoAsync();
        renderer.RemoveExif = true;
        if (exifRotation || ((MemoryManager.AppMemoryUsageLimit / 1024) / 1024) < 200)
        {
          renderer.RenderOptions = RenderOptions.Cpu;
        }
        var buffer = await renderer.RenderAsync();
        using (var output = await newFile.OpenAsync(FileAccessMode.ReadWrite))
        {
          await output.WriteAsync(buffer);
          await output.FlushAsync();
        }
      }
    }
  }
davidbozjak commented 8 years ago

It's true, there appears to be a bug in the Lumia Imaging SDK when it comes to EXIF orientation and rendering on GPU.

That said, there is an easy workaround. When you first load an IImageProvider from an StorageFile, make a temporray bitmap and use that as a source in your other rendering operations. That way you will only take the penalty of a CPU-only render operation once, in the most limited possible scenario. All your other rendering operations will the optimally GPU accelerated.

Here is a helper method to use when using a StorageFile as a source:

public static async Task<IImageProvider> CreateImageSourceFromFile(StorageFile file)
{
    using (var source = new StorageFileImageSource(file))
    using (var renderer = new BitmapRenderer(source) { RenderOptions = RenderOptions.Cpu })
    {
        var bitmap = await renderer.RenderAsync();
        return new BitmapImageSource(bitmap);
    }
}
eliprand commented 8 years ago

@davidbozjak - thanks for the tip. We had been doing something similar to @jamesmundy 's suggestion for months now. Your approach is definitely cleaner for us at this point. Do you know if a newer version of the SDK is coming out soon? where can I keep my ears to the ground for that?

Regards,

Eric.