48

I want to fetch images from s3 and display them on my HTML page.

Angular HTML file:

<section data-ng-controller="myCtrl">
    <img ng-src="{{src}}" width="200px" height="200px">
</section>

Angular Controller file:

angular.module('users').controller('myCtrl', ['$scope',function($scope) {
    var s3 = new AWS.S3(); 
    s3.getObject({Bucket: 'mybucket', Key: 'myimage.jpg'},function(err,file){

    //code?? to display this image file in the img tag
    //$scope.src=file????....obviously it wont work

    });
}]);

I found something call FileReader and tried this one:

var reader = new FileReader();
reader.onload = function(event) {
    $scope.src = event.target.result;
}
reader.readAsDataURL(file);

But it shows error:
Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.

Please help me with the code to display image file in the img tag
My S3 bucket is not public

EDIT:
I am not interested in s3. what i want to know is that
how to display an image which you have in your javascript code in the form of a file object(s3 obj) using the HTML image tag

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Gaurav Gupta
  • 1,929
  • 4
  • 21
  • 40
  • May I ask why your bucket cannot have public read access? If you do not do that you need to access the bucket via a key, and if you put a key into your code then your bucket is basically very public. – enpenax Oct 10 '15 at 03:38
  • 1
    @enpenax actually my question is how to display a image that you have in your javascript code in the form of file object using html image tag – Gaurav Gupta Oct 10 '15 at 06:24
  • is it working now? i have some issue – Adarsh M Pallickal Feb 22 '17 at 09:37

4 Answers4

67

You don't "fetch" the images to display. You just point the image URL to the location where they are stored (S3 in your case). So instead of pulling individual object, pull the list of files in that bucket (bucket.listObjects) and then add them to the source of the thumbnails/images.

<section data-ng-controller="myCtrl">
    <img ng-src="{{s3Url}}{{image.Key}}" width="200px" height="200px" ng-repeat="image in allImageData">
</section>
$scope.s3Url = 'https://s3-<region>.amazonaws.com/myBucket/';
var bucket = new AWS.S3({params: {Bucket: 'myBucket'}});
  bucket.listObjects(function (err, data) {
    if (err) {
      console.log(err);
    } else {
      console.log(data);
      $scope.allImageData = data.Contents;
    }
  });

Assuming here that the files have read permission. They won't be accessible without public read permission for obvious reasons.

EDIT: Based on the comment, the question is seeking to load the actual image on the page. Here's how to do it:

function myCtrl($scope, $timeout) {    
    AWS.config.update({
        accessKeyId: 'YOUR_ACCESS_TOKEN', 
        secretAccessKey: 'YOUR_SECRET'
    });
    AWS.config.region = "YOUR_REGION";
    
    var bucket = new AWS.S3({params: {Bucket: 'YOUR_BUCKET'}});
    
    bucket.getObject({Key: 'happy-face.jpg'}, function(err,file){
        $timeout(function(){
            $scope.s3url = "data:image/jpeg;base64," + encode(file.Body);
        }, 1);
    });
}

function encode(data) {
    var str = data.reduce(function(a,b){ return a+String.fromCharCode(b) },'');
    return btoa(str).replace(/.{76}(?=.)/g,'$&\n');
}

The data you get from the S3 is a byte array. You need to convert it into the base64encoded data URI. The encode function is borrowed from here. Here's one working jsFiddle with credentials removed.

PapEr
  • 815
  • 5
  • 16
show-me-the-code
  • 1,553
  • 1
  • 12
  • 14
  • actually my question is how to display a image that you have in your javascript code in the form of file object using the img tag – Gaurav Gupta Oct 10 '15 at 06:25
  • I have updated the answer to meet your requirements. – show-me-the-code Oct 10 '15 at 17:15
  • did you face any insufficient resources issue in chrome? I am pre-loading a bunch of images and I don't see that working. – Tisha Nov 07 '16 at 07:14
  • This works great! The timeout is important to trigger a digest. – Ladmerc Apr 02 '17 at 10:02
  • 1
    >They won't be accessible without public read permission for obvious reasons. Right, but you could have access to it via cognito or some other credential. In that case just using the URL won't work unless you use a presigned URL of some sort – Georgii Oleinikov Apr 25 '18 at 12:26
  • Hi @show-me-the-code ......can you please help to do the above code in angular 6 if possible...thanx.... – Ricky Jan 02 '19 at 07:04
7

Full implementation of getting an image from s3 with promise - enjoy!

<!DOCTYPE html>
<html lang="en">
<head>
  <script src="https://sdk.amazonaws.com/js/aws-sdk-2.179.0.min.js"></script>
</head>
<body>
  <img height="200" width="200">
  <script>

    var mimes = {
        'jpeg': 'data:image/jpeg;base64,'
    };

      AWS.config.update({
          signatureVersion: 'v4',
          region: 'us-east-1',
          accessKeyId: '',
          secretAccessKey: ''
      });

      var bucket = new AWS.S3({params: {Bucket: 'xxx'}});

      function encode(data)
      {
          var str = data.reduce(function(a,b){ return a+String.fromCharCode(b) },'');
          return btoa(str).replace(/.{76}(?=.)/g,'$&\n');
      }

      function getUrlByFileName(fileName,mimeType) {
          return new Promise(
              function (resolve, reject) {
                  bucket.getObject({Key: fileName}, function (err, file) {
                      var result =  mimeType + encode(file.Body);
                      resolve(result)
                  });
              }
          );
      }

      function openInNewTab(url) {
          var redirectWindow = window.open(url, '_blank');
          redirectWindow.location;
      }

      getUrlByFileName('sprites.png', mimes.jpeg).then(function(data) {
          //openInNewTab(data);
          document.querySelector('img').src = data;
      });

  </script>
</body>
</html>
Liad Livnat
  • 7,435
  • 16
  • 60
  • 98
  • Hi @Liad Livnat ......can you please help to do the above code in angular 6 if possible...thanx.... – Ricky Jan 02 '19 at 07:05
  • if i supply secret key and access key. is it safe? I assume it should be but just confirming if anyone could track these keys from browser in any way. – dksahuji Oct 11 '21 at 02:46
  • AWS does not advise to store them in the JS, but read from JSON or environment variables, as explained here https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html – David Bensoussan Mar 05 '22 at 14:18
1

If your S3 file is public (you have to change it, by default it isn't public) you can get the url from this schema:

https://s3-<region>.amazonaws.com/<bucket-name>/<key>

So if the region is eu-west-1 with something like this:

$scope.src = 'https://s3-eu-west-1.amazonaws.com/mybucket/myimage.jpg';
michelem
  • 14,430
  • 5
  • 50
  • 66
  • 2
    my bucket can't be public...any idea then? – Gaurav Gupta Sep 21 '15 at 19:12
  • So you should use the JavaScript SDK for browsers http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-intro.html – michelem Sep 21 '15 at 19:18
  • @GauravGupta if your bucket is not public, but you place the key in the javascript to download the image, then you are actually making it public... That is much worse than making it public, because other people of your team thought it was secure and put sensitive data in it. – Ben L Jan 31 '23 at 23:40
-6

You only have to mention the url of the image that is stored in the s3.

https://mybucket.s3.amazonaws.com/myimage.jpg

This should work.

Siddhu
  • 389
  • 1
  • 4
  • 8