使用SkiaSharp调整大小时,iPhone图像方向错误

时间:2017-05-25 13:33:03

标签: image image-processing xamarin xamarin.forms skiasharp

我在Xamarin.Forms项目中使用SkiaSharp中的SKBitmap.Resize()方法调整图像大小以供显示。我遇到的问题是在iOS上拍照时,当以肖像拍摄照片时,图像会以正面朝上显示。在Android上拍照,从Android和iOS设备上的照片库导入可以保持方向,但在iOS上拍照不会。如果我不使用SkiaSharp调整图像大小(仅显示图像而不调整大小),则图像将以正确的方向显示。然而,这不是解决方案,因为图像需要调整大小。以下是我的代码 -

private byte[] GetResizedImageData(string imageName)
    {
        float resizeFactor = 0.5f;
        var filePath = PathUtil.GetImagePath(imageName);
        var ogBitmap = SKBitmap.Decode(filePath);

        float fWidth = ogBitmap.Width * resizeFactor;
        int width = (int) Math.Round(fWidth);

        float fHeight = ogBitmap.Height * resizeFactor;
        int height = (int) Math.Round(fHeight);

        if (height >= 4096 || width >= 4096)
        {
            width = width * (int)resizeFactor;
            height = height * (int)resizeFactor;
        }

        var scaledBitmap = ogBitmap.Resize(new SKImageInfo( width, height), SKBitmapResizeMethod.Box);
        var image = SKImage.FromBitmap(scaledBitmap);
        var data = image.Encode(SKEncodedImageFormat.Jpeg, 100);

        return data.ToArray();
    }

PathUtil.GetImagePath()只是获取照片存储位置的特定于平台的路径的帮手。

4 个答案:

答案 0 :(得分:7)

对于那些有同样问题的人,我做了以下事情,很乐意接受有关改进的意见。

        public static SKBitmap HandleOrientation(SKBitmap bitmap, SKCodecOrigin orientation)
    {
        SKBitmap rotated;
        switch (orientation)
        {
            case SKCodecOrigin.BottomRight:

                using (var surface = new SKCanvas(bitmap))
                {
                    surface.RotateDegrees(180, bitmap.Width / 2, bitmap.Height / 2);
                    surface.DrawBitmap(bitmap.Copy(), 0, 0);
                }

                return bitmap;

            case SKCodecOrigin.RightTop:                                                 
                rotated = new SKBitmap(bitmap.Height, bitmap.Width);

                using (var surface = new SKCanvas(rotated))
                {
                    surface.Translate(rotated.Width, 0);
                    surface.RotateDegrees(90);
                    surface.DrawBitmap(bitmap, 0, 0);
                }

                return rotated;

            case SKCodecOrigin.LeftBottom:
                rotated = new SKBitmap(bitmap.Height, bitmap.Width);

                using (var surface = new SKCanvas(rotated))
                {
                    surface.Translate(0, rotated.Height);
                    surface.RotateDegrees(270);
                    surface.DrawBitmap(bitmap, 0, 0);
                }

                return rotated; 

            default:                       
                return bitmap;            
        }

然后使用以下内容获取原始方向。

            // TODO: Improve this.. I do not know how to "reset" 
            // the inputStream, so new it up twice. :/
            using (var inputStream = new SKManagedStream(imageIn))
            {
                using (var codec = SKCodec.Create(inputStream))
                {
                    orientation = codec.Origin;
                }
            }

....... 然后

SKBitmap orientedWExif = HandleOrientation(resized, orientation);

答案 1 :(得分:2)

SkiaSharp实际上并没有提供一种操作和改变图像方向的方法。最后,当我捕获并使用平台特定代码保存图像时,我最终改变了方向。

答案 2 :(得分:1)

用于调整大小和方向的可行解决方案

public class ImageResizer : IImageResizer
{
    private const int Quality = 75;

    public byte[] Resize(byte[] data, int newWidth, int newHeight)
    {
        using (var inputStream = new SKMemoryStream(data))
        {
            using (var codec = SKCodec.Create(inputStream))
            {
                using (var original_old = SKBitmap.Decode(codec))
                {
                    int sourceWidth = original_old.Width;
                    int sourceHeight = original_old.Height;

                    float nPercentW = ((float) newWidth / (float) sourceWidth);
                    float nPercentH = ((float) newHeight / (float) sourceHeight);

                    float nPercent = nPercentH < nPercentW ? nPercentH : nPercentW;

                    int destWidth = (int) (sourceWidth * nPercent);
                    int destHeight = (int) (sourceHeight * nPercent);

                    using (SKBitmap original = original_old.Resize(new SKImageInfo(destWidth, destHeight), SKFilterQuality.Medium))
                    {

                        var useWidth = original.Width;
                        var useHeight = original.Height;
                        Action<SKCanvas> transform = canvas => { };
                        switch (codec.EncodedOrigin)
                        {
                            case SKEncodedOrigin.TopLeft:
                                break;
                            case SKEncodedOrigin.TopRight:
                                // flip along the x-axis
                                transform = canvas => canvas.Scale(-1, 1, useWidth / 2, useHeight / 2);
                                break;
                            case SKEncodedOrigin.BottomRight:
                                transform = canvas => canvas.RotateDegrees(180, useWidth / 2, useHeight / 2);
                                break;
                            case SKEncodedOrigin.BottomLeft:
                                // flip along the y-axis
                                transform = canvas => canvas.Scale(1, -1, useWidth / 2, useHeight / 2);
                                break;
                            case SKEncodedOrigin.LeftTop:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(useHeight * 1.0f / useWidth, -useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                            case SKEncodedOrigin.RightTop:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(useHeight * 1.0f / useWidth, useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                            case SKEncodedOrigin.RightBottom:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(-useHeight * 1.0f / useWidth, useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                            case SKEncodedOrigin.LeftBottom:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(-useHeight * 1.0f / useWidth, -useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                        }

                        var info = new SKImageInfo(useWidth, useHeight);
                        using (var surface = SKSurface.Create(info))
                        {
                            using (var paint = new SKPaint())
                            {
                                // high quality with antialiasing
                                paint.IsAntialias = true;
                                paint.FilterQuality = SKFilterQuality.High;

                                // rotate according to origin
                                transform.Invoke(surface.Canvas);

                                // draw the bitmap to fill the surface
                                surface.Canvas.DrawBitmap(original, info.Rect, paint);
                                surface.Canvas.Flush();

                                using (SKImage image = surface.Snapshot())
                                {
                                    return image.Encode(SKEncodedImageFormat.Jpeg, Quality).ToArray();
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

答案 3 :(得分:0)

谢谢@ttugates,您的回答帮助我解决了方向旋转问题。只是想更新您的答案,因为有一些不推荐使用的代码。

 using (var inputStream = new SKManagedStream(await file.ReadAllStreamAsync()))
                {
                    using (var codec = SKCodec.Create(inputStream))
                    {
                          orientation = codec.EncodedOrigin;
                    }
                }
  public static SKBitmap HandleOrientation(SKBitmap bitmap, SKEncodedOrigin orientation)
    {
        SKBitmap rotated;
        switch (orientation)
        {
            case SKEncodedOrigin.BottomRight:

                using (var surface = new SKCanvas(bitmap))
                {
                    surface.RotateDegrees(180, bitmap.Width / 2, bitmap.Height / 2);
                    surface.DrawBitmap(bitmap.Copy(), 0, 0);
                }

                return bitmap;

            case SKEncodedOrigin.RightTop:
                rotated = new SKBitmap(bitmap.Height, bitmap.Width);

                using (var surface = new SKCanvas(rotated))
                {
                    surface.Translate(rotated.Width, 0);
                    surface.RotateDegrees(90);
                    surface.DrawBitmap(bitmap, 0, 0);
                }

                return rotated;

            case SKEncodedOrigin.LeftBottom:
                rotated = new SKBitmap(bitmap.Height, bitmap.Width);

                using (var surface = new SKCanvas(rotated))
                {
                    surface.Translate(0, rotated.Height);
                    surface.RotateDegrees(270);
                    surface.DrawBitmap(bitmap, 0, 0);
                }

                return rotated;

            default:
                return bitmap;
        }
    }