1

I am trying to import a very simple JS library to Angular 2. This is what the library looks like:

JIC.js

var jic = {
        /**
         * Receives an Image Object (can be JPG OR PNG) and returns a new Image Object compressed
         * @param {Image} source_img_obj The source Image Object
         * @param {Integer} quality The output quality of Image Object
         * @param {String} output format. Possible values are jpg and png
         * @return {Image} result_image_obj The compressed Image Object
         */

        compress: function(source_img_obj, quality, output_format){

             var mime_type = "image/jpeg";
             if(typeof output_format !== "undefined" && output_format=="png"){
                mime_type = "image/png";
             }


             var cvs = document.createElement('canvas');
             cvs.width = source_img_obj.naturalWidth;
             cvs.height = source_img_obj.naturalHeight;
             var ctx = cvs.getContext("2d").drawImage(source_img_obj, 0, 0);
             var newImageData = cvs.toDataURL(mime_type, quality/100);
             var result_image_obj = new Image();
             result_image_obj.src = newImageData;
             return result_image_obj;
        },

        /**
         * Receives an Image Object and upload it to the server via ajax
         * @param {Image} compressed_img_obj The Compressed Image Object
         * @param {String} The server side url to send the POST request
         * @param {String} file_input_name The name of the input that the server will receive with the file
         * @param {String} filename The name of the file that will be sent to the server
         * @param {function} successCallback The callback to trigger when the upload is succesful.
         * @param {function} (OPTIONAL) errorCallback The callback to trigger when the upload failed.
         * @param {function} (OPTIONAL) duringCallback The callback called to be notified about the image's upload progress.
         * @param {Object} (OPTIONAL) customHeaders An object representing key-value  properties to inject to the request header.
         */

        upload: function(compressed_img_obj, upload_url, file_input_name, filename, successCallback, errorCallback, duringCallback, customHeaders){

            //ADD sendAsBinary compatibilty to older browsers
            if (XMLHttpRequest.prototype.sendAsBinary === undefined) {
                XMLHttpRequest.prototype.sendAsBinary = function(string) {
                    var bytes = Array.prototype.map.call(string, function(c) {
                        return c.charCodeAt(0) & 0xff;
                    });
                    this.send(new Uint8Array(bytes).buffer);
                };
            }

            var type = "image/jpeg";
            if(filename.substr(-4).toLowerCase()==".png"){
                type = "image/png";
            }

            var data = compressed_img_obj.src;
            data = data.replace('data:' + type + ';base64,', '');

            var xhr = new XMLHttpRequest();
            xhr.open('POST', upload_url, true);
            var boundary = 'someboundary';

            xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);

        // Set custom request headers if customHeaders parameter is provided
        if (customHeaders && typeof customHeaders === "object") {
            for (var headerKey in customHeaders){
                xhr.setRequestHeader(headerKey, customHeaders[headerKey]);
            }
        }

        // If a duringCallback function is set as a parameter, call that to notify about the upload progress
        if (duringCallback && duringCallback instanceof Function) {
            xhr.upload.onprogress = function (evt) {
                if (evt.lengthComputable) {  
                    duringCallback ((evt.loaded / evt.total)*100);  
                }
            };
        }

            xhr.sendAsBinary(['--' + boundary, 'Content-Disposition: form-data; name="' + file_input_name + '"; filename="' + filename + '"', 'Content-Type: ' + type, '', atob(data), '--' + boundary + '--'].join('\r\n'));

            xhr.onreadystatechange = function() {
            if (this.readyState == 4){
                if (this.status == 200) {
                    successCallback(this.responseText);
                }else if (this.status >= 400) {
                    if (errorCallback &&  errorCallback instanceof Function) {
                        errorCallback(this.responseText);
                    }
                }
            }
            };


        }
};

So far I have tried this:

npm install j-i-c --save

In the typescript file I want to use it:

import * as jic from 'j-i-c';

In my app.component.ts:

declare var jic: any;.

When I run it and try to log the global variable jic it is just an empty object {}. I'm assuming this is because I need a typings definition, and I need help with that - but I'm also wondering if JIC.js needs to be rewritten in anyway. I tried exporting the two functions compress and upload and getting rid of the jic object declaration like this:

        export function compress(source_img_obj, quality, output_format){

             var mime_type = "image/jpeg";
             if(typeof output_format !== "undefined" && output_format=="png"){
                mime_type = "image/png";
             }


             var cvs = document.createElement('canvas');
             cvs.width = source_img_obj.naturalWidth;
             cvs.height = source_img_obj.naturalHeight;
             var ctx = cvs.getContext("2d").drawImage(source_img_obj, 0, 0);
             var newImageData = cvs.toDataURL(mime_type, quality/100);
             var result_image_obj = new Image();
             result_image_obj.src = newImageData;
             return result_image_obj;
        };

        /**
         * Receives an Image Object and upload it to the server via ajax
         * @param {Image} compressed_img_obj The Compressed Image Object
         * @param {String} The server side url to send the POST request
         * @param {String} file_input_name The name of the input that the server will receive with the file
         * @param {String} filename The name of the file that will be sent to the server
         * @param {function} successCallback The callback to trigger when the upload is succesful.
         * @param {function} (OPTIONAL) errorCallback The callback to trigger when the upload failed.
         * @param {function} (OPTIONAL) duringCallback The callback called to be notified about the image's upload progress.
         * @param {Object} (OPTIONAL) customHeaders An object representing key-value  properties to inject to the request header.
         */

        export function upload(compressed_img_obj, upload_url, file_input_name, filename, successCallback, errorCallback, duringCallback, customHeaders){

            //ADD sendAsBinary compatibilty to older browsers
            if (XMLHttpRequest.prototype.sendAsBinary === undefined) {
                XMLHttpRequest.prototype.sendAsBinary = function(string) {
                    var bytes = Array.prototype.map.call(string, function(c) {
                        return c.charCodeAt(0) & 0xff;
                    });
                    this.send(new Uint8Array(bytes).buffer);
                };
            }

            var type = "image/jpeg";
            if(filename.substr(-4).toLowerCase()==".png"){
                type = "image/png";
            }

            var data = compressed_img_obj.src;
            data = data.replace('data:' + type + ';base64,', '');

            var xhr = new XMLHttpRequest();
            xhr.open('POST', upload_url, true);
            var boundary = 'someboundary';

            xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);

        // Set custom request headers if customHeaders parameter is provided
        if (customHeaders && typeof customHeaders === "object") {
            for (var headerKey in customHeaders){
                xhr.setRequestHeader(headerKey, customHeaders[headerKey]);
            }
        }

        // If a duringCallback function is set as a parameter, call that to notify about the upload progress
        if (duringCallback && duringCallback instanceof Function) {
            xhr.upload.onprogress = function (evt) {
                if (evt.lengthComputable) {  
                    duringCallback ((evt.loaded / evt.total)*100);  
                }
            };
        }

        xhr.sendAsBinary(['--' + boundary, 'Content-Disposition: form-data; name="' + file_input_name + '"; filename="' + filename + '"', 'Content-Type: ' + type, '', atob(data), '--' + boundary + '--'].join('\r\n'));

        xhr.onreadystatechange = function() {
            if (this.readyState == 4){
                if (this.status == 200) {
                    successCallback(this.responseText);
                }else if (this.status >= 400) {
                    if (errorCallback &&  errorCallback instanceof Function) {
                        errorCallback(this.responseText);
                    }
                }
            }
        };

So, why is the object that gets logged to console empty? How do I correctly import this library? Also, I am trying to do this because I can't find a usable angular2/ionic image compression package. I found ng2-img-tools - but there was a problem - the image file was without a type attribute (it was null instead of image/jpeg and that made it impossible to compress.

7
  • This might Help. There is a question solely dedicated on how to import third party JS properly . Commented Jul 22, 2017 at 20:15
  • thanks but the example with typings just tells you how to install a typings package with npm...i need to create my own typings file Commented Jul 22, 2017 at 20:24
  • you can go ahead with the the one without typings , to define typings its quite tedious and you need to know the whole library properly @ewizard Commented Jul 22, 2017 at 20:44
  • I am using ionic 3 (built on angular 2) and i don't think there is a place for scripts like that "scripts": [ "../node_modules/jssha/src/sha.js" ]...i dont see an angular-cli.json Commented Jul 22, 2017 at 20:55
  • i would suggest you to skip the step where it adds to the scripts array in .json file and just declare a var in component and use the function. this might work Commented Jul 22, 2017 at 20:59

1 Answer 1

1

According to this issue in github
https://github.com/brunobar79/J-I-C/issues/47
You can't import it as is.

You have to make a very simple modification in the minified version to be enable to 'require' it as a module:

In j-i-c/dist/JIC.min.js,
you can change
var jic =
by
module.exports =

After in you import in the component file, you can write

import * as jicLib from 'j-i-c/dist/JIC.min'; declare const jib:any = jicLib;';

and use jib.compress() whenever you want to

Sign up to request clarification or add additional context in comments.

2 Comments

thanks i ended up using an ionic-native camera option to compress the image. if i ever need this ill give it a shot
very interesting, I have the exact same issue.. Only problem when you use the camera compression you can't be sure of the final size because that depends of the resolution of the camera. Currently I'm trying to make a custom compress fonction and looping until I have the good size... I will post it here after maybe

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.