Code Monkey home page Code Monkey logo

cordova-plugin-image-resizer's Introduction

ATTENTION

I don't have any time to maintain this plugin anymore. As long as no one wants to maintain it I don't see the possiblity to fix all the stuff mentioned in the issues, sorry. I recommend to not use this plugin anymore.

Image Resizer for Cordova

By: Protonet GmbH

Authors: Joschka Schulz

Adding the Plugin

Use the Cordova CLI and type in the following command:


// This plugin uses the cordova-plugin-camera
cordova plugin add cordova-plugin-camera

// This plugin
cordova plugin add https://github.com/protonet/cordova-plugin-image-resizer.git

Sample Code

At the moment the plugin is available on android, iOS and windows

resize

window.ImageResizer.resize(options, success, failed);

Options

  • uri(String): The Uri for the image on the device to get scaled (can be file:// path (iOS,Android) or data:image base64 encoded string(Android only))
  • folderName(String): The name of the folder the image should be put in android only
  • fileName(String): A custom name for the file. Default name is a timestamp. android and windows only
  • quality(Number): Quality given as Number for the quality of the new image - defaults to 85 android and iOS only
  • width(Number): The width of the new image,
  • height(Number): The height of the new image
  • base64(Boolean): Whether or not to return a base64 encoded image string instead of the path to the resized image
  • fit(Boolean): Whether or not to fit image in bounds defined by width and height android only

Android Example

    var options = {
          uri: uri,
          folderName: "Protonet Messenger",
          quality: 90,
          width: 1280,
          height: 1280,
          base64: true,
          fit: false
    };

    window.ImageResizer.resize(options,
      function(image) {
         // success: image is the new resized image
      }, function() {
        // failed: grumpy cat likes this function
      });

cordova-plugin-image-resizer's People

Contributors

athirdlane avatar ben3005 avatar bochetatron avatar gabrielsscavalcante avatar grafikart avatar jayordway avatar joschkaschulz avatar karvapallo avatar kdcro101 avatar keyz182 avatar kurudinov avatar michaeleeztradercom avatar ntrp avatar sithwarrior avatar snirs90 avatar sybeck2k avatar tiff avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cordova-plugin-image-resizer's Issues

build failed Could not find exifinterface.jar

Hi, here's my build log:

`$ cordova build android
ANDROID_HOME=E:\android\Sdk
JAVA_HOME=C:\Program Files\Java\jdk1.8.0_161
Reading build config file: E:\movil_phonegap\indata1\build.json
Reading the keystore from: E:\movil_phonegap\indata1\largekey.keystore
Subproject Path: CordovaLib
null
The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
at build_2a96tzvbki9m3komuie0misov.run(E:\movil_phonegap\indata1\platforms\android\build.gradle:146)
org.xwalk:xwalk_core_library:23+
The JavaCompile.setDependencyCacheDir() method has been deprecated and is scheduled to be removed in Gradle 4.0.
Incremental java compilation is an incubating feature.
The TaskInputs.source(Object) method has been deprecated and is scheduled to be removed in Gradle 4.0. Please use TaskInputs.file(Object).skipWhenEmpty() instead.

BUILD FAILED

Total time: 3.543 secs
FAILURE: Build failed with an exception.

  • What went wrong:
    A problem occurred configuring root project 'android'.

Could not find exifinterface.jar (com.android.support:exifinterface:27.1.1).
Searched in the following locations:
https://jcenter.bintray.com/com/android/support/exifinterface/27.1.1/exifinterface-27.1.1.jar

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    (node:19588) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: cmd: Command failed with exit code 1 Error output:
    FAILURE: Build failed with an exception.

  • What went wrong:
    A problem occurred configuring root project 'android'.

Could not find exifinterface.jar (com.android.support:exifinterface:27.1.1).
Searched in the following locations:
https://jcenter.bintray.com/com/android/support/exifinterface/27.1.1/exifinterface-27.1.1.jar`

Aspect ratio in IOS

Am I correct in my impression that the plugin does not keep the aspect ratio of the resized image in ios. In android the aspect ratio is maintained but not so in ios. If true is there a way we can keep the aspect ration as we resize in ios.

Exif Lost

Hey,
I am afraid that thid plugin is losing all the EXIF data after resizing!

It means that the portrait pictures will be saved as landscape, which is a main issue.

I'm using Android Samsung A5

fileName parameter on iOS does not work the way it is documented?

Hi @JoschkaSchulz ,

i just noticed on iOS the resized image file url returned from the plugin is always an auto generated filename (img%d.jpg with %d being a static count variable, line 124 in ImageResizer.m).
Looking into the code, it does seem like fileName parameter on iOS is used as an asset name which can be used instead of the uri parameter to load the source image.. (lines 58 et sec., correct me if i am wrong..)
If this is the way it works on iOS - why fileName is mandatory like stated in #16 ?

Different behaviour on different platforms is not the way a cordova plugin should be implemented and different parameter meanings on different platforms is really bad practice (i would actually say a no go).
Even worse, the documentation does not mention this. Doc says: A custom name for the file. Default name is a timestamp. , which is absolutely not true for iOS.

I would recommend to at least clarify the meaning of fileName parameter in the docs with a big hint on different behavior. Better: implement a new optional parameter like assetIdentifier for this iOS specific stuff and change the filename generation to work like in Android..

displaying resized image

i have a question about displaying a resized image

i'm doing this with cordova on android.

cordova has a property called cordova.file.applicationDirectory that maps to the uri file:///android_asset/

thru trial and error i have discovered android_asset contains the standard cordova directory named www

i have placed sample.jpg in www and referenced it in the following example

   var options = {
                    uri: cordova.file.applicationDirectory + "www/sample.jpg",
                    folderName: "www",
                    filename: "resized.jpg",
                    quality: 90,
                    width: 32,
                    height: 32};

    window.ImageResizer.resize(options,
                               function(image) {
                                   alert("resize success");
			       var htmlToAppend = '<img src="www/resized.jpg" />';
			       $('#scaled').append(htmlToAppend);
                               }, 
                               function() {
                                   alert("FAIL");
                               });

however, when this runs, no image displays.

what is the recommended way to reference a resized image?

Build failure

Here's my build log:

:CordovaLib:compileReleaseJavaWithJavac
:CordovaLib:transformClassesAndResourcesWithPrepareIntermediateJarsForRelease
:app:preBuild UP-TO-DATE
:app:preReleaseBuild
Download https://maven.google.com/com/android/support/appcompat-v7/maven-metadata.xml
Download https://maven.google.com/com/android/support/appcompat-v7/23.4.0/appcompat-v7-23.4.0.pom
Download https://jcenter.bintray.com/com/android/support/appcompat-v7/maven-metadata.xml
Download https://jitpack.io/com/github/ergovia-mobile/android-transcoder/v0.1.10R_ergovia/android-transcoder-v0.1.10R_ergovia.pom
Download https://jitpack.io/com/github/ergovia-mobile/android-transcoder/v0.1.10R_ergovia/android-transcoder-v0.1.10R_ergovia.aar
:app:compileReleaseAidl
:CordovaLib:packageReleaseRenderscript NO-SOURCE
:app:compileReleaseRenderscript
:app:checkReleaseManifest
:app:generateReleaseBuildConfig
:app:prepareLintJar
:app:generateReleaseResValues
:app:generateReleaseResources
:app:mergeReleaseResources
:app:createReleaseCompatibleScreenManifests
:app:processReleaseManifest
/usr/src/app/platforms/android/app/src/main/java/info/protonet/imageresizer/ImageResizer.java:15: error: package org.apache.cordova.camera does not exist
import org.apache.cordova.camera.FileHelper;
                                ^
/usr/src/app/platforms/android/app/src/main/java/info/protonet/imageresizer/ImageResizer.java:92: error: cannot find symbol
            BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(uriString, cordova), null, options);
                                       ^
  symbol:   variable FileHelper
  location: class ImageResizer
/usr/src/app/platforms/android/app/src/main/java/info/protonet/imageresizer/ImageResizer.java:99: error: cannot find symbol
            Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(uriString, cordova), null, options);
                                                               ^
  symbol:   variable FileHelper
  location: class ImageResizer

Unable to create compressed file in Android Oreo (8.0)

Hi,

This plugin is working as a charm but suddenly it stopped working, we found that its working well till till Android 7.0 but not in Android Oreo 8.0.

We are getting "Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference".

I see that its not able to create folder and compressed file in given folder.

Please let us know if you found any work around for Android 8.0.

thank you

Picture IOS not display

Bonjouur, on IOS, I can not display the image, do you have a solution?
(On android it works well)

Failed to fetch plugin

I'm trying to install this plugin but I have the next issue:

Failed to fetch plugin https://github.com/protonet/cordova-plugin-image-resizer.git via registry.
Probably this is either a connection problem, or plugin spec is incorrect.
Check your connection and plugin name/version/URL.
Failed to get absolute path to installed module

This is my enviroment:

Ionic:

ionic (Ionic CLI) : 4.2.1 (/usr/local/lib/node_modules/ionic)
Ionic Framework : ionic-angular 3.9.2
@ionic/app-scripts : 3.2.0

Cordova:

cordova (Cordova CLI) : 8.1.2 ([email protected])
Cordova Platforms : android 6.4.0
Cordova Plugins : no whitelisted plugins (15 plugins total)

System:

NodeJS : v8.11.1 (/usr/local/bin/node)
npm : 6.4.1
OS : macOS

Failed to resize an image on iOS 12.x

When trying to resize an image on iOS 12.x no errors shown but the resized image is empty (just white background).
The problem seems to be due to the path assets-library:// which is not supported (for example "assets-library://asset/asset.JPG?id=8458AC82-B00F-4595-8B78-A135643A3AB3&ext=JPG")

Using cordova file plugin and window.resolveLocalFileSystemURL to convert the file to cdv file path seems to fix the problem and the image is resized correctly.

resize function not working properly...

const options: CameraOptions = {
    quality: 100,
    sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
    destinationType: this.camera.DestinationType.FILE_URI,
    encodingType: this.camera.EncodingType.JPEG,
    mediaType: this.camera.MediaType.PICTURE
  }
this.camera.getPicture(options).then((imageData) => {
      alert(imageData);
         this.imageResizer.resize({
                         uri:imageData,
                         folderName:'trouble',
                         quality:50,
                         height:200,
                        width:200,
                                }).then((path:string) =>{
                                   alert(path);
                                   if (this.platform.is('android')) {
                                          this.cameraUrl = path;   
                                          this.uploadPhoto(path);
                                    }
     
                           })
                   //this.uploadPhoto(imageData)
     }, (err) => {
      console.log(err);
     });

Here is my code....my resize function does get executed without the error , but the new image is not populating(generated), the rest of the code is working fine ,as i have tested it . I have to upload an image which has to be resized.

Thank You

Plugin crash the app when trying to resize an image from file (i.e. gallery)

code:

window.imageResizer.resizeImage(
               function(data) { 
                    console.log("resizeImage : \r\n" + data);
                }
               , function (error) {
                 console.log("Error : \r\n" + error);
               }, imageURI, 750, 750, {
                  resizeType: ImageResizer.RESIZE_TYPE_PIXEL,
                  imageDataType: ImageResizer.IMAGE_DATA_TYPE_URL,
                  format: ImageResizer.FORMAT_JPG
               }
            );

If you imageURI is an image chosen from gallery "content://media/external/images/media/5045"

the plugin crashes the app.

More info:
cordova -v 6.1.0
cordova platform version android 5.1.1
cordova-plugin-image-resizer 1.0.0 "ImageResizer"
android version 4 - 5

code for getting the image from the device:

navigator.camera.getPicture(
  that.photoTaken,
  that.onCaptureFail, {
    destinationType: Camera.DestinationType.FILE_URI,
    sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
    mediaType: Camera.MediaType.PICTURE,
    saveToPhotoAlbum: true
  }
);

Is this plugin works in Ionic 1

I have real problem on resizing images before upload to firebase in my Ionic 1 app , i just found this plugin and i hope it can help me , can any one advise if it is tested in ionic 1 app .

Code executes synchronously. Android

Hi guys, I have an issue about synchronous executing of resizing an image.
It works ok when u have small size one image, but when u try to resize a lot of large size images the app freezes. I just wrapped up code into runnable and it works much faster and app doesn't freeze. Maybe someone could create pull request to fix it(I am not an expert in Java, but it takes just few lines of code)? Don't know if contributor is still here...

Plugin does not compile with latest version of Java

Plugin does not compile with latest version of java.

build 1.8.0_66-b17

[removed for brevity]/ImageResizer.java:15: error: cannot find symbol
import org.apache.cordova.FileHelper;
^
symbol: class FileHelper
location: package org.apache.cordova
[removed for brevity]/protonet/imageresizer/ImageResizer.java:84: error: cannot find symbol
BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(uriString, cordova), null, options);
^
symbol: variable FileHelper
location: class ImageResizer
[removed for brevity]/protonet/imageresizer/ImageResizer.java:91: error: cannot find symbol
Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(uriString, cordova), null, options);
^
symbol: variable FileHelper
location: class ImageResizer

Mismatch in ID/Package name causing double addition of plugin to package.json

In package.json and config.xml, this plugin has an ID of "info.protonet.imageresizer" but has a name of "cordova-plugin-image-resizer" in package.json. This is confusing either npm, Ionic, or cordova, and causing the plugin to be put into package.json twice:

"cordova-plugin-image-resizer": "https://github.com/protonet/cordova-plugin-image-resizer.git", 
"info.protonet.imageresizer": "https://github.com/protonet/cordova-plugin-image-resizer.git"

The simple solution seems to be to make these match. I would submit a PR, but I'm not sure what name would be preferable.

iOS App Crashes after resizing a bunch of images

Hi!

I am developing a iOS app using Ionic 1.7.15 and Cordova 6.2.0. The app downloads a lot of imagens from the internet and I want to generate a thumbnail for each imagen downloaded. So I can have two versions of each image, the thumbnail and the original one.

The plugin works just fine in Android. But in my iPad 2, the app crashes after resizing lots of imagens (lets say after 500 imagens).

I wonder if I am doing something wrong, forgetting to free some resources or something like that.

Here is the code I am doing:

var filePath = cordova.file.dataDirectory + image.fileName;

 var options = {
  uri: filePath,
  image:image.fileName,
  folderName: "Thumbnails",
  quality: 100,
  width: 170,
  height: 140};

  window.ImageResizer.resize(options,
      function(thumbnailPath) {

        RepositoryService.updateImage(resultado.nativeURL, thumbnailPath, image.id)
        .then(function() {
          resolve({"id": image.id, "fileName": image.fileName});
        }).catch(function(error) {
            console.log(error);
          reject({"description": "Error updating image on the database", "error": error});
        });


  }, function(error) {
    // failed: grumpy cat likes this function
    console.log(error);
  });

I have also posted on Stack Overflow, hoping that someone could help me identify the problem:
https://stackoverflow.com/questions/37923566/ionic-ios-app-crashes-after-resizing-lots-of-imagens

Android giving black background for transparent Images

I am trying to resize an image which has a transparent background. After resizing the image comes with a black background. I did some google around this. I found this solution.

I have used the following code for compressing the images in android. Now it's working fine.
bitmap.setHasAlpha(true); bitmap.compress(Bitmap.CompressFormat.PNG, quality, out);

Please do the above changes in source code.

Thanks in advance.

Build failing (Unknown property `ANDROID_EXIFINTERFACES_VERSION`)

My builds started failing after the latest changes to the plugin.xml file. I'm getting this error

A problem occurred evaluating root project 'android'.
> Could not get unknown property 'ANDROID_EXIFINTERFACES_VERSION' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.

After looking at where the build is failing it pointed me to my build.gradle file. It's failing here

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    // SUB-PROJECT DEPENDENCIES START
    debugCompile(project(path: "CordovaLib", configuration: "debug"))
    releaseCompile(project(path: "CordovaLib", configuration: "release"))
    compile "com.android.support:support-v4:24.1.1+"
    compile "com.android.support:exifinterface:$ANDROID_EXIFINTERFACES_VERSION" 
// FAILS HERE ^^ 
    // SUB-PROJECT DEPENDENCIES END
}

It looks like the variable ANDROID_EXIFINTERFACES_VERSION isn't getting properly replaced in the build.gradle file. Any idea why this is happening?

โ€œCannot read property 'apply' of undefinedโ€

โ€œCannot read property 'apply' of undefinedโ€
my code
`getPicture() {
var options: CameraOptions = {
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
allowEdit: true,
mediaType: 0,

    };
   
    Camera.getPicture(options).then((fileUri) => {
        let options: ImageResizerOptions = {
            uri: fileUri,
            folderName: cordova.file.externalCacheDirectory,
            quality: 90,
            width: 1280,
            height: 1280
        };
        ImageResizer.resize(options).then(img => {
            var d = img;
        }).catch(err => {
            alert(err)
        });
    });`

Always execute the error function

My full code is
var options = { uri: "data:image/jpeg;base64,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UYpKKBhRRQKYAKUUmKUUgCloHSkoAM0vWkpRQAUUUCkAtFFFABQaKM0AFAopKYDqKSlHSgAApaBRQMUVPbDk1BVi1oJZZrLvz++NalZF4czv9atGTIab1p1JWggpQaTFLjkUAW7bpmrFV7UZFT96zZaFpr9DS02U/IaQykOZqsYxVWI/vjVupKEopT0pKBh2opDRSAWiiigApaSlpgGaWkFLQMSiilpCEoApaKBhRRQKAFFBopKAClpKWgAooooEFKKSigQopaQGjrQAtJmlpKBi0AUlKKACilpKAAUtFFAgFFFAoAKKWigAooooAWjFFFACUtJRQAuaKKKBi0UUUAFAoooEKKBSCloGFFJS0CEopaKACiiigAooooASiiigYUUUUAFFFFAC0UCigQUtJS0AFFFFABSUtJQAUUUUAFJS0lAC0UlLQAYooooAKKKKACiiigAoopaACkpaKYCUUUtAwooopCCiiigApaSlFAgooopgFFFFABRQKKAAUtFFMBKUUlKKACiiigAooopAFFFFMApaSigBaKKMUhBRRRQAUUUUALRRRTAKSlpKAClpKUUAFFFFAgooooAKa54p1RynAoGjOvD8xNUHOTVq6bkiqhoGV7k8Vi3jfvMHoRWtcvkEVjXDHcc4q0JkEu7b8vGOmaEDMOeuKACMnJxnpRk4JXp/OrRHUQZ44NPBx296Zk7hxxilPzHg8UE3sP4IB7Go2PPQ05jtK8Hp1pPvdwPamD1EDjJ4P4inBTg4bBPrzTCH5CsMZHGKeiDOeuKAHKuAOevX2pQGHLcKemfSg8g8frSncyAsc44FAMdg8EdD3oAHeo1RlUKBx25qRATwRSFcntOJGzn8a6nw3HxJJwQBjNc1EGGFXHPrXX6BD5WnLkfMxyamWw0aYoooqCxaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAxOtLS4pKRqBo7UUvagBDSCloFAAaTpS9KDQAlL60lFAhaKTNLQAUCkNKKACkNLmigYClxxSiigQlKKSloAQ0lLQBQAhFFLQBQAmKWkooGOFApBxSg0CCkoNKOlIBBRiijNABQKOtAoAU0gpetJigApaCaKYAaO1FFAAKKUUUgCijFGKYCUCjvRSGLQKBRQAUYpaAaBhSUtFMQUtJS0gCgCiikAd6KSl7UAHakoooELRQKWmMSlFFAoAKKKKYDhVm2qsKtWv3TSJZPWNdczMfetmsOdsytz3rSJmxtFITQDViHUYpA1OpAW7XhamqK3HyVLUMpC1HP/qjUlRXP+rNSUUoOZGq1nAqta5y1WaRSCiilpDEooo70AFFFKKBgKKKKYBRRRSAKKWigQUUlLQAUCigUDFpKWigBKKWg0AFJS4oxQIBRijFGKBC4oxiiigYUUGigAooooAWikFLQAtFIKWgQUUUUALRSUooGFFLSUCCiiloASiiigYUtFAoAWikpaACiiigQUUCigApaKSgBaKKBQAUUUUAFFFFAAKQ0tJQMKKKKACiiigBRRRRQIWikooAWikooAWkpRSUAGKMUUUAFFFFABiiiigAoopaAEpaKKAEopaSgAooooAWiiimAUUUUAFFFFABRRRSAKUUUUAFFFFMQUUUUgCiiimMKKKKBC0UlLQAUUUCgAooopgFFFFABRRRQAtJS0lAhaKKKACikoFIBwooFFMApKWkoAKUUUtACUUtFAgpKWigBKr3BwKsGqd22AaCkZlw2W5qBzwaklOWNQyngihAULtgoJJx61kTSK0uPXoK0b/hCKyj17VokQ2x4PJHbFIDjhfzpo/IUuACMDHpVEXAjJHYGkU7Sw3AjNHCA87znoDTVkzkZ5B9KBXsDOc4HfpTiG42MCQMEGlVmxyB9cU3I3EigEJu2vyp59+KkiwFwetN9yM04AFhxgEUx63HA5+hp6D92B1wOaj8tRkAcHvTh+7Hyg59qAux3C4boOlSJjPXmmD7uDyKmtkUcc4z3OaQFq3jLbV7g13FrH5VvGncKM1yWkoJLuJPVv5V2VRIaFpKKKkoWiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAMUGijFGKRqFFAooABRRRmgAoopKBBRS0UANxmlopaQCY4pe1LSUwAUUZoFAxwopKOtAAKWkozQIM0UUlACjpS02gUALSUo6UnegBQKXFAoNACGlHSkpRSAMUYpaCMimA0UCgccUtAAKQ0tJQAd6WkpRQAUUtJQAvaijtRg0ALRSYpcUAIaKWkoAMUYoxRikMKKBS4oABS0CigYgopaMUCCijHFGKQBQOlFAFABSU4UUwAUUCigAooopAApe1JSimAoq1bD5TVUVctx8tMlkh4BrCl/wBY31rbl4jb6ViMcux96tGTG0YpRRVAApwPNNpy9aALtv8AdqYCo7f7makqGUgqG5+4anqC6PyGpKRVswNpIqxUNn9w/Wp+9ItABS4pKWgYlIBTqSkIAKWiigYlFFFABRSikoEKOlFAooASilooGFApaSgQUUUtAwFLSUUAFFLQKACiiigQtJRRQAUUUUAFLRRQAYooooEFKKSlFABSikooAWikFLQAUUUUDCiiigAoooxQAA0tIKUUALRRRQIKKKBQAUtFFACClopKAFoFJS0AFFFFABRRRQAUUUUAFJS0UAFJRS0gAUUUUwCiiigAooFFABRS0UAFFFFACUUUUAFFJS0AFFLmkoAKWkFLQAlLSCigBaKKKACiiigAoxRRQAUUUUAFFFFAC0UUUwCkpaSgBaKSloEFFFFMYUUYopCCloooAKKKSgBaKKKACiiimAUUUtABRRRQISiiigApaSikAopaQUtMAooooAKWkpaQgooopgFFFIaQDT0NULtuCKvOcKazLtuDTKRRfqagnbC1Oaq3B4oQGVeNkNmqJJ9BVm6fcSMdqqBmwdoyR0Ga1RnJj27k4AoDZxmh0JjLHHTse9MHLLg4UfrTJbH/ALs5yVJxyKaV3AYPT35pzY38EY6YpD8vfFAhgbaxU/Ng8+1AxzjoaccAEtzu7jvQv3c0AhGKphRyAMfhToSTyBnsKZ9/5v8AJqVPlGwgh/T2phre/QeqbUOTyTT1GFPFRqN5BJ6VKSFHPFIoQcAYqeJPMXvUSHLZHQ9qsRKcbc4ye1AG34ZtVMpZuTGK6cVkeHohHBIwUjcRWvWb3GhaKKKQwooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDGpKdTT1oNQooFFIBKXikooEHegUAZpcUAJiloooAKBRQKAClxSUtACUCigCgBRS4pFp1ADe9FA60poGJRijFAoATFFLRQAGkooAoEKKXtRQKAEopaBQAClpopaAEPWlWkpRSAWkIpRRTAQUCloxQAUUUUAKKKO1FAwozRSUgCigUUwFFFAopAJThSYpaAFFFJRQMUUUlOFAgxRiiigBtLRRigAoozRSAXFFFFMApMUtFACCnYpKWgBQKuQ/cqotW4fuU0TIJv8AVN9KxG+8a2rg4hb6Vit941aMmIKXNJS1QBnNOQfNTKkjPIoBF+H/AFYp/amRfcp/aoLCq94cJViqt4QQRSZSGWn3PrU1RwLhBUuKkpCUoooHSkMKKKMUAFFFAoAKKWigA7UUUUAApO9LRQISilpKACiiigAooFLQAUopBS0DCiigUIAooooEHaiiigAooooAKKKM0ALRQKKBBS0gpaBiUtFFAAKWkFLQAUlLRQIKDRRQMKKKKAClpKWgQUZoooAWgUgpaAFopAaWgAooooAKKKKACiiigAoxRRQAUUUUAFFFFABRRRQAlLRRQAUUUUAFFFFAC0lLRQAlFFFABRRSUALRSUtAC0lLSUAFFFFAC0lFFABRRRQAUtFFABRRRQAUUUUAAooooAKKKKACiiimAUUUUALRRRTADS0lLSEJQKKKAFpKWkoAWikpRQAUUUUAFFFFAhaSlpKACiiimAClooFIAFLSUtMAooooAKKKKBBS0UUgEooopgiKc4Q1kXLHNady3ymse4bL5FBRG3FUbt8Katu2AayrqblsHI9apAzOuj85UHk8mo1BXkDk06SQbtwwc0sLGbecAKnGSep+laGOjYjfOBnIA9+tCjA4IzTXZsERgFutIj7jwCPrQhD3LBBggYI7c0wlWXOMk9SaeOc5OMUzAZQVJwelMAOGUAHBFIuQwHUY4pyL260FQGBJIoHy6XHDKtzRjdI0hBz0BNJvUHO7j3qRTxxSFcItu7LHAz1p3mrKAUyVPTIxQuOe+KUuC2CfpQBInoOtWIkZiAB3FV0TZKctzWlZwNNIqqeSQMUmNHW6anl2UYxjIzVqmou1FX0AFOrMoWiiigYUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBjZ4pKQc0tBqFAoFFACGiiloEApabSg0AFFFLQAhoFLQaQCClzSUUAGKUGk70tACiikFOoGJSiiigBCKTmnUhoAQUUtGOKAExxQKKWgQUgpaSgYtGKBRSABRS0hpgJSgUUopCCiiimMKKSigBaKKBQIXrRQKKBhSGiigBRQaBRSAKDRRQADpQKBS0AKOlJS0lACr0paaKdQAUGkooAWiiigBKKKUUgEpaSigYoooFFMBaKSloEKtXYvuCqS1dj+6KaJkR3hxbufasUHPWti/8A+Pcj1rI24q0ZgKBRmkqhCinxcuKjqWD71AI0I+FFOpi/dFOqDQWqN8SMEd6vdqo31JgSW/8AqhUlMgGIx9KfUloKB0ooHFIYtJQaBQAYoFLRTAKKKKACiiikIKKKKACiiigQYooooAKKKKBoBS0gpaBhRRRQAUCigUCCiloNACClpBQKBBRRRQMUUUUUALRRSUAKKKKKACiiigAooooAUUUgp1ACUUUCgApc0UUAFApKUUAFLSUUCFFFAooADRS0lABS0lLQAlFLSUALSUUUALSUUtABRRRQAUUUUAFFFAoAKKKKBhRRRQIKKKKACiiigAxSUtFACUtFFABRRQKBhRRRQIKKSigYtFJRQA6ikFLQISilooAKKSigBaSiigBaKTNFAC0UUUwAUtJRSAWiiimIKKKKAFpKWkoAKKKKAClpKBQAtFFFMAooooAKKWkpCCilooAKKKKAFopM0UwFooooELSUUCgBaKKSgApDS0jcCgaKd22KyZjlzWleNxWY5yTQUQTcCsq72gMpGc8YrUuG4rGu3LEnPfiqiSygBtYjAAHAof7uQoJBp5XikK9q0MbBGo3nrkihGUk8gkfpSZweKWNVGeOvNAxsmXzgjFOG3JIGATSNhSBnB9aRj8vA707iJARjimj52K9aQDoeh/nQ3JyDQVfQRk4O5i3PcdKlRW35ZgUx0A5piKzDAznuR6VOqhQRzmkTYRQMkj+Lmpdisu1u9R7fu4faO/FSAp53HzFV5Pagdh0Kndz17Vu6FE73sJH3FyW+vasaMZIIrpfDA3pLJtI2/L9algjfooFFQULRRRQMKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAxcYFIKKWkahRRQKADFJS0GmIKKAc0UDEHenUgooELQaKSgAoFKKKQCYpaKTFADqKB0pccUDCikNL2oASijtRQAdqWkFFAgNFLikoAKMUYopAAFFLSUxhS0lL2oAQ0tJS0CAUmKUUtACUUUUAFFFFIAFLSCgUwFpKWikMKSlxSYpgLRRRQAYpaKSkAopaQClNAAKUU2lFAC0mKBRQAUUZpaBiUooooEFApBRQMWiilFACUoooxSAVetXk+6KpL1q6v3RVIiRW1E4grKOcVp6n/qB9azGNWjMSgUUVQC1JAPmFR1Lb/foYIvjoKdSdAKWsywPSqF38zEZq+elZ9z98fWkNE8P3BT6bHwoxS9aRSDvS9aSikMKBRRQAtLSCigBaKKTtQAtIKKKBAKUUCigAoFFFAhaSiigYUtJS0AFFFFMYUUtJSEFLSUtABmkpaKBCUtFFABRRRQAUUUUDFopKBQAUtJSigAFFFFABS0gooAKcKbS0ALRSUtABRSUtACUUUtABmiiigQUtFFABRRRQAUopKBQAtFFFACUUtJQAUtJS0AFFJRQAtFJS0AAooooGFAoooAKWkpaBCUYpaSgAooooAKKKKACiiigAopaSgAooooGJRS0UCEzRRiigYtFFJQIWigUUAFFFFABRRRQAUUUUALRmkooAdRSUUwFooFFAhaKSloAKSiloASiiigAooooAWiigUwCiiigApaSikIWikooAWikpaAClpKWgAooopgFLSUtAhKKKKACmSHCmn1FOcKaBozLxsmqJPJq1dNliKqEUIZVu3AzWNP8ANJgHn61rXZxmsW5MZcsy/d46VpEmTEPXGQcelIaYgdclFPlnkj0pzHIB9aozuNU89OPWn4B3cZwaarnABXGPendjjmgBsiZUHOGpMknJIP4U58HrUQCqaCWOPXNOQjJHfHFNLc9OKcgJ5Az9KYIepXfkEbu4p5Cg7juJz0FIuWbgc04c8HselBYFPlDBuO9PJ2DFNUAIQB1NSJyaRJYt496jcAQeea67QIBDYAjHznPArlbdd5C9s84ruLWMRW8aAYwoqZFIloooqChaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAMWikzRmkahRRniigBelJ1ooFMAoooNABS0gpe1ABS0UUCEpaO1FIAo70UUALml7U2loAKBRRQAtJS0UDEooNAoEKKBRRQAUUdqDSAKDRQaBiUtHaigAoAzR2oHSmAUUUUCCgUtFABRSUtABRRRSGFAopKYhaMUUUgCjFFLQMMUUUUAKKM0CigBKUUUCgBRRSCloAMUUtJmgBKOtFHSkAYooooGLRSCnUAJSg0UUxD06irq9KpJ94VdHSmiJFLVD+7Ue9ZzVe1U/cHrWfnNWiQo6GiimIUdKmtR84qAcirFp9+hgXjSim5pRUFg3Q1n3B/eL9avseDWexLT8jgUgLS9KWkXgUuaRYUlGaTNIYopaQUUAOopB0paACiiigAoopaAAUUUlAhaKSlFAC0lGaOtABSikoFAC0UUUDDNLSCigQtFJS0AFFFJQIWkpaMUAJQKWigYUUCigAooooGKKBRRQIKKUUlABS0lLQIKKKKBhS0lLQAlLSUtAgoFFFABRRRQAtFFFABRRRQAUUUUALRRSUALSUUUAFFLSUAFLSUooASgUtJQAUUUUDClFJS0CFooooAKSiigAooFFABRSUtABRRRQAtJRRQAUlLSUDFooooEFJS0UAJRS0lAwoopaBBRRRQAUUUtACUUUUAFFFFABS0lKKYBS0lFAC0UUUAFFFJQAUtJRSEKKWkpKAFooopgLmikooAWlpKKBBRRRQAtFFFMApaQ0CgBaKKKQC0UUlMQUUUUDA1VunwKsmqV4c5oGjNnOWJqB2wtSyHmq8p4NNAzNv5CFOBlh2rKkYqSTjmr9++0gHqf5VQyF6dq0RlITc3TJA9PWigNnkgUDBGaZI9TnqcYqKRmGCFyT6GnqDnnH1pGI7g5HQigA2kRq54z2pF5ORjP0pABkM2455pc4bigQi9T9eaXBB9qQd8k809SAOee9AkKh2nJzzTy/zfMjZPcU2IiRAy5GfWnoS6KSPm6nFMq47HGQTUkCliWUjApiEAEYJqxCODSGjR0m3+0XEeMZyDwe1dnXM+G7cG4ZywO0bgB6GumqJFIWkooqRi0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAYQ5pRR2opGgopaaDilzTGBpM0HNANAC0dqTNKKBBRmigUDFozQaSgQ4Gim5pc0ALRSUd6QCilpBTqACkozRjNABmjNJ0pRQMKKKKBAKUUlFACiijpSigBKDRnFGaACkpRRQAdqAaO1FAwz1ooooEFLRRQAlKKSnCkMKSlpDQAgpaBRTELRSUUgClpKWgYUUDpRQAopKWikAlKKKBTAKWkxS0gFFJRRTGFJS0lIAooooAXFKKQUtACUUtJTESRcsKujpVOAfOKuU0QzO1XlkHpVCrupN+9x3xVKtEQBozSHpQOlADhVi0+9VcVYtDhqGMt04UgpagoR/u1QH+vIq+/3TVGMZuGpDRY6CiiikUhKSnUlIYgNOFNFOFACilpKWgBKKWkoAWlpopaAFzSUUUCCiiigANFFFAAKWigUALRSUUAFLSUCgYopRSUUCFpKKKBhS0UlAhaKKKAAUUUUAFFFFAwpaSigQtFFFABS0UUAFKKKKAEooooAKWkooEFLSUtABRRRQAoopBS0AFFFFABRRRQAUtFFABSUtFACUUUtAxKBRiigAopaSkAtJS0lAAKWkopgLRRRQIKKKSgAooooGKKKBRQIKKKKACiikoAKKKBQAtFFFABRRRQAUUUUAFFFFABRRRQAUtJRQAUUUUAFFFFABSikpaYBRRS0AFFFFACUUtFIBKUCiigQUCiigAFFFFMAoopaACiiigAooooAKWkoFAgpaSimA6ikpaQBRRRQAUUUUAIxwDWZdnnNaEhwprLum60DRTaqs7YFWieKp3ZwKpDZkXzYLPjnHyg9KqnbjPAB7CpL6TzJNobgVC7BQBjOSK0MJMAeDQo+XHIzS5UA5xgUbht+tMQoXAwDTVI83B64oV9zDFDH5sjpQIRhznNKFJPHalcrnj9KQAZyeWxzQMRxzTo+vPPFJgk9sY6Uqg7t3GKBDgCOBj6VLEMLzTMgDJY5z6UvPYkigFuSKuOKtRFflXPJ4qomdwJq9GMocYyPWhjTOm8NRbLaRipzu2gnuBWzVPSofI0+JMH7ueauVky0LRRRQMKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAMPtRUJlAxk04SgDNOxpckpR0pnmDGc0B80WBMkptH1oyKQwoozRmkAtANAopgFA60ZooELmkoooAUUE0lFIBy0p6UzpS9aADPtThTaUUDFNANIaBQAtFJSUALS02lBoAWigUmaAFNApKWgAzS0lFAhaKQUA0ALS0UhNIBaSgGigBaKKKBi0hozSUALRRRQAoopBS0AJRRS0DFopKBQAtFFFAhaDRR1oGFFFFABRRRQAlLRRSEFGKWkoABS0lKKBhRS0lMRJAPnFXKq233qtVSIZk6kc3BqrVnUDmYn3qrmrRAGlFNpQaAHVZtRmquat2Y45pMaLK07mgUVJQx/umqkWBIfU1bl+4aqQcs1SUieg0UUDCkoopDDFKKSloAUUUlOoAKSig0AKKKQUtABRiiloASlpKKACiijFABSikooAWiigUCClFFFABS0lLQAgpaSloGJRRRQAUtJS0CCiiigYUUUUCClpKUUAFGKKM0AFKKSlFABRRRQAUUUUAFFFFABRRRQIWlFIKUUAFFFFAwooooEFFLRQAUUUUAFFFFACUtFJQAUUUCgYtFFJQAZooopAFLSdKWmAUUUlAC0UlFAgpRSUtAwFFFFAgooooAKSlooASloooAKKKKACiiigAooooAKKKKACiiigAooooAKKKSgBaKKKACloopgFLSUtABRSUtIQUUUUwCiiikAUUUUAFFFFABRRS0wCiiigAooooAKKKKAFoooFMQClpBRQAtFFFIApKWkNMCC4bC1lTnJNad0flNZM5O40iiFuBVG7k6gdauyHisi/fD5LADBGMVcRNma+GYn1prAE8DimBQcMScrnine4HX0qznYqqMcjOaDg8ClPTpTAdp9/SmAAgErjnrQM/UU5xjg9cU1RxjNACquc5PSlAwckUYwp/nTUB2YJOc9aYxx+XJBAPv0pygkZYjPsMVF25JyD3FSKx6dqBXJOqkbj1z04pyoOPSo8sQQMcHvTowxX7wTnuKBXJUxuFaFgm+VY+W3sOKoQrjgnJ9a3dBh3XkRVT8vJNJjidWihVCjoBinUUVkaC0UUUDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDlc4PNBagEkfNRirAXdxSo5xzTCKKAuTiU9zSiSoOtFKw+YsiQU8OKp7iKXeaVh8xb3dqFbmqoc45oEpFAcxcHr2oLDtVYS8UqyUDuWOtKKhD+9PV80h3Hk0UgIpcjFABS0DpQaADsaWkopDFopM0vagApBRRQAUCiigAopaCKAEzS0go6UALS00UvagQtIeKO9L2oAAaOtNFOBzQAUClpMUgHUUlLTGApKKXNABRmig0gF7UlGeKBQMWkoooEKKKSgUAOFFFGaBiiikpRQIKBRQKBhRRRQAlLRRSEFFFFAwpRSUUCFoFFFMCa2+9Vqq1sPmqyeBVIzkYt6R57jPQ1X71Ld8zMfU1FVkBSUtGMUAKKu2n3aoir9qMRikykWAaKQUtSUMlJCmqtv1J9as3H+rNV7YcGpGibtSUtFIsSinEcUlABRRRQAoFLTRS0AJS0hooAXNLTRS0ALRSUtABRRRQAYpaTNKKACkpc0UAGKSlooAWikoFAC0UUUCCikpaBhRRRQIKWkpaBhRRRQIKKBRQAClpBS0AFFLRQAlFFFACiigUUDCigUUCCiiigAooooEKKWkooAWikpaACiiigBaSiigBaKSigApaSloASlopKACiiigYUUUUAFFFFIApaKKYBRRQKBCUUUtABSUtFABRRRQAUUUUAFFJRQAUUUUAApaKKACiiigAooooAKKKKACikpaACiiigAopKKAFooopjFooooEFFFFIAFLSUtMAooooEFFFFIAoopaAEopaSmAtJS0UAJRS0UAFFJRQAtFJS0AFFFFMApaTtS0CClpKKACg9KKR+FNAyndvwaypDkmr923JrObOaQyKVsKax71wTz1rVuDhcVh3sgLEA8A1pEmRX49Ka+BjBpQ/GCKRjx261Zix3UU0IoORnd9acMA9RTWHcdaBMbn58Ac0iqc8dSacq+vWlKjB5+agBuDjrk04ZApAAOBnPWlBOCBQAZx+NPXP8ACR+IzTFXOQR1qQD5cCgLAG65xUoVcA45NRhdxIAJqUAHapPzY6UwsSxfex610/hiIgSufTArmYFG5dvIJxmu00GIRWA9Sx5qZDiaVLSUVmaC0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAHLhMd6Nue9LRmrAaUxRinE02gQmCDSnpRS0xDaKXFGKQCUUCloGJQtFFADs0BiKaDzilosO48Sn1pfNqKilYVydJak82qhJxQGIFFh8xcDj1pd1Uw59acshpWHzFsGlzx1qqHPc05ZPWlYaZZzRUIlHrThJnvSsXckozTA49aduFAXCjNNLgUoOeR0oFccKDQDRmgYClpKM0ALQKBRmgBKUUlOoEFLSCikAE0Zo60AUDFopKMUALRRRQAtFNpc0AKBRQDRQAUCjOKBQMdRRRTAKKTNLQIM0opKKQxaKSigBRS0lFABR3oopAFFLRQIKWkFFMCxbdanY4Un2qG271LJxG30qkZyMKfmQn3plPk5dvrTKskWim5pQc0CFXk1fgGEqjGPmNX4vuCpZSJBThTVpwNSURXP+rIqG1+6akuj8pqO2GE/GkUiaijFFIoWkoFFACAUuKKWgBKKKWgBKSlooAKBRQKBBS0lFAwopKWgQtApKWgYUUUooASlpKKYC0tIKWgApKWkpAFLSUZoEKKWkzRQAUUtFAw7UUUUCEpaKKACiiigBaKKKACgUUUALRQKKACiiigAopKKAFFLTadQAUUtFAhKWkooAWiiigAooopAFFFGKYwooooEFFJS0DCkpaKACiiigApaKKACikopCClpKKYxaKSloASloooEFFFFABRSUtABRRQaAEpRSUUALS0lLQAlFLSUAFJilooAKKKKACiiigBKWkpaAEoFLRTAKKKUUgAUUUUAFFFFMApaSloAKBRRQIKKKKAAUtJS0AFFFFABSUtJQAUUUtABRRRQAUlLRQAlLRQKADFLRRQIKKKM0wAUyU4Wn1BcnC0DRnXbdapmprlsn2qBjgUhlW5OOvpWFKRIzDpWpqMvp1NY5LbsnoTWiIkxikoxUkMB/FQSG/ClbHel6dhVmItJ0zSjlc8U0HgH2oGOXATJ65xUUmSw2kg56gU4HBIJ60ob0NAARnOOKQfrRt3cCnRkAYIJz0PpQIF4GTxTt4U8HJPoOlI+857g+g6UqqRigB4Ypz0zU8Z3HJ61DuPADD8Rmpox82M5OaBlqABWX1LDArubSLybdEPUDmuS0uES3cIwPvjrXZ1EikgoooqShaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDlgSRyKU9KQ+lL+GKskO1HFGeKbQMXmkZ1QZYge9KCaXNMQZyOKKM0mc0AIKWgUY4oATFOApOlKKAG4OeKMcU7NITQAg60uOaQUtACHvQKMZo6UgFxSY96XtQKBiE4FApSM0AUAANBY9jRikzSsFxyuad5hFRgUZosFx5kNKkpx1qI9KVRRYLk4m560/zRVYUueKLFcxbEoNKDVMORTlkNKw+YuBhRVUSGniWlYfMWBS1B5vFOElIdySlHNMDUu6kFx1JmgEGjigBaKKKYwFLSCg0gFoopM0AKBRRRQACnU2jNAx1FJRQIWjNJRTAdRSUUDFopKKAFooopCFozSCloAKWkoFAC0UUUwLVv0p9wcRN9KZbdKdc/wCpb6U0ZyMSQ5Ymo6c/3jSVZAlGaKMUAPQ81fj/ANWKz0+9Wggwg+lSy0PFLmkFFSUQ3R4+tFuB5Ypt0eKdD9wUhokFLTRTqRQlFBooAKWkzS0AFApKKACiiigBKKKKAClxQKWgBKBRilxQIMUgpaKBhS9qKKAEooooAUUUUUAFFFFABRRRQAoopKKAFoFFFAhaKSloGFFFFAgooooAWikooAWikpaAClptKKAFoopKACiiigApwptKKAFopKWgAooooAWikopALRQKKYBRRRQAUUUUAFFFFABRRRQAUUUUALRSUUgCijFFMAooooAKKKWgAooooAKKKSgQtAoooAKSiigBaKQUtABRRRQAUUUlAxaKKKBBRRRQAlFFLTGIKWkopCFooooAKKWimAUUUUAFFAopAFLRRQAUUUUxBRRRQAUtJRSAKKKKAFpKKKYBS0lLQAUUUUAFFFLTASlpKKQgpaSigBRSUUtACVVu24xVkniqF4/FAyhOOc1XlPy1Mxyear3DYQmmDMu8OTxWYwy3ToavXD9c1RLFT3Oa0Rmxr5OccGjdhQO9ORgM7gSfWkGH5FUQOUYU03cAFHfvxTsjBXvmmt6kg96AYxMlckc0obv3oBBHB+tCqGGaCRedue1Kg4BFI8ZVc9VFAXgdc9eDTHYlXg9M4p4HtTByMU9MscKM84pAKFAPHWrES81XUgnPBzVqJSQNvUmgDd8NRbrtnxwi/hXT1jeHIQkEkmMEnFbNZs0QtFFFIYUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAHKUuaarDuaXINVcQoNFJRTAdRSCigBaSjOKTIoELQKDQKYC0maCaQUCFzzS0UlIApaKBTAKTNLSUgFpaSjNAxaWmilpgFJwKWkxikAfhRjJpc0ZoATFJ0p1FACAc0H6UtFADaUUYooEAFLRSZosO4uacHxTaMUrDuPEtL5xFR4oFKw7k6yGnCQHvVfNGaLDuWhIKcGFUw1O3kClYakW80uc1UWU1IJqLFcxYoxUImFPWQGlYLj6Wm7qNwoGOopu6lBFAxwoNJS0CAUtJRSAKUUgpaYBRSUUALmikopAKOlKKSgUAhTSg0lJ3oGPFJ3ozQOaYi3bfdouzi3altxhabff8e5poyZiMcsaSlI5NJViCiijFADox8wrRH3B9Kz4vvir4PFSykOU0tNHSlzipKK10ecVJF9wVFcH5qmT7opFIfQKKBSGFJS0lAC0ZpKKAFopKKAFopBRQAUUtFAhRQaBRQMKKKKACig0UALSUUUCCgUUooGFFFJQAtJS5pKBC0UUtAxKKWgCgQUUUUAFLSUUALQKKBQAUtFFADaWiigBKWikoAWlFNpRQAtLSUUALRSUZoAKUUlKKACiiloAKKKSgBaKKKAAUtJRQAUUUUAFLSUUALSUUUAKKKBRQAUlLRQAUUlKKACiiigAooooAWiiigQUUUUDCiiigQUUUUAJQKKKAClpKWgAoFFFABRRRQAUUlLQAlLSUUDCilpKYBRRRQAoFFKKKQgpKKKAFooopgFFLRSAKKKKYgooooAKWiigBKSlpKQwpaSigBaKSimAtFJRQIdRSZpRQAUtJRTAKKKKQBRRRQIKWkooGNc4BrNu261fmOFNZN2xLH0oAgz1qpdthD61aPAqhdPwR3qkDMi6JPGc9OtQEgEZqScDJxkE1Fg7Tz0OCatGTFJBGAeKbnawHrTgARkD8aQrlxg8CmIQfeYnPtTc8lcduMU98A8UzBVsg49aZNhIwq8McsfWnDCnIppO58rz604dxjgUCsPDbhtJ+XuKeFC+9RqvzcHJPanIG3uGGGU4xmmUOA74NKenQ0biDSoN/Qc/lSEPRMKMDircKEtGV7YqugIbB7cVfs1Mk6x7cg4FJjSOv0uEQ2KLjGeauU1F2oq+gxTqzLQtFFFAwooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAOIWXr2xTvOPY0xlzzQBx70hEyTD1p4lB6VUI9DzTlOBTuBb34FAfNVFc7femrIxZgrd+9O4F6lxVcS46mnLNxyaLgS0tReaKUSAnrTuA8UtN3D1pdw9aLiHZopoNKGGaYgpc0h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OAcn0pFPsadjdwDg0AOQfLx196kTOMd6iGVOD0qRAWBwQPqaARJtP94Usf3sZBPtUcYK7xkHLCpo1G4EdaYixD97njNdfoMPlWGf77Zz6iuUhA3rlc5IFdxaRiG1jjHRVAqJFImoooqCxaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA5ooTSbCRU+BSYqBldos9ab9nX0qyRSYoApta7ulM+zEdqvAc0uygZmNA4JxTQhGa02jHcVH5ANAGdgmjdtYA96vm2FNe0BHbNO4rFLdSE54qwLYhQOvrTWhx0FAiLcAwB7in44qMxuTwpGKdsbaQcnikAtIOopADikzzwaoB9NxknNKGzS9+tACAYFLSBuOadn34ouAmT68UZPaj6UgouA4ucdakSTioc0UXAseaO9AlFV6adwPAyKVxFzzB60ocYqnvOacjHHWncC3uHajINVw5Bp3mVVwsT5yKUGq6zADFOEnNFxWJe9LTA1G6i4DxQaaDS07iFXPcUppoOOKdmi4wpRSZ5ooGBoFBNJmmIcaSiloAKKKKACgUUUALSUZooAM0tIKKAHCg0gooAKUfpSCloAKKKM0AGKSlBpcUANxxSCn4pDQAnalox70uKAEpDTqMUASQSbDxT7mTfjnmoOlIWzQAh60UUtAAKKBR3oGPhPIqyDzVVOKlD81LGiwCKjlkwpphkqCRiQRSsO5nzzk36gdAMmti3fKLWQ9nun80E5HatC1bC80rFJl7NFR76UNSsVcfmim5zSjpRYYtFHFFIBRS0gNLmgBKWijNABmlFJS5oGFLmm0UCHUU2lzQAtLTKcKAFooooGFLmkooAWiikoEFLRSUALQKOtFAC0UlFAC0UUmaBBSigUtAxKKKKAFopBS0CCkoooGLRSUZoEFKBSUtAwpaBRQAlFLSUCCgUlKKAFopKWgYUUUUCFoFJSigBaKSloAKSiigAooooAM0UUlAC0UUUDCiikoAWikooELS000oNAC0UmaWgAooooABRSUUDFFLSCigQtJS0lABRRSUALS0gpaACikooAKKWkoAWkoooGFGaKKBBQKKKAFopKKAFpc02loAWikozQIXNFJS0wAUtJS0gCiiigBaKKSmAUtJRQAtNpaSgAooooGLRRRQAUUCigQUUUUgFpRTaUUCFooopgFFFFABUcxwpqSq9y2FNAGbdHk1VPAqaZssaryH5aaGUrxxg+orFlcMSxOfpWpesMGscfez2q0RIQnAHvQQeCD+FBUZzml3YAxzxVGQUcEEHkUJ1PP4Uh49qYEasduD8p7inYXdkE4PrQQASeue1NT7p4I9KBEi4JIFKDzz0psBf72AcAjFPGSACOnpQNClhnHOakGAvI5NRpg80/AYgsTgelAmPX06+9SJ7VGOD8ueatQABSMdTmgFcv6Vbie6hRgeucV2grmfDKb7jd18tOtdPUSNELSUUVIxaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAwBS0UYqBiUYpQKAKBjcUtLRQAlJTsUlACEUm3Jp2KKAGbAKayA1NjmkOKBEHl4zxTWgB7VYxRigCoYB6VG1tnNXitG3imIzGtmBAVc56mmCFwTmtQrSGMelAGW6lVyRimjPoa1PJU9VBpjQj0oAz0Zudw4zxRuq29uDxUZs8gjkCgCsWpQc082ZXoSfrSCBlNAgGM0jGlIYD7pNMVwykgUhjlw3WlxjPBpobn0pdw9aYDqMU3PvSg+9Fxi0ZPYUA0tMBvmsKPMU4LZx14pdvWmFRgCgmxKZwDncKcs2e9QqoHYU7bxQFidZBT/MqpgjpS5YUXCxb3ZoBqosjDvTvPNNMC1mlBBqqJSetO84KKYFjNGaj8ylDU7gSUU3cKUGi4C0gozRQAuaWm0opiFzxRRRQMM0Ug606kIM0lJSimAtJRQKAFFOzTRRQAuaKKSgQuc0tNBpTQMWigUCgBCcCmg5pW6U1TQMcKU0gooABRRmkJoEODCnA1BuwalU8Uikx2aQilBoPNADSBSqcUUUAODU4PimDpRSC5IJaestV6Wiw+YseZTw4NVMmlDEUrD5i2HHrQGqqJDThJSsPmLQbNLmqwkp4lFKw7kwoqMSClDigdx9LTQwpQc0DuLRQDRQAUopKWgBaBSE0A0gFpaTPFANAC0lFFAC0UlAoAWiiigBaKM0ZoAKSlooABTqbTqACkpaKAEooooADS0lFAC0UlLQAUCigUAL0ooooASloooEJSiiigAooooAKKKKAClpKUUAFFLRQAlFFFACUtFFABSUtFABRRRQMSiiigQUUUUAFAoooGOooFJQIWkoooAKKKKAFFFAooAKSlpKACiilFABRSUUDHUlJmloEFFFFABSUtFAwooooAKKKKACiiigQUopKWgAooooASloxRTAKWgUUhBS0lFAC0UUmaADNLSUUALmkoooAKBRRTGLRRRSEFFFFABRRSUALS0lKKAFopKWmIKKSigAzVO6brVtjwaz7tutAyhIf3hNQSng+1Ssck1WunC/lTQMy76RefmwxGFrNjj2gAscAfnVi/G9gc4KnNRIcqT6VojFu40phs5pNvXJJzSkjoRmkzVE2GKCDnPFP+vIPakUhmIJA780kh2tweBQC2Eb5SMYFIBubP6Ubg3PX6Uo5Pv6UCHlz/dINOQ5GT2poG4fSgv5ZAx1PXFA9tSVRmQlsY9qcVw3XNJzjPGfal3ZAHqKAJUNWI89hVRM5HWr0IIXnoB2oHFnTeGIdlm8hHLNgVtCqekwmGwjVhgkbsfWrlZspC0UUUhhRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAGDRQBQKgYooopKBgKKBS0AJSClIooAOtHelFBoASkPWnUlAhBRRiigAxRSmkoEFAFKKKYxuKTbTzSAcUCI9vNBWpKUDNICHy6Qxg9RU/TNMxk0AVzCPSmNbr/AHRVzAppFMCkbZfSovspU4FaQUUhQCkBmNCyg0gUkZxWl5Y/Ck8lT2oGZnOelGSK0GtlweKiazBx2xQBUDH1xQMGrDW2DxTWtyOlO4iMGjNIYW9CKbtYN04oAeT1ozTeRRmgBcYoKgikz1pc5ouFhpQ9jShSRjNKGoBp3CwgZgxz0xQZCBmlYjHNIOlADxIwHNOWY8VGaBQBOJqXzqgxSEccU7gWhKCM04NVMdOKQO6g96dxF8NS7s9Ko+cwHvUizYApXAsg0vWq4mBqRZRg8ii4EgozUayZFO3Zp3EOB4pQaYCKXNMB4opoajORQA49KQHNJnIoHApiFFLmkpQaAFoFJQKQwY4FMTpSynikj+6KBjqXNAoNMQho7UUUCIjjPPWpl6VEfvVKooGKKXNIOtBoC4ZozSUUgH0lAoNAwooooAWikzRTAWkpRSYpWGLmkzSmm4osK44ORT/MNRUUrDUiYSGnCWoQaKLDuWRLSiQVVBpwOaVhplrzB604PxVPdigSEUrDuXQwpc1UWU07z/Wiw7lnNANVxNmnCUUrBcnzRmovNHrShwaVh3JKKaGpQaAHUZpKWgBc0optLQMWiiigApRTc0tAC0UZooAKKM0CgAooooAKWikoAKBRQKAFpaSigAoozRQAtApKUUCFpKO1FAwooooAKWkooAWlpKWgQUlLRQMSiiigApe1JRQAGiikoEKKSiigYtAoooEFFFFAxaSijFAgpKWigBKWkFLQAUtIKWgApKKKACikpaACg0UUAFFFFAC0UUUDCiiigQUUUUDCiiigAoopKAFoo7UUCClpKBQAtLSUUAKKSilFABRRRQIKSiigApaSloASloFJQAtFJRQMWlpKKBC0UUUAFJS0lAC0UlLQAUtJRQAuaKSigBshwprMum61oTHCmsq5bJIpgVzVLUGwpI9KuPWffv8AJ71SE9jJuGy3vUNOdtxJ96bmtEZXEbFDDLD6UMMnOeKUj5eOuaBMBlfxppxzT2bI5A+mKaeRnApisMVTyTT0B/D6U0HdTgTnjpQApbbmlzubcaZvBBJHANPxzxjFAMcGyBjpT1+7ntUYUjjtUkTrjYOqj0pEkiHy8EDduxWnYR750A5yQCKo243sMjAA6Gtnw/BuvweGA6+1DNEdZGu1FX0AFOoorMoWiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig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BcbyKXJ9adim4pWHcAxpwkxTcUmKVhpkolpwlqCjOKXKPmLQmp4lqmDShiKXKUpFwSU4MKp+ZxSiUilYOYu5o3VUEp9acJaVh3LOaKhEtOEmaVh3JaKYHFLuFMLjqKM0ZpAKKKSlzQAUUUUDCigUUAGKKKKAClFFJQIXNFJRmgY6ikooEFFFFAC0UlFAxRS0gpaBBRRSUALRSUUALRSCloAKSlooASlpKKBhS0UUAJRS4pKACiiigAooooAKWiigApKKKBCiikpaAClpKKAFpaSigApaSlpgFJS4oxQAUUuKSgBKKXFJSAKBRS0AFFFJQAtFFFAgooooAKWkopgFLSUUALUNw3ympaq3LcGgDOuG+aq7ng1JN96opDhc0wM69cbTWNI4cnCkDPQ1pX7NyFGSO2aymOSc8A1aIkxQFxnvSgKRknkcYpg4PFOCjJJHWmZodTS454JpcdetNPHAzTBh94Y6UKAc89KRT15zQJMNgg4xgj1oJHZxwRTgy555PtSY3AE0A4NMLjxyakA5GMA880xRuNPVQrd6BhtwQGwT7VahBAz2qJenvU6glcL1pDRu+HLcPdebgYRevvXT1i+GIito7kcE4FbVQ2UhaSlpKQxaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAOfGdvWnDmgCisxhRSHrSimAUUYo6UDCjtRRQIKKByKKADNJS4o49aBCUtFKKBgDRRRQAlAoNAoAMUpoooASig0o4oAKTNLjIpMUAFKBRiigApKWigBMc0tIOtLQAUUUUAJRS0lAC0UUCkAUUUlAwooopiCiiigQUYzRRQACiiigBe1JRS0AJRRQKACkpaSgBcUmKWigBMUUtJQAYopaSgBKKWigAFIRS0UANxSYp1JTAaQKrTLVk1BP0NMCNKk7VHH1qWrQhRQaKKBiYpGPFONMYcUhFYffNSkcUxPvGn4zSGRulVZX2jpVx6ozKXlCrjNIBUfKjjFOBoFuygZ60CJs9KAHrRSYII4oGcnigBcA0owOBTM80oPNAD896QOeo6GkHSlyKAFDt2p4mI60wEY4FHU0CJlnxUiXB/CqhA9aUHHFFwLnnAGpBLkVRB4pQxHei4WL4lXHWnK4Pes7eQDQspTFVcVjTzS1RF16U5Lo55ouBdo4qAT+9PWUHvTuMfilpocU7I9adxBRilGDS4oAbilApcUYpgNpRS4oxQAlApSKQCgAFLQBS0AJRS4oAoEJS4pcUUwExRS0UAIKXGaAKdigY3FGKUUtAhm2jbTqXrQBHto2VLijFICApSbc1OVpAuKAIdtG01Nto20DICDSYqcx8U0x0rARiinlaTZRYLibiKcHNJtpMUuUq4/zDSiU9%E2%80%A6", folderName: "Protonet Messenger", quality: 100, width: 100, height: 100, base64: true};

window.ImageResizer.resize(options, function(image) { debugger; // success: image is the new resized image }, function(i) { debugger; // failed: grumpy cat likes this function });

Always execute the error function and i="Error"

Short on Time

Hey all readers of that issue...

At the moment I don't really have much time to take care of this repo... I never thought that it would get mentioned in the documentation of ionic and I have no idea how it get there. If someone feels fine to help maintaining this or at least fork this repo and done more cool stuff with it in the future I would be happy to add the person here or would write a link to the fork in readme,... someone interested?

Image proportion

Thanks for the great free plugin.

Documentation should be slightly more clear. I don't clearly get if the proportion of the image is changed.

      width: 1280,
      height: 1280

Shouldn't it work also by just providing either width or height and not mandatorily both?

Thanks

ImageResizer blocks thread

PluginManager: THREAD WARNING: exec() call to ImageResizer.resize blocked the main thread for 150ms. Plugin should use CordovaInterface.getThreadPool().

Hi when we are going through multiple resizes, we get the message that the thread has been blocked.
Is this something you are looking into or planning to fix?

IOS gives back an empty base64 string

On IOS 12+ the base64 string is empty.
In options I gave a base64 image string but in return only this string "data:image/jpeg;base64," was coming back in success function.

Missing folderName causes error on android

An obscure JSON exception is triggered on android if you forgot to include folderName key in your config. Should probably mention this in docs.

In general, it seems errors don't bubble through to the web console and with logcat they are also obscure as the original error isnt printed.

This probably applies to other config keys too.

Android build fails without cordova-plugin-camera

Hello,

After installing the plugin on Android platform, I get the following error:

/platforms/android/src/info/protonet/imageresizer/ImageResizer.java:12: error: package org.apache.cordova.camera does not exist
import org.apache.cordova.camera.FileHelper;

Guess, this happens because of missing FileHelper class from cordova-plugin-camera. I tried copying getInputStreamFromUriString to this plugin, but it requires other imports and methods, so I gave up after dozens of build errors.

I guess we should specify dependency on cordova-plugin-camera in your plugin.xml or ship the FileHelper with the plugin.

Webkit error in iOS

WebKit discarded an uncaught exception in the webView:decidePolicyForNavigationAction:request:frame:decisionListener: delegate: *** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]

This code cause silence in ios:

PHFetchResult *savedAssets = [PHAsset fetchAssetsWithLocalIdentifiers:@[fileName] options:nil];
   [savedAssets enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
       //this gets called for every asset from its localIdentifier you saved

       [[PHImageManager defaultManager]
        requestImageDataForAsset:asset
        options:imageRequestOptions
        resultHandler:^(NSData *imageData, NSString *dataUTI,
                        UIImageOrientation orientation,
                        NSDictionary *info)
        {
            sourceImage  = [UIImage imageWithData:imageData];
        }];

}];

Nested FolderName throwing exception

For Android, if we give the nested value for folderName property, it throws exception:
Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference.

sample object-
{fileName:"test.jpg",
folderName:"ParentFolder/ChildFolder",
height:768,
quality:100,
uri:"file:///storage/emulated/0/img1.jpg",
width:1024
}

Basically, i would like to copy the resized image in a nested folder, not in only parent folder.
So, if the value of folderName is 'ParentFolder', it works.
Can you please fix this issue so that the resized image gets copied to other nested folders.

License file missing

Hello,

i'd like to use this library for a commercial project.
Could you please add a License?

Windows 10 Support

Would it be possible to add windows 10 support.

I don't mind creating a pull request to implement this feature myself.

Unable to use the resize function

I am unable to use the resize function in iOS... it is giving the following error:

TypeError: undefined is not an object (evaluating 'window.ImageResizer.resize')

please advice..

base64: true not work in Android, returns file:/// uri scheme

base64: true not work in Android, returns file:/// uri scheme, code:

            (<any>window).ImageResizer.resize({
                uri: url,
                quality: 90,
                width: 320,
                height: 240,
                base64: true
            }, (data) => {
                  console.log('RESPONSE', JSON.stringify(data));
            }, (err) => {
                  console.log('ERROR', JSON.stringify(err));
            });

Is returned a url like this: file:///storage/emulated/0/1554074577205.jpg

iOS Error

2016-09-15 21:29:21.145 thumbnail[239:11885] IMAGE RESIZER START ----------------------------------------------------------------------------
2016-09-15 21:29:21.146 thumbnail[239:11885] Image Resizer Image URL : file:///var/mobile/Containers/Data/Application/288FAECE-4A71-450E-A35A-2F9A7A175772/tmp/cdv_photo_007.jpg
2016-09-15 21:29:21.173 thumbnail[239:11885] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
*** First throw call stack:
(0x2507791b 0x24812e17 0x24f8c871 0x24f96a21 0x11f02f 0x135c09 0x1354df 0x136955 0x258a16df 0x25039dff 0x250399ed 0x25037d5b 0x24f87229 0x24f87015 0x26577ac9 0x2965b189 0x109cfb 0x24c2f873)
libc++abi.dylib: terminating with uncaught exception of type NSException

The same code works perfectly in Android.
My environment is Cordova 5.3.3, Xcode 7.3.1, Deployment target 9.3
I attached the js source code too.

Thanks for all
app.txt

Image Dimension is not working

Hi @JoschkaSchulz,

I am using your plugin and upon using it the Image dimension is not working by setting the width and height in the actual device but when i use the emulator it works fine.

Regards,
Greg

Photos framework missing from iOS dependencies

Using XCode 7.3.1, Cordova 5.4.1, building for iOS 9.3.

I needed to add the element <framework src="Photos.framework" /> to the iOS platform element in plugin.xml:

<plugin>
  ..
  <platform name="ios">
    ..
    <framework src="Photos.framework" />
  </platform>
</plugin>

Otherwise the build was throwing errors such as:

Undefined symbols for architecture armv7:
  "_OBJC_CLASS_$_PHImageManager", referenced from:
      objc-class-ref in ImageResizer.o
  "_OBJC_CLASS_$_PHAsset", referenced from:
      objc-class-ref in ImageResizer.o
  "_OBJC_CLASS_$_PHImageRequestOptions", referenced from:
      objc-class-ref in ImageResizer.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

** BUILD FAILED **

ios bug

Hello!
it doesn't work for iOS, nothing happens when I use it:
ionic 2 code ex:
//Start
Camera.getPicture(options).then((imageUrl) => {
console.log(imageUrl); //it's displayed the right image path
let options = {
uri: results[i],
quality: 70,
width: 570,
height: 430
} as ImageResizerOptions;
//Starting with this line nothing happens, any error/log displayed
ImageResizer.resize(options)
.then((filePath) => {
console.log(filePath);
}, err => {
console.log(err);
}
);
}
});
PS: on android it works fine

Thanks, Victor

Version 0.2 isn't avaliable in NPM

Update NPM please.

In NPM 0.1.1 is last version, but I need 0.2 features for Android (base64), thanks!

Note: NPM is not auto sync


Alternative solution

Install using command:

npm i github:JoschkaSchulz/cordova-plugin-image-resizer#v0.2.0

Or put in your package.json

    "cordova-plugin-simple-image-resizer": "github:JoschkaSchulz/cordova-plugin-image-resizer#v0.2.0",

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.