kovpack
kovpack

Reputation: 5045

How to get file size of newly created Image() if src is base64 string?

How can I get the size of the newly created new Image() in bytes if this image's src is base64 data image?

I have such coffeescript code:

# This string is received after some original image preprocessing
base64String = "data:image/jpeg;base64......"

newImageObj = new Image()
newImageObj.src = base64String
newImageObj.onload = ->
  console.log "Resized image width is " + this.width
  console.log "New file size in bytes is " + newImageObj.fileSize

The output is always like this:

Resized image width is 500
New file size in bytes is undefined

This newImageObj.fileSize is always undefined.

Upvotes: 13

Views: 44866

Answers (6)

M Barzel
M Barzel

Reputation: 817

Here is the algorithm to find file size from base64 string:

base64String = "data:image/jpeg;base64......";

var stringLength = base64String.length - 'data:image/png;base64,'.length;

var sizeInBytes = 4 * Math.ceil((stringLength / 3))*0.5624896334383812;
var sizeInKb=sizeInBytes/1000;

 

Upvotes: 35

Ajay Pandey
Ajay Pandey

Reputation: 21

You can refer to this example and see how base64 decoding works:


I have also attached the reference to base64 table. Base64 index table

Decoding->base64 string : QWJoaXNoZWs=


  1. First, you need to split the string character by character. Thus, you got 12 groups: Q W J o a X N o Z W s =

  2. Each group (character) is a Base64 character that has its own index, and now your task is to convert groups to indices. To do this, by mapping values from the Base64 Characters Table replace each character by its index (if you cannot find an index for a specific group, just discard it). All in all, you should get the following indices: 16 22 9 40 26 23 13 40 25 22 44

  3. At this step you should convert each group from decimal to binary. So find corresponding decimal values in the ASCII table and make sure you get the following binary values: 00010000 00010110 00001001 00101000 00011010 00010111 00001101 00101000 00011001 00010110 00101100

  4. Now remove the prefix “00” (two zeros) in front of each group: 010000 010110 001001 101000 011010 010111 001101 101000 011001 010110 101100

  5. There you have a simple concatenation of previous groups (that is, glue all the binary values together and get an 66-character string): 010000010110001001101000011010010111001101101000011001010110101100

  6. Then, divide the resulting string into groups so that each one has 8 characters (if the last group has less than 8 characters, you must discard it). Now you have 8 groups of eight-bit bytes: 01000001 01100010 01101000 01101001 01110011 01101000 01100101 01101011

  7. Once again using the ASCII table, convert all binary values into their ASCII characters: A b h i s h e k

  8. The final chord, concatenate all ASCII characters to get the result string: Abhishek

Thus,

Size of original string(in bytes) = floor(6n/8) – padding


Size of base64 string(in bytes) = ceil(8n/6) + padding


When decoding from base64

int paddingCount = (base64Data.endsWith("==")) ? 2 :(base64Data.endsWith("=")) ? 1 : 0;

double dataSize = floor(base64Data.length() * 3 / 4) - paddingCount;

When encoding to base64

int paddingCount = 3 - (stringToEncode.length()) % 3;

double dataSize = ceil(stringToEncode.length() * 4 / 3) + paddingCount;

Upvotes: 2

Rahul
Rahul

Reputation: 1642

const img = 'data:image/png;base64,aBdiVBORw0fKGgoAAA';

const buffer = Buffer.from(img.substring(img.indexOf(',') + 1));

console.log("Byte length: " + buffer.length);
console.log("MB: " + buffer.length / 1e+6);

Upvotes: -2

Nino Filiu
Nino Filiu

Reputation: 18551

You can take advantage of the inner workings of fetch for that:

const url = 'data:image/jpeg;base64...'
const resp = await fetch(url)
const size = +resp.headers.get('Content-Length')

Upvotes: -1

Todd Davis
Todd Davis

Reputation: 6035

I'm a little late to the question here, and maybe I'm wrong but...

Looking at your code above, it looks like you are defining a function and using arrow notation to return the answer. However, there are TWO lines following the arrow, and they aren't grouped in any way, so... the arrow notation is returning the value of onload() to the first log() only. So "this" actually has a value. But the second log() is a new command altogether, right? It's not being returned from onload(). So newImageObj is undefined.

Or maybe it's a coffeescript syntax, I'm not familiar with it. Would this fix it?

newImageObj = new Image()
newImageObj.src = base64String
newImageObj.onload = ->
{
  console.log "Resized image width is " + this.width
  console.log "New file size in bytes is " + newImageObj.fileSize
}

Upvotes: 0

JD Byrnes
JD Byrnes

Reputation: 831

I'd personally use something like this to do the above, which will work correctly in the case that the data isn't formatted correctly (eg, an '=' missing, which usually gets decoded correctly anyway)

new Buffer(base64String, 'base64').length

Upvotes: 7

Related Questions