54

I am building an image resize/crop, and I'd like to show a live preview after they've edited it in a modal (bootstrap). This should work, I believe, but I just get 0 in console.log. This requires feeding the width and the height of the original image into another script (which I'll do after, just need them in console.log/a variable for now)

function doProfilePictureChangeEdit(e) {
    var files = document.getElementById('fileupload').files[0];
    var reader = new FileReader();
    reader.onload = (function(theFile) {
        document.getElementById('imgresizepreview').src = theFile.target.result;

        document.getElementById('profilepicturepreview').src = theFile.target.result;
      }
    );
    reader.readAsDataURL(files);
    var imagepreview = document.getElementById('imgresizepreview');
    console.log(imagepreview.offsetWidth);
    $('img#imgresizepreview').imgAreaSelect({
        handles: true,
        enable: true,
        aspectRatio: "1:1",
        onSelectEnd: preview
    });
    $('#resizeprofilepicturemodal').modal('show');
    };
rjohnston
  • 7,153
  • 8
  • 30
  • 37
Martin Alderson
  • 892
  • 1
  • 7
  • 14
  • You can use an EXIF library if your images are relatively big (>500 KB). Then you just read the EXIF header that has a tag with width and height. – Pithikos May 15 '20 at 14:46

5 Answers5

122

You have to wait for the image to load. Try handling the element inside .onload.

I've also simplified the process of setting the source of the two elements to how you should be doing it (with jQuery).

reader.onload = (function(theFile) { 
    var image = new Image();
    image.src = theFile.target.result;

    image.onload = function() {
        // access image size here 
        console.log(this.width);

        $('#imgresizepreview, #profilepicturepreview').attr('src', this.src);
    };
});
Austin Brunkhorst
  • 20,704
  • 6
  • 47
  • 61
  • 1
    Great, thanks very much. I was under the misinformed impression that the files would of loaded with the readAsDataURL call. – Martin Alderson Mar 19 '13 at 04:34
  • 5
    `reader.onload` is called when the file system is finished reading the file from the hardrive. `image.onload` is called essentially when essentially the image object has buffered the image data in browser. I see how you could have misinterpreted the onload functions; glad to have help though. – Austin Brunkhorst Mar 19 '13 at 05:45
  • 1
    Note: This works only when you use "reader.readAsDataURL". With "reader.readAsBinaryString" you have to go a different way. – Benny Code Jan 30 '14 at 14:25
  • @BennyNeugebauer which way? Provide some details or link to example. – andilabs Jul 23 '14 at 07:46
  • 1
    You eventually need to get to a data uri from the image contents, so using `.readAsBinaryString()` is pointless. – Austin Brunkhorst Jul 23 '14 at 16:35
  • 1
    @AustinBrunkhorst It isn't pointless if you send the same binary string to server (file uploads). using `readAsBinaryString()` is significantly faster than creating it manually in javascript from data URL. – Robert Koritnik Oct 29 '15 at 11:22
  • This is giving me 250 in console every time. No matter what is size of image. – Sunil Pachlangia Jan 19 '18 at 09:06
  • 1
    @SunilPachlangia: Are you displaying the image somewhere? Then the 250 px is the width of the displayed image. When setting the `src` of a newly created image ( `myPreviewImage = new Image()` ), then you get the correct dimensions. – uruk Nov 16 '18 at 07:47
  • I am using readAsArrayBuffer. How can I get the image width in such case? I'm now getting the following error: `[object%20ArrayBuffer]:1 GET http://localhost/[object%20ArrayBuffer] 404 (Not Found)` – Avner Moshkovitz Feb 22 '19 at 07:15
34

For me the solution of Austin didn't work, so I present the one worked for me:

var reader = new FileReader;

reader.onload = function() {
    var image = new Image();

    image.src = reader.result;

    image.onload = function() {
        alert(image.width);
    };

};

reader.readAsDataURL(this.files[0]);

And if you find that assignment image.src = reader.result; takes place after image.onload a bit wired, I think so too.

andilabs
  • 22,159
  • 14
  • 114
  • 151
  • 1
    It is not wired that image loading is asynchronous. All data in src must be decoded, if the src is a link it must be loaded and decoded to image, if base64 also. So it's quite natural :-) – BrightShadow May 19 '16 at 08:26
4

fileChangeEventHeader(fileInput) {
    const oFReader = new FileReader();
    oFReader.readAsDataURL(fileInput.target.files[0]);
    oFReader.onload = (event: any) => {
      var image = new Image();
      image.src = event.target.result;
      image.onload = function () {
        console.log(`width : ${image.width} px`, `height: ${image.height} px`);
      };
    };
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>

<input type="file" name="profile_img" accept="image/*" (change)="fileChangeEventHeader($event)"
                  class="input-file">
1

Here's an answer inspired by Austin Brunkhorst with a callback for ascertaining image size in case you want to reuse the function elsewhere in your code.

fileControl is assumed to be a jQuery element.

function didUploadImage(fileControl) {      
   // Render image if file exists.
   var domFileControl = fileControl[0];
   if (domFileControl.files && domFileControl.files[0]) {
      // Get first file.
      var firstFile = domFileControl.files[0];

      // Create reader.
      var reader = new FileReader();

      // Notify parent when image read.
      reader.onload = function(e) {
         // Get image URL.
         var imageURL = reader.result;

        // Get image size for image.
        getImageSize(imageURL, function(imageWidth, imageHeight) {
            // Do stuff here.
        });
      };

      // Read image from hard disk.
      reader.readAsDataURL(firstFile);

      // Print status.
      console.log("Uploaded image: " + firstFile.name);
   }
}


function getImageSize(imageURL, callback) {      
   // Create image object to ascertain dimensions.
   var image = new Image();

   // Get image data when loaded.
   image.onload = function() {      
      // No callback? Show error.
      if (!callback) {
         console.log("Error getting image size: no callback. Image URL: " + imageURL);

      // Yes, invoke callback with image size.
      } else {
         callback(this.naturalWidth, this.naturalHeight);
      }
   }

   // Load image.
   image.src = imageURL;
}
Crashalot
  • 33,605
  • 61
  • 269
  • 439
0

this is the way I have for AngularJS

          fileReader.readAsDataUrl($scope.file, $scope).then(function(result) {
               var image = new Image();
               image.src = result;
               image.onload = function() {
                    console.log(this.width);
               };
               $scope.imageSrc = result; //all I wanted was to find the width and height


          });
Brian Sanchez
  • 832
  • 1
  • 13
  • 11