7

xamarin forms labs カメラを使用して写真を撮るためのこのコードを取得するのを誰かが手伝ってくれました。

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です。これは、Googleの「大きなビットマップを効率的にロードする」ドキュメントに従っています。

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 ...それを禁止し、より一般的なサイズ変更オプションが必要です (画像は Web 呼び出しからのものであり、そうではありませんデバイス、次に見てください: https://github.com/InquisitorJax/Wibci.Xamarin.Images

于 2016-11-10T03:03:54.143 に答える