Get the right dimensions for social preview image!

I have been writing a large amount of blog posts lately and found there's one real crazy problem that takes some good amount of time and effort from me. Whenever I share my posts, you see this small preview that comes up for the links, it's called as a Link Preview and mostly it's given by Open Graph Image, a part of the Open Graph protocol, which enables any web page to become a rich object in a social graph.

The Open Graph protocol enables any web page to become a rich object in a social graph. For instance, this is used on Facebook to allow any web page to have the same functionality as any other object on Facebook.

Also, there were some major changes in the Social Networking apps too. Facebook disabled the option to edit link previews. Everyone was pretty keen on this feature and tried to work around it. However, Facebook also prevented those "workarounds" and luckily added a feature of their own, on how to do it. Apart from all these "workarounds", wouldn't it be always better to do it on our own? Now read on. This is what I do.

Contents

  1. Adding the Meta Data
    1. Basic Metadata
  2. Preview Image
  3. Versions
    1. Version 1
    2. Version 2
    3. Version 3
  4. Final Ultimate Version

Adding the Meta Data

Basically, when I create a page or a blog post, I add the following Meta Data to the content. This is for most of the search engines, social link preview agents for Twitter, Facebook, LinkedIn, etc. to get an idea of what it should be showing as a preview when my link is shared anywhere.

Basic Metadata

Directly taken from The Open Graph Protocol Docs.

To turn your web pages into graph objects, you need to add basic metadata to your page. We've based the initial version of the protocol on RDFa which means that you'll place additional <meta> tags in the <head> of your web page. The four required properties for every page are:

  • og:title - The title of your object as it should appear within the graph, e.g., "The Rock".
  • og:type - The type of your object, e.g., "video.movie". Depending on the type you specify, other properties may also be required.
  • og:image - An image URL which should represent your object within the graph.
  • og:url - The canonical URL of your object that will be used as its permanent ID in the graph, e.g., "http://www.imdb.com/title/tt0117500/".

If you have a look at my website, it has the following meta data:

<meta property="og:type" content="website" />  
<meta property="og:title" content="Praveen Kumar Purushothaman" />  
<meta property="og:description" content="Personal website of Praveen Kumar Purushothaman, a Cook, Cat Lover, Front End Architect, Web Developer Evangelist &amp; Cloud Computing Consultant." />  
<meta property="og:url" content="https://praveen.science/" />  
<meta property="og:image" content="https://i.imgur.com/IjdZYJVm.jpg?https://i.imgur.com/IxOfzYhl.png?" />  
<meta property="profile:first_name" content="Praveen Kumar" />  
<meta property="profile:last_name" content="Purushothaman" />  
<meta property="article:author" content="https://www.facebook.com/praveenscience" />  
<meta property="fb:app_id" content="My-FB-AppID" />  

The above meta data contains the og:image meta data, that helps to define how the site will be appearing in popular social shares. Some examples include WhatsApp, Facebook, Twitter, LinkedIn, Skype, Microsoft Outlook, etc. and all these can be checked out using Rich Link Preview.

Chat Apps

Social Networks

The technique is very similar to the original three Meta Tags namely the <title>, <meta name="description" /> and <meta name="keywords" />, but this is a better modern approach to provide more useful information to the crawlers and agents.

Preview Image

Whenever we think of Social Networks, the only thing that comes to our mind is the giant Facebook. Facebook gives you a set of guidelines about the preview picture.

The URL of the image for your object. It should be at least 600×315 pixels, but 1200×630 or larger is preferred (up to 5MB). Stay close to a 1.91:1 aspect ratio to avoid cropping. Game icons should be square and at least 600×600 pixels. You can include multiple og:image tags if you have multiple resolutions available. If you update the image after publishing, use a new URL because images are cached based on the URL and might not update otherwise.

That's where the issue started. When I try getting my hands on pictures online or getting the logos or banners, I get to see a variety of image sizes ranging from 640×480, 1024×768, etc. but to get it to the right dimensions, it would be a tough task of a person like me, who's not that good with Maths to get to the conclusion of the right dimensions.

So what I did? I created a small and simple application that helps me with the problem. Not only it solves the dimension issue, but also suggests me of additional dimensions that I may consider using for the pictures. I had created about four basic versions before getting to the final ultimate one.

Versions

Version 1

This started with a simple JavaScript function that takes in either of the values and calculates the corresponding missing dimension.

function prop (dim) {  
  if (!!dim.x) {
    var y = 630 / 1200 * dim.x;
    console.log(dim.x.toFixed(2) + " × " + y.toFixed(2));
  }
  if (!!dim.y) {
    var x = 1200 / 630 * dim.y;
    console.log(x.toFixed(2) + " × " + dim.y.toFixed(2));
  }
}

For now, it just checks if a particular dimension is present, it just logs it to the console, the right dimension. You can find the working example here and I have also mimicked the console for your reference.

See the Pen Share Dimensions 1 by Praveen Kumar (@praveenscience) on CodePen.

Version 2

Well, I didn't want to have too many decimals in this. I planned to round off a few things. At first, I want to round to the nearest 10s and then 100s. I made a small snippet for the same. And here it goes.

function getRound(n, p) {  
  if (!p)
    p = 1;
  var t = Math.pow(10, p);
  if (n % t === 0)
    return n;
  else
    return parseInt(n / t) * t;
}

The above one is extremely backward compatible and helpful in terms of getting the stuff done for me. Check it out in action.

See the Pen Share Dimensions 2 by Praveen Kumar (@praveenscience) on CodePen.

So the above cannot be considered as a version but it's a reusable snippet I created for this. With the above code, what I have done is exciting, which combines both the first version and the reusable code. This also gives another set of values for your consideration, based on the value you get when you round off to the nearest tenth value.

function prop (dim) {  
  if (!!dim.x) {
    var y = 630 / 1200 * dim.x;
    console.log(dim.x.toFixed(2) + " × " + y.toFixed(2));
  }
  if (!!dim.y) {
    var x = 1200 / 630 * dim.y;
    console.log(x.toFixed(2) + " × " + dim.y.toFixed(2));
  }
}

function display (x, y) {  
  console.log("Values that you need:");
  prop({x: x, y: y});
  console.log("Values that you might consider:");
  prop({x: getRound(x, 1), y: getRound(y, 1)});
  prop({x: getRound(x, 2), y: getRound(y, 2)});
}

function getRound(n, p) {  
  if (!p)
    p = 1;
  var t = Math.pow(10, p);
  if (n % t === 0)
    return n;
  else
    return parseInt(n / t) * t;
}

And here goes with the preview.

See the Pen gdYvwa by Praveen Kumar (@praveenscience) on CodePen.

Version 3

With the previous version, you might have noticed something strange. Okay, let me tell you. I could find a lot of duplicates and also the values are getting repeated from the ones that are there in the original value. The reason for this is, if you get the nearest tenth or hundredth value of, say 700, it will be 700 for both. But the same thing for 755 will be 750 and 700.

To handle the duplicates, I used a few array methods to get only unique values and those that are rounded off too for the user's perusal.

function prop (dim) {  
  if (!!dim.x) {
    var y = 630 / 1200 * dim.x;
    return (dim.x.toFixed(2) + " × " + y.toFixed(2));
  }
  if (!!dim.y) {
    var x = 1200 / 630 * dim.y;
    return (x.toFixed(2) + " × " + dim.y.toFixed(2));
  }
}

function display (x, y) {  
  var need = [];
  var cons = [];
  console.log("Values that you need:");
  need.push(prop({x: x}));
  need.push(prop({y: y}));
  need = need.filter(function (value, index, self) { 
    return self.indexOf(value) === index;
  });
  need.forEach(function (v) {
    console.log(v);
  });
  console.log("Values that you might consider:");
  cons.push(prop({x: getRound(x, 1)}));
  cons.push(prop({y: getRound(y, 1)}));
  cons.push(prop({x: getRound(x, 2)}));
  cons.push(prop({y: getRound(y, 2)}));
  cons = cons.filter(function (value, index, self) { 
    return self.indexOf(value) === index && need.indexOf(value) === -1;
  });
  cons.forEach(function (v) {
    console.log(v);
  });
}

function getRound(n, p) {  
  if (!p)
    p = 1;
  var t = Math.pow(10, p);
  if (n % t === 0)
    return n;
  else
    return parseInt(n / t) * t;
}

With the same set of input, you can see that there's some reduction in the set of values, that are duplicated.

See the Pen Share Dimensions 4 by Praveen Kumar (@praveenscience) on CodePen.

Final Ultimate Version

With the code base from the last version and some nice UI effects like Bootstrap, I managed to create a better user interfact with the above code. This has some more serious array and object manipulations and checking for null values. Input values are validated to make sure it's an integer and provide necessary errors, in case of errors committed by the users.

Have a play with the fully working version here.

See the Pen Share Dimensions Ultimate by Praveen Kumar (@praveenscience) on CodePen.

I really hope you enjoyed reading this as much as I enjoyed writing this article. Let me know if you have any questions in the comments below. Until the next article, see you soon! 😇



comments powered by Disqus