7

有人帮我获取了使用 xamarin forms labs camera 拍照的代码:

picker = DependencyService.Get<IMediaPicker> ();  
                task = picker.TakePhotoAsync (new CameraMediaStorageOptions {
                    DefaultCamera = CameraDevice.Rear, 
                    MaxPixelDimension = 800,

                });

                img.BackgroundColor = Color.Gray;

                Device.StartTimer (TimeSpan.FromMilliseconds (250), () => {
                    if (task != null) {
                        if (task.Status == TaskStatus.RanToCompletion) {
                            Device.BeginInvokeOnMainThread (async () => {
                                //img.Source = ImageSource.FromStream (() => task.Result.Source);
                                var fileAccess = Resolver.Resolve<IFileAccess> ();
                                string imageName = "img_user_" + User.CurrentUser().id + "_" + DateTime.Now.ToString ("yy_MM_dd_HH_mm_ss") + ".jpg";
                                fileName = imageName;

                                fileAccess.WriteStream (imageName, task.Result.Source);
                                fileLocation = fileAccess.FullPath(imageName);

                                FileStream fileStream = new FileStream(fileAccess.FullPath(imageName), FileMode.Open, System.IO.FileAccess.Read);
                                imageUrl = (string)test[0]["url"];
                                img.Source = imageUrl;
                            }); 
                        }

                            return  task.Status != TaskStatus.Canceled
                            && task.Status != TaskStatus.Faulted
                            && task.Status != TaskStatus.RanToCompletion;
                    }
                    return true;
                });

它保存了图像,但是拍摄的手机图片的实际尺寸很大,有没有办法调整它的大小。

4

4 回答 4

15

更新:原始答案没有用,请参阅下面的更新答案。问题是 PCL 库非常慢并且消耗了太多内存。

原始答案(请勿使用):

我找到了一个图像 I/O 库 ImageTools-PCL,我在 github 上创建了它,并削减了 Xamarin 中无法编译的内容,将修改保持在最低限度,结果似乎有效。

要使用它,请下载链接的存储库,使用 Xamarin 编译它并将Build文件夹中的 DLL 添加到您的 Forms 项目中。

要调整图像大小,您可以这样做(应该适合您的问题的上下文)

var decoder = new   ImageTools.IO.Jpeg.JpegDecoder ();
ImageTools.ExtendedImage inImage = new ImageTools.ExtendedImage ();

decoder.Decode (inImage, task.Result.Source); 

var outImage = ImageTools.ExtendedImage.Resize (inImage, 1024, new ImageTools.Filtering.BilinearResizer ());

var encoder = new ImageTools.IO.Jpeg.JpegEncoder ();
encoder.Encode (outImage, fileAccess.CreateStream (imageName));


ImageSource imgSource = ImageSource.FromFile (fileAccess.FullPath (imageName));

更新答案:

从 nuget 获取 Xamarin.XLabs,了解如何使用 Resolver,使用方法创建 IImageService 接口Resize

iOS的实现:

public class ImageServiceIOS: IImageService{
   public void ResizeImage(string sourceFile, string targetFile, float maxWidth, float maxHeight)
    {  
        if (File.Exists(sourceFile) && !File.Exists(targetFile))
        {
            using (UIImage sourceImage = UIImage.FromFile(sourceFile))
            {  
                var sourceSize = sourceImage.Size;
                var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);

                if (!Directory.Exists(Path.GetDirectoryName(targetFile)))
                    Directory.CreateDirectory(Path.GetDirectoryName(targetFile));

                if (maxResizeFactor > 0.9)
                {
                    File.Copy(sourceFile, targetFile);
                }
                else
                { 
                    var width = maxResizeFactor * sourceSize.Width;
                    var height = maxResizeFactor * sourceSize.Height;

                    UIGraphics.BeginImageContextWithOptions(new CGSize((float)width, (float)height), true, 1.0f);  
                    //  UIGraphics.GetCurrentContext().RotateCTM(90 / Math.PI);
                    sourceImage.Draw(new CGRect(0, 0, (float)width, (float)height)); 

                    var resultImage = UIGraphics.GetImageFromCurrentImageContext();
                    UIGraphics.EndImageContext();


                    if (targetFile.ToLower().EndsWith("png"))
                        resultImage.AsPNG().Save(targetFile, true);
                    else
                        resultImage.AsJPEG().Save(targetFile, true);
                }
            }
        }
    }
}

Android服务的实现:

public class ImageServiceDroid: IImageService{
public void ResizeImage(string sourceFile, string targetFile, float maxWidth, float maxHeight)
{ 
    if (!File.Exists(targetFile) && File.Exists(sourceFile))
    {   
        // First decode with inJustDecodeBounds=true to check dimensions
        var options = new BitmapFactory.Options()
        {
            InJustDecodeBounds = false,
            InPurgeable = true,
        };

        using (var image = BitmapFactory.DecodeFile(sourceFile, options))
        {  
            if (image != null)
            {
                var sourceSize = new Size((int)image.GetBitmapInfo().Height, (int)image.GetBitmapInfo().Width);

                var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);

                string targetDir = System.IO.Path.GetDirectoryName(targetFile);
                if (!Directory.Exists(targetDir))
                    Directory.CreateDirectory(targetDir);

                if (maxResizeFactor > 0.9)
                { 
                    File.Copy(sourceFile, targetFile);
                }
                else
                { 
                    var width = (int)(maxResizeFactor * sourceSize.Width);
                    var height = (int)(maxResizeFactor * sourceSize.Height);

                    using (var bitmapScaled = Bitmap.CreateScaledBitmap(image, height, width, true))
                    {
                        using (Stream outStream = File.Create(targetFile))
                        {
                            if (targetFile.ToLower().EndsWith("png"))
                                bitmapScaled.Compress(Bitmap.CompressFormat.Png, 100, outStream);
                            else
                                bitmapScaled.Compress(Bitmap.CompressFormat.Jpeg, 95, outStream);
                        }
                        bitmapScaled.Recycle();
                    }
                }

                image.Recycle();
            }
            else
                Log.E("Image scaling failed: " + sourceFile);
        }
    }
}
}
于 2014-08-12T15:32:48.513 回答
5

@Sten 的回答可能会在某些 android 设备上遇到内存不足的问题。这是我实现该ResizeImage功能的解决方案,根据谷歌的“有效加载大型位图”文档:

public void ResizeImage (string sourceFile, string targetFile, int reqWidth, int reqHeight)
{ 
    if (!File.Exists (targetFile) && File.Exists (sourceFile)) {   
        var downImg = decodeSampledBitmapFromFile (sourceFile, reqWidth, reqHeight);
        using (var outStream = File.Create (targetFile)) {
            if (targetFile.ToLower ().EndsWith ("png"))
                downImg.Compress (Bitmap.CompressFormat.Png, 100, outStream);
            else
                downImg.Compress (Bitmap.CompressFormat.Jpeg, 95, outStream);
        }
        downImg.Recycle();
    }
}

public static Bitmap decodeSampledBitmapFromFile (string path, int reqWidth, int reqHeight)
{
    // First decode with inJustDecodeBounds=true to check dimensions
    var options = new BitmapFactory.Options ();
    options.InJustDecodeBounds = true;
    BitmapFactory.DecodeFile (path, options);

    // Calculate inSampleSize
    options.InSampleSize = calculateInSampleSize (options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.InJustDecodeBounds = false;
    return BitmapFactory.DecodeFile (path, options);
}

public static int calculateInSampleSize (BitmapFactory.Options options, int reqWidth, int reqHeight)
{
    // Raw height and width of image
    int height = options.OutHeight;
    int width = options.OutWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        int halfHeight = height / 2;
        int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
               && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}
于 2015-10-08T00:46:21.130 回答
3

您可以为每个平台本地执行此操作并使用接口。这是IOS的一个例子

在您的 PCL 项目中,您需要添加一个接口

public interface IImageResizer
{
    byte[] ResizeImage (byte[] imageData, double width, double height);
}

然后要在代码中调整图像大小,可以使用 DependencyService 加载该接口的 IOS 实现并运行 ResizeImage 方法

var resizer = DependencyService.Get<IImageResizer>();
var resizedBytes = resizer.ResizeImage (originalImageByteArray, 400, 400);
Stream stream = new MemoryStream(resizedBytes);
image.Source = ImageSource.FromStream(stream);

IOS 实现,将这个类添加到你的 IOS 项目中。

[assembly: Xamarin.Forms.Dependency (typeof (ImageResizer_iOS))]
namespace YourNamespace
{
    public class ImageResizer_iOS : IImageResizer
    {

        public byte[] ResizeImage (byte[] imageData, double maxWidth, double maxHeight)
        {
            UIImage originalImage = ImageFromByteArray (imageData);


            double width = 300, height = 300;

            double maxAspect = (double)maxWidth / (double)maxHeight;
            double aspect = (double)originalImage.Size.Width/(double)originalImage.Size.Height;

            if (maxAspect > aspect && originalImage.Size.Width > maxWidth) {
                //Width is the bigger dimension relative to max bounds
                width = maxWidth;
                height = maxWidth / aspect;
            }else if (maxAspect <= aspect && originalImage.Size.Height > maxHeight){
                //Height is the bigger dimension
                height = maxHeight;
                width = maxHeight * aspect;
            }

            return originalImage.Scale(new SizeF((float)width,(float)height)).AsJPEG ().ToArray ();
        }


        public static MonoTouch.UIKit.UIImage ImageFromByteArray(byte[] data)
        {
            if (data == null) {
                return null;
            }

            MonoTouch.UIKit.UIImage image;
            try {
                image = new MonoTouch.UIKit.UIImage(MonoTouch.Foundation.NSData.FromArray(data));
            } catch (Exception e) {
                Console.WriteLine ("Image load failed: " + e.Message);
                return null;
            }
            return image;
        }
    }
}
于 2014-10-09T11:30:42.627 回答
2

Xamarin Media Plugin 的更新允许您调整图像的大小 https://github.com/jamesmontemagno/MediaPlugin ...除此之外,您需要一个更通用的调整大小选项(比如图像来自网络调用,而不是设备,然后看看: https ://github.com/InquisitorJax/Wibci.Xamarin.Images

于 2016-11-10T03:03:54.143 回答