Populate ng-flow with jpeg/jpg as blob

1.8k Views Asked by At

I'm currently trying to populate ng-flow with images from my webserver(nodejs http-server), and I found this thread:

Populating image files with ng-flow.js from json

As you can see in the answer from Aidas, he says that you need to add the data to a blob and then use addFile(blob)

But... when I use $resource to GET an url like:

http://localhost:8080/3c6397ff-cbb4-4a1c-98b3-5304e02c1bd4.jpg

and then take the value from $resource, and adding it to a blob the image is missing - In ng-flow it says that the blob is 15kb - and not the 700kb the actually image is.

I've read that the picture could be base64 formatted, but my google dev console says:

content-length:780831
content-type:image/jpeg; charset=utf-8

If I take a look at the response data in google dev console, there's alot of questionmarks (it cannot display the character I guess).

How do I get the response formatted correctly, so I can add it to ng-flow using the addFile(blob) function?

3

There are 3 best solutions below

0
On BEST ANSWER

I ended up doing like this..

My $resource function look like:

ENV.imagesEndpoint = 'http://localhost:8080/

id = the image name / ID

getimages: $resource(ENV.imagesEndpoint + id, {}, {
    get: { 
      method: 'GET',  
      isArray: false,
      responseType: 'arraybuffer',
      transformResponse: function(data) {
        // Stores the ArrayBuffer object in a property called "data"
        return { data: data };
      }
      //headers: {'Content-Type': 'image/jpeg;charset=utf-8;base64'}
    }
  })

My controller look like:

angular.forEach($scope.images, function(imageid) {
        filefactory(imageid).getimages.get().$promise.then(function(value) {
          $timeout(function() {
              var blob = new Blob([value.data], {type: 'image/jpeg'});
              blob.name = 'file.jpg';
              $scope.obj.flow.addFile(blob);
          });
        });
      });
0
On

The solution I'll provide here is based on the post here:

Creating a Blob from a base64 string in JavaScript

I faced similar case, but the images are stored on the server using Base64.When the web page is loaded, and the images are retrieved from the Database, such images must be added back to the flow.files array. The images are saved in Database using Base64 string. So, during page load, the only way for me was to convert Base64 string to Blob and add the files back to the flow.files array.

This enabled the flow controller to function correctly after the page is loaded from the Database.

Following are the steps:

  1. Add directive load-photo and add it to the input element additional_image1 which has the Base64 string loaded from Database on document ready event using jQuery.

  2. Add a Directive to access the element and call scope function $scope.loadPhoto on document ready to load the photo.

  3. In load photo function, convert the Base64 to Blob and add the file to the flow control.

  4. Ensure the scope variable $scope.imageStringB64 and the input element additional_image1 are synchronized manually as ng-model didn't work as expected. This is because jQuery code outside angular is loading the input element from Database, and I found out that they are not bound dynamically.

JavaScript code:

app.directive('loadPhoto', function () {
    return function (scope, element, attrs) {
        //This directive 'load-photo' is required to access the DOM element inside the scope
        //This will get the Base64 string of the image which is stored in the input element
        angular.element(document).ready(function () {
            scope.loadPhoto(element[0]);
        })
    }
})

app.controller('photosController', ['$scope', '$http', '$timeout',
    function ($scope, $http, $timeout) {
        ...
        var BLANK_IMG_URL = "//:0";
        $scope.removeFile = function () {
            //debugger;
            $scope.$flow.cancel();
            $scope.imageStringB64 = '';
            $scope.imageString = BLANK_IMG_URL;
        }
        $scope.loadPhoto = function (elem) {
            //Load photo from Database
            //The photo Base64 is stored in the input element 'elem'
            var blobImage;
            var tmpBase64;
            tmpBase64 = angular.element(elem).val(); 
            if (tmpBase64) {
                //Convert Base64 to Blob object
                blobImage = b64toBlob(tmpBase64, 'image/png');
                blobImage.name = "image.png";
                //Add the Blob object to flow files.
                $scope.$flow.addFile(blobImage);
            }
        }
        ...
}]);

HTML Code:

                    <div class="photo-wrapper"  ng-controller="photosController" 
                        flow-init
                        flow-file-added="!isAppraiserSigned() && !!{png:1,gif:1,jpg:1,jpeg:1}[$file.getExtension()]"
                        flow-files-submitted="$flow.upload()">
                        <h4 class='photo-title'>Photo 1</h4>
                        <div class="property-photo drag-drop-photo" ng-hide="$flow.files.length" flow-drop
                            flow-drag-enter="isAppraiserSigned()?style={}:style={border:'4px solid green'}" flow-drag-leave="style={}" ng-style="style">
                            <div class='drag-drop-lbl'>Drop file here</div>
                        </div>
                        <div class="property-photo" flow-drop ng-show="$flow.files.length" 
                            flow-drag-enter="isAppraiserSigned()?style={}:style={border:'4px solid green'}" flow-drag-leave="style={}" ng-style="style">
                            <img id="additional_image1_section" style="max-height:100%" flow-img="$flow.files[0]" />
                            <input id="additional_image1" name = "additional_image1" ng-hide="true" type="text" ng-model="imageStringB64" load-photo/>                      
                        </div>
                        <div>
                            <a href="#" class="btn" ng-hide="$flow.files.length" flow-btn flow-attrs="{accept:'image/*'}"><%=selectImageLbl%></a>
                            <a href="#" class="btn" ng-show="$flow.files.length" flow-btn flow-attrs="{accept:'image/*'}">Change</a>
                            <a href="#" class="btn btn-danger" ng-show="$flow.files.length"
                               ng-click="removeFile()">
                              Remove
                            </a>
                        </div>
                        <div class='photo-description'>
                            <label class='description-lbl' for='additional_image_describe1'><%=descriptionLbl%></label>
                            <input class='description' id='additional_image_describe1' name='additional_image_describe1' type="text" />
                        </div>
                    </div>

See this code sample for more options to convert Base64 image to blob and back to Base64:

fiddle.jshell.ne

0
On

I did something combining cvjensen solution and penner's one in Populating image files with ng-flow.js from json

Controller:

First I read images from db and store them in $scope.project.images:

$scope.project.images : [ 
        {
            "image_type" : "image/jpeg",
            "src" : "/images/uploaded/flow-122256-fontiosojpg.1",
            "alt" : "fontioso.jpg",
            "_id" : ObjectId("5608ef37f7672d8b1fcab111")
        }
    ]

Then:

Flow.prototype.addExistingFile = function (file, event) {
  var f = new Flow.FlowFile(this, file);
  this.files.push(f);
};

angular.forEach($scope.project.images, function(value, key) {
    getBase64Images.get(value.src) //src contains the full path to img
        .success(function(data) {
             var blob = new Blob([data.data], {type: value.image_type});
              blob.name = value.alt;
              blob.image_url = value.src;
              blob.alt_text = value.alt;
              $scope.uploader.flow.addExistingFile(blob);
        })
        .error(function(error){
            console.log(error);
    });

});

Service:

.factory("getBase64Images", ['$http', function ($http) {
    return {
        get: function (url) {
            return $http.get(
                url, { 
                responseType: 'arraybuffer',
                transformResponse: function(data) {
                  console.log(data);
                  return { data: data };
                }
            }
          );
        }
    };
  }]);