Browse Source

clone from https://github.com/RealBrubru/cordova-plugin-image-processing.git

Christian Kahlau 6 years ago
commit
eb231f2335
8 changed files with 905 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 201 0
      LICENSE
  3. 86 0
      README.md
  4. 47 0
      plugin.xml
  5. 193 0
      src/android/ImageProcessing.java
  6. 12 0
      src/ios/CDVImageProcessing.h
  7. 315 0
      src/ios/CDVImageProcessing.m
  8. 50 0
      www/ImageProcessing.js

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+.vscode/

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 86 - 0
README.md

@@ -0,0 +1,86 @@
+# Ionic / Cordova Image Processing #
+
+Authors: Bruno Oliveira, Marcus Oliveira
+
+## Adding the Plugin ##
+
+Use the Cordova CLI and type in the following command:
+
+`cordova plugin add https://github.com/RealBrubru/cordova-plugin-image-processing.git`
+
+To remove:
+
+`cordova plugin rm cordova-plugin-image-processing`
+
+## Methods
+
+At the moment the plugin is only avaible on the android and ios platform.
+
+### resize
+
+    ImageProcessing.resize(success, failed, options);
+
+#### options
+  - **sourceUri** (String): The Uri for the image on the device to get scaled
+  - **destinationUri** (String): The name of the image to be saved
+  - **newWidth** (Number): Width of the new resized image
+  - **newHeight** (Number): Height of the new resize image
+
+##### example
+    var options = {
+          sourceUri: sourceUri,
+          destinationUri: destinationUri,
+          newWidth: 800,
+          newHeight: 400,
+          keepScale: true
+          };
+
+    ImageProcessing.resize(function(success) {
+         // success: 
+      }, function(fail) {
+        // failed: 
+      }, options);
+
+### rotate
+
+    ImageProcessing.rotate(success, failed, options);
+
+#### options
+  - **sourceUri** (String): The Uri for the image on the device to get scaled
+  - **destinationUri** (String): The name of the image to be saved
+  - **angle** (Number): Rotation angle
+
+##### example
+    var options = {
+          sourceUri: sourceUri,
+          destinationUri: destinationUri,
+          angle: 30
+          };
+
+    ImageProcessing.rotate(function(success) {
+         // success: 
+      }, function(fail) {
+        // failed: 
+      }, options);
+
+### crop
+
+    ImageProcessing.crop(success, failed, options);
+
+#### options
+  - **sourceUri** (String): The Uri for the image on the device to get scaled
+  - **destinationUri** (String): The name of the image to be saved
+  - **rect** (Rectangle): Rectangle to crop
+
+##### example
+    var options = {
+          sourceUri: sourceUri,
+          destinationUri: destinationUri,
+          rect: [30, 30, 120, 140]
+          };
+
+    ImageProcessing.crop(function(success) {
+         // success: 
+      }, function(fail) {
+        // failed: 
+      }, options);

+ 47 - 0
plugin.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin 
+    xmlns="http://apache.org/cordova/ns/plugins/1.0"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    id="cordova-plugin-image-processing"
+    version="0.0.1">
+    
+    <name>Image Processing</name>
+    <description>Cordova Image Processing Plugin</description>
+    <license>Apache 2.0</license>
+    <keywords>cordova,image,vision,processing</keywords>
+    <repo>http://h2779862.stratoserver.net:6000/cordova/cordova-plugin-image-processing.git</repo>
+    <issue>http://h2779862.stratoserver.net:8080/cordova/cordova-plugin-image-processing/issues</issue>
+    
+    <js-module src="www/ImageProcessing.js" name="ImageProcessing">
+        <clobbers target="window.imageProcessing" />
+    </js-module>
+    
+    <engines>
+        <engine name="cordova" version=">=8.0.0" />
+    </engines>
+    
+    <!-- android -->
+    <platform name="android">
+        <config-file target="res/xml/config.xml" parent="/*">
+            <feature name="ImageProcessing">
+                <param name="android-package" value="org.apache.cordova.imageprocessing.ImageProcessing"/>
+            </feature>
+        </config-file>
+        <config-file target="AndroidManifest.xml" parent="/*">
+        </config-file>
+
+        <source-file src="src/android/ImageProcessing.java" target-dir="src/org/apache/cordova/imageprocessing" />
+    </platform>
+
+    <!-- ios -->
+    <platform name="ios">
+        <config-file parent="/*" target="config.xml">
+            <feature name="ImageProcessing">
+                <param name="ios-package" value="CDVImageProcessing" />
+            </feature>
+        </config-file>
+
+        <header-file src="src/ios/CDVImageProcessing.h" />
+        <source-file src="src/ios/CDVImageProcessing.m" />
+    </platform>
+</plugin>

+ 193 - 0
src/android/ImageProcessing.java

@@ -0,0 +1,193 @@
+package org.apache.cordova.imageprocessing;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.content.ContentResolver;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Environment;
+
+public class ImageProcessing extends CordovaPlugin {
+    
+    public static final String LOG_TAG = "ImageProcessing";
+    public CallbackContext callbackContext;
+    
+    private Bitmap resize(Bitmap image, int newWidth, int newHeight, boolean keepScale)
+    {
+		if (newWidth > 0 && newHeight > 0) {
+        int width = image.getWidth();
+        int height = image.getHeight();
+        int finalWidth = width;
+        int finalHeight = height;
+
+    		/*if(keepScale)
+    		{
+		        //Log.d("autocrop", width + " x " + height);
+		        float scaleFactor = (width > height) ? (float)maxWidth / width : (float)maxHeight / height;
+            //Log.d("autocrop", "" + scaleFactor);
+            finalWidth = (int)(width * scaleFactor);
+		        finalHeight = (int)(height * scaleFactor);
+	        }*/
+
+	        image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
+	        return image;
+	    } else {
+	        return image;
+	    }
+    }
+
+    private Bitmap crop(Bitmap image, Rect rect) {
+        return Bitmap.createBitmap(image, rect.left, rect.top, rect.width(), rect.height());
+    }
+    
+    private String saveImage(Bitmap image, String destinationUri) throws JSONException, IOException
+    {
+        File f = new File(destinationUri);
+        File folder = f.getParentFile();
+        if (!folder.exists()) {
+            folder.mkdirs();
+        }
+
+        FileOutputStream fos = new FileOutputStream(f);
+        image.compress(Bitmap.CompressFormat.PNG, 100, fos);
+
+        return f.getAbsolutePath();
+    }
+
+    @Override
+    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
+        Log.d(LOG_TAG, "action: " + action);
+        Log.d(LOG_TAG, "args: " + args.toString());
+        
+        this.callbackContext = callbackContext;
+        
+        if (action.equals("resize")) {
+          final String sourceUri = (String) args.get(0);
+          final String destinationUri = (String) args.get(1);
+          final int newWidth = args.getInt(2);
+          final int newHeight = args.getInt(3);
+          final boolean keepScale = args.getBoolean(4);
+
+          super.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+              try
+              {
+                Bitmap image = BitmapFactory.decodeFile(sourceUri);
+
+                if (null == image) {
+                    throw new FileNotFoundException(sourceUri);
+                }
+                
+                Bitmap newImage = resize(image, newWidth, newHeight, keepScale);
+                
+                saveImage(newImage, destinationUri);
+
+                callbackContext.success(destinationUri);
+
+              } catch (JSONException e) {
+                callbackContext.error(e.getMessage());
+                
+              } catch (IOException e) {
+                callbackContext.error(e.getMessage()); 
+              }             
+            }
+          });
+          
+          return true;
+        }
+        else if (action.equals("rotate")) {
+        }
+        else if (action.equals("crop")) {
+            final String sourceUri = args.getString(0);
+            final String destinationUri = args.getString(1);
+            final JSONArray jsrect = args.getJSONArray(2);
+
+            final Rect rect = new Rect();
+            rect.set(jsrect.getInt(0), jsrect.getInt(1), jsrect.getInt(2), jsrect.getInt(3));
+
+            super.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    Uri uri = Uri.parse(sourceUri);
+                    ContentResolver res = ImageProcessing.super.cordova.getActivity().getContentResolver();
+                    try (InputStream is = res.openInputStream(uri)) {
+                        Bitmap image = BitmapFactory.decodeStream(is);
+
+                        if (null == image) {
+                            throw new FileNotFoundException(sourceUri);
+                        }
+
+                        Bitmap newImage = crop(image, rect);
+
+                        callbackContext.success(saveImage(newImage, destinationUri));
+                    } catch (JSONException e) {
+                        Log.e(LOG_TAG, e.getMessage(), e);
+                        callbackContext.error(e.getClass().getSimpleName() + ": " + e .getMessage());
+                    } catch (IOException e) {
+                        Log.e(LOG_TAG, e.getMessage(), e);
+                        callbackContext.error(e.getClass().getSimpleName() + ": " + e .getMessage());
+                    } catch (Exception e) {
+                        Log.e(LOG_TAG, e.getMessage(), e);
+                        callbackContext.error(e.getClass().getSimpleName() + ": " + e .getMessage());
+                    }
+                }
+            });
+
+            return true;
+        } else if (action.equals("info")) {
+            final String sourceUri = args.getString(0);
+
+            super.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    Uri uri = Uri.parse(sourceUri);
+                    ContentResolver res = ImageProcessing.super.cordova.getActivity().getContentResolver();
+                    try (InputStream is = res.openInputStream(uri)) {
+
+                        Bitmap image = BitmapFactory.decodeStream(is);
+
+                        if (null == image) {
+                            throw new FileNotFoundException(sourceUri);
+                        }
+
+                        JSONObject info = new JSONObject();
+                        info.put("width", image.getWidth());
+                        info.put("height", image.getHeight());
+
+                        callbackContext.success(info);
+                    } catch (JSONException e) {
+                        Log.e(LOG_TAG, e.getMessage(), e);
+                        callbackContext.error(e.getClass().getSimpleName() + ": " + e .getMessage());
+                    } catch (IOException e) {
+                        Log.e(LOG_TAG, e.getMessage(), e);
+                        callbackContext.error(e.getClass().getSimpleName() + ": " + e .getMessage()); 
+                    } catch (Exception e) {
+                        Log.e(LOG_TAG, e.getMessage(), e);
+                        callbackContext.error(e.getClass().getSimpleName() + ": " + e .getMessage());
+                    }
+
+                }
+            });
+        }
+
+        return true;
+    }
+
+}

+ 12 - 0
src/ios/CDVImageProcessing.h

@@ -0,0 +1,12 @@
+#import <Foundation/Foundation.h>
+#import <Cordova/CDVPlugin.h>
+
+@interface CDVImageProcessing : CDVPlugin {}
+
+- (void) resize:(CDVInvokedUrlCommand *)command;
+
+- (void) rotate:(CDVInvokedUrlCommand *)command;
+
+- (void) crop:(CDVInvokedUrlCommand *)command;
+
+@end

+ 315 - 0
src/ios/CDVImageProcessing.m

@@ -0,0 +1,315 @@
+#import <Cordova/CDV.h>
+#import "CDVImageProcessing.h"
+
+@implementation CDVImageProcessing
+
+- (void) resize:(CDVInvokedUrlCommand *)command {
+    [self.commandDelegate runInBackground:^{
+        CDVPluginResult* pluginResult = nil;
+
+        NSString *sourceUri = [command argumentAtIndex: 0];
+        NSString *destinationUri = [command argumentAtIndex: 1];
+        NSNumber *width = [command argumentAtIndex: 2];
+        NSNumber *height = [command argumentAtIndex: 3];
+        BOOL keepScale = [[command argumentAtIndex:4 withDefault:[NSNumber numberWithBool:NO]] boolValue];
+        
+        [self resizeImage:sourceUri toDestinationUri:destinationUri withSize:CGSizeMake([width floatValue], [height floatValue]) andKeepScale:keepScale];
+        
+        pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString:@"Image resized"];
+        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+    }];
+}
+
+- (void) rotate:(CDVInvokedUrlCommand *)command {
+    [self.commandDelegate runInBackground:^{
+        CDVPluginResult* pluginResult = nil;
+
+        NSString *sourceUri = [command argumentAtIndex: 0];
+        NSString *destinationUri = [command argumentAtIndex: 1];
+        NSNumber *angle = [command argumentAtIndex: 2];
+
+        [self rotateImage:sourceUri toDestinationUri:destinationUri toAngle:angle];
+
+        pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString:@"Image rotated"];
+        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+    }];
+}
+
+- (void) crop:(CDVInvokedUrlCommand *)command {
+    NSLog(@"CDVImageProcessing - crop");
+}
+
+- (void)resizeImage:(NSString *)sourceUri toDestinationUri:(NSString *)destinationUri withSize:(CGSize)size andKeepScale:(BOOL)keepScale {
+    UIImage *originalImage = [self loadImage:sourceUri];
+
+    CGSize newImageSize = size;
+    CGSize imageSize = originalImage.size;
+    if (keepScale) {
+        newImageSize = [self estimatedScaleSize:newImageSize forImageSize:imageSize];
+    }
+    
+    CGImageRef imageRef = [originalImage CGImage];
+    CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
+    
+    // There's a wierdness with kCGImageAlphaNone and CGBitmapContextCreate
+    // see Supported Pixel Formats in the Quartz 2D Programming Guide
+    // Creating a Bitmap Graphics Context section
+    // only RGB 8 bit images with alpha of kCGImageAlphaNoneSkipFirst, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedFirst,
+    // and kCGImageAlphaPremultipliedLast, with a few other oddball image kinds are supported
+    // The images on input here are likely to be png or jpeg files
+    if (alphaInfo == kCGImageAlphaNone)
+        alphaInfo = kCGImageAlphaNoneSkipLast;
+    
+    // Build a bitmap context that's the size of the thumbRect
+    CGContextRef bitmap = CGBitmapContextCreate(
+                                                NULL,
+                                                newImageSize.width,       // width
+                                                newImageSize.height,      // height
+                                                CGImageGetBitsPerComponent(imageRef),   // really needs to always be 8
+                                                4 * newImageSize.width,   // rowbytes
+                                                CGImageGetColorSpace(imageRef),
+                                                alphaInfo
+                                                );
+    
+    // Draw into the context, this scales the image
+    CGContextDrawImage(bitmap, CGRectMake(0, 0, newImageSize.width, newImageSize.height), imageRef);
+    
+    // Get an image from the context and a UIImage
+    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
+    UIImage* resizedImage = [UIImage imageWithCGImage:ref];
+    
+    CGContextRelease(bitmap);   // ok if NULL
+    CGImageRelease(ref);
+
+    NSError* err = nil;
+    [self saveImage:resizedImage toFilePath:destinationUri error:&err];
+}
+
+- (CGSize)estimatedScaleSize:(CGSize)newSize forImageSize:(CGSize)imageSize {
+    if (imageSize.width > imageSize.height) {
+        newSize = CGSizeMake((imageSize.width / imageSize.height) * newSize.height, newSize.height);
+    } else {
+        newSize = CGSizeMake(newSize.width, (imageSize.height / imageSize.width) * newSize.width);
+    }
+
+    return newSize;
+}
+
+
+
+- (void)rotateImage:(NSString *)sourceUri toDestinationUri:(NSString *)destinationUri toAngle:(NSNumber *)angle {
+    UIImage *originalImage = [self loadImage:sourceUri];
+
+    CGFloat radians = M_PI * [angle intValue] / 180;
+
+    CGSize imageSize = originalImage.size;
+    CGRect imageRect = CGRectMake(0, 0, imageSize.width, imageSize.height);
+    CGRect rotatedRect = CGRectApplyAffineTransform(imageRect, CGAffineTransformMakeRotation(radians));
+
+    CGImageRef cgOriginalImage = [originalImage CGImage];
+}
+
+
+
+
+
+
+
+
+
+- (BOOL)saveImage:(UIImage *)image toFilePath:(NSString *)filePath error:(NSError **)error; {
+    NSURL* imageURL = [NSURL URLWithString:filePath];
+    
+    NSData *imgData;
+    if ([filePath containsString:@".jpg"]) {
+        imgData = UIImageJPEGRepresentation(image, 0.9);
+    } else {
+        imgData = UIImagePNGRepresentation(image);
+    }
+
+    return [imgData writeToURL:imageURL options:NSAtomicWrite error:error];
+}
+
+- (UIImage *)loadImage:(NSString *)filePath {
+    NSURL* imageURL = [NSURL URLWithString:filePath];
+    UIImage* image = [UIImage imageWithData: [NSData dataWithContentsOfURL: imageURL]];
+    if (!image) {
+        return nil;
+    }
+
+    return image;
+}
+
+- (NSString *)documentsPathForFileName:(NSString *)name {
+    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+    NSString *documentsPath = [paths objectAtIndex:0];
+
+    return [documentsPath stringByAppendingPathComponent:name];
+}
+
+@end
+
+
+
+
+/*
+
+
+
+
+
+- (CGSize)getImageSize:(NSString *)filePath {
+    
+    CGSize imageSize;
+    
+    CGImageSourceRef imageSource = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL URLWithString:filePath], NULL);
+    
+    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
+                             [NSNumber numberWithBool:NO], (NSString *)kCGImageSourceShouldCache, nil];
+    
+    CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (CFDictionaryRef)options);
+    if (imageProperties) {
+        NSNumber *width = (NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
+        NSNumber *height = (NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
+        
+        imageSize = CGSizeMake([width floatValue], [height floatValue]);
+        
+        CFRelease(imageProperties);
+    }
+    
+    CFRelease(imageSource);
+    
+    return imageSize;
+}
+
+
+- (void)doResizeImage:(NSString *)sourceUri toDestinationUri:(NSString *)destinationUri withSize:(CGSize)size {
+    
+    UIImage *originalImage = [self loadImage:sourceUri];
+    
+    CGImageRef imageRef = [originalImage CGImage];
+    CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
+
+    // There's a wierdness with kCGImageAlphaNone and CGBitmapContextCreate
+    // see Supported Pixel Formats in the Quartz 2D Programming Guide
+    // Creating a Bitmap Graphics Context section
+    // only RGB 8 bit images with alpha of kCGImageAlphaNoneSkipFirst, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedFirst,
+    // and kCGImageAlphaPremultipliedLast, with a few other oddball image kinds are supported
+    // The images on input here are likely to be png or jpeg files
+    if (alphaInfo == kCGImageAlphaNone)
+        alphaInfo = kCGImageAlphaNoneSkipLast;
+    
+    // Build a bitmap context that's the size of the thumbRect
+    CGContextRef bitmap = CGBitmapContextCreate(
+                                                NULL,
+                                                size.width,       // width
+                                                size.height,      // height
+                                                CGImageGetBitsPerComponent(imageRef),   // really needs to always be 8
+                                                4 * size.width,   // rowbytes
+                                                CGImageGetColorSpace(imageRef),
+                                                alphaInfo
+                                                );
+    
+    // Draw into the context, this scales the image
+    CGContextDrawImage(bitmap, CGRectMake(0, 0, size.width, size.height), imageRef);
+    
+    // Get an image from the context and a UIImage
+    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
+    UIImage* resizedImage = [UIImage imageWithCGImage:ref];
+
+    CGContextRelease(bitmap);   // ok if NULL
+    CGImageRelease(ref);
+    
+    [self saveImage:resizedImage toFilePath:destinationUri];
+}
+
+- (void)upscaleImage:(NSString *)sourceUri toDestinationUri:(NSString *)destinationUri withSize:(CGSize)size {
+    
+    UIImage *originalImage = [self loadImage:sourceUri];
+    CGImageRef cgOriginalImage = originalImage.CGImage;
+    
+    size_t bitsPerComponent = CGImageGetBitsPerComponent(cgOriginalImage);
+    size_t bytesPerRow = CGImageGetBytesPerRow(cgOriginalImage);
+    CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgOriginalImage);
+    CGBitmapInfo info = CGImageGetBitmapInfo(cgOriginalImage);
+    
+    CGContextRef context = CGBitmapContextCreate(nil, size.width, size.height, bitsPerComponent, bytesPerRow, colorSpace, info);
+    
+    CGContextSetInterpolationQuality(context, kCGInterpolationMedium);
+    
+    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), cgOriginalImage);
+    
+    CGImageRef cgResizedImage = CGBitmapContextCreateImage(context);
+    
+    UIImage *resizedImage = [UIImage imageWithCGImage:cgResizedImage];
+    
+    CGContextRelease(context);
+    CGImageRelease(cgOriginalImage);
+    CGImageRelease(cgResizedImage);
+    
+    [self saveImage:resizedImage toFilePath:destinationUri];
+}
+
+- (void)downscaleImage:(NSString *)sourceUri toDestinationUri:(NSString *)destinationUri withSize:(CGSize)size {
+    
+}
+
+- (UIImage *)resizeImage:(UIImage *)originalImage toSize:(CGSize)size andKeepScale:(BOOL)keepScale {
+    CGImageRef cgOriginalImage = originalImage.CGImage;
+
+    NSLog(@"CDVImageProcessing - resizeImage() - image size (%fX%f)", originalImage.size.width, originalImage.size.height);
+    NSLog(@"CDVImageProcessing - resizeImage() - desired size (%fX%f)", size.width, size.height);
+    NSLog(@"CDVImageProcessing - resizeImage() - keepScale: %hhd", keepScale);
+       
+    if (keepScale) {
+        size = [self estimatedScaleSize:size forImage:originalImage];
+        NSLog(@"CDVImageProcessing - resizeImage() - scaled size (%fX%f)", size.width, size.height);
+    }
+
+    size_t bitsPerComponent = CGImageGetBitsPerComponent(cgOriginalImage);
+    size_t bytesPerRow = CGImageGetBytesPerRow(cgOriginalImage);
+    CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgOriginalImage);
+    CGBitmapInfo info = CGImageGetBitmapInfo(cgOriginalImage);
+
+    CGContextRef context = CGBitmapContextCreate(nil, size.width, size.height, bitsPerComponent, bytesPerRow, colorSpace, info);
+    
+    if (!context) {
+        NSLog(@"CDVImageProcessing - resizeImage() - 0.1 - context IS NIL");
+    }
+    
+    NSLog(@"CDVImageProcessing - resizeImage() - 0.1");
+    
+    CGContextSetInterpolationQuality(context, kCGInterpolationMedium);
+    
+    NSLog(@"CDVImageProcessing - resizeImage() - 0.2");
+
+    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), cgOriginalImage);
+    
+    NSLog(@"CDVImageProcessing - resizeImage() - 1");
+    
+    CGImageRef cgResizedImage = CGBitmapContextCreateImage(context);
+    
+    UIImage *resizedImage = [UIImage imageWithCGImage:cgResizedImage];
+    
+    NSLog(@"CDVImageProcessing - resizeImage() - 2");
+    
+    CGContextRelease(context);
+    CGImageRelease(cgOriginalImage);
+    CGImageRelease(cgResizedImage);
+    
+    NSLog(@"CDVImageProcessing - resizeImage() - 3");
+
+    return resizedImage;
+}
+
+- (CGSize)estimatedScaleSize:(CGSize)newSize forImage:(UIImage *)image {
+    if (image.size.width > image.size.height) {
+        newSize = CGSizeMake((int)(image.size.width / image.size.height) * newSize.height, newSize.height);
+    } else {
+        newSize = CGSizeMake(newSize.width, (int)(image.size.height / image.size.width) * newSize.width);
+    }
+
+    return newSize;
+}
+
+*/

+ 50 - 0
www/ImageProcessing.js

@@ -0,0 +1,50 @@
+var exec = require('cordova/exec');
+var argscheck = require('cordova/argscheck');
+
+var imageProcessing = new ImageProcessing();
+
+function ImageProcessing() {
+    console.log("ImageProcessing.js - is created");
+}
+
+imageProcessing.resize = function (successCallback, errorCallback, options) {
+    console.log("ImageProcessing.js - resize: " + JSON.stringify(options));
+
+    options = options || {};
+    var getValue = argscheck.getValue;
+
+    var sourceUri = options.sourceUri;
+    var destinationUri = options.destinationUri;
+    var width = options.newWidth;
+    var height = options.newHeight;
+    var keepScale = getValue(options.keepScale, false);
+
+    var args = [sourceUri, destinationUri, width, height, keepScale];
+
+    exec(successCallback, errorCallback, "ImageProcessing", "resize", args);
+};
+
+imageProcessing.rotate = function (successCallback, errorCallback, options) {
+    console.log("ImageProcessing.js - rotate: " + JSON.stringify(options));
+
+    options = options || {};
+    var getValue = argscheck.getValue;
+
+    var sourceUri = options.sourceUri;
+    var destinationUri = options.destinationUri;
+    var angle = getValue(options.angle, 90);
+
+    var args = [sourceUri, destinationUri, angle];
+
+    exec(successCallback, errorCallback, "ImageProcessing", "rotate", args);
+};
+
+imageProcessing.crop = function (successCallback, errorCallback, sourceUri, destinationUri, rect) {
+    exec(successCallback, errorCallback, "ImageProcessing", "crop", [sourceUri, destinationUri, rect]);
+};
+
+imageProcessing.info = function (successCallback, errorCallback, sourceUri) {
+    exec(successCallback, errorCallback, "ImageProcessing", "info", [sourceUri]);
+};
+
+module.exports = imageProcessing;