In this post, I will share how I implemented logic to have Galaxie Blog automatically create social media sharing images for you when uploading an image for a given post.

Background

When a Galaxie Blog owner creates a post using the administrative interface, there is an option to upload an enclosure by clicking a Choose File button at the end of the add entry page. The interface is simple, when the Choose File button is clicked, it opens up a file browser and the user selects the image that they want to be displayed at the top of the post. In this post, the picture above is an abstract image that is 2200 pixels wide, and 1760 pixels in height. However, the social media images that the code below produces from this image will have different sizes that are optimized for both Facebook and Twitter. Galaxie Blog has always created a responsive image that automatically adjusts itself to fit on any modern device, however, I have now implemented logic that will manipulate the selected image and create both Facebook and Twitter social media images as well. Here is my approach...

Usage

To use this to create and save social media images, all that you need to do is invoke the createSocialMediaImages function below. It takes three arguments, the URL of the image that you want to perform operations on, the social media platform, and optionally, the Social Media Image Type. If the social media type argument is left blank (which is what I use in Galaxie Blog), the function will automatically determine the size and the proper aspect ratio. Here is the production code for Galaxie Blog that is working right now:

<!-- Set the path. --->
<cfset socialMediaImagePath="D:homegregoryalexander.comwwwrootlogenclosuresaspectRatio1.jpg">
<!-- Automatically generate social media images for Facebook, Twitter, Instagram and LinkedIn. --->
<cfset createSocialMediaImages(socialMediaImagePath,="" 'facebook',="" '')="">
<cfset createSocialMediaImages(socialMediaImagePath,="" 'twitter',="" '')="">
<cfset createSocialMediaImages(socialMediaImagePath,="" 'instagram',="" '')="">
<cfset createSocialMediaImages(socialMediaImagePath,="" 'linkedIn',="" '')=""> 

Logic Walkthrough

I am assuming that if you're reading this, you're someone with the technical skills that can read this and try it out, so I'll jump right in to briefly cover the core logic of this approach. For the sake of clarity, I will only cover how the logic creates Facebook social media images. Most of the logic for the other platforms is the same, and I'll provide the full code at the end of the article. Once the blog image is selected by the blog owner, Galaxie Blog will first get the width and height of the uploaded enclosure image that was just uploaded.

<cfimage action="info" source="#socialMediaImagePath#" structname="imageInfo">
</cfimage>

The logic will then compare the height and width of the original image and determine which type of image will be used. Essentially, are we going to use the largest image type specified by the social media platform, or the minimum depending upon the image that was just uploaded.

<cfcase value="facebook">
	<!--- Is the original image larger or smaller than Facebook's large image size? If larger, use the larger image dimensions specified by the social media platform. If the original image is smaller, use a smaller sized image. We are going to use similiar logic for every social media platform. --->
	<cfif imageInfo.width gte facebookSharedImageWidth and imageInfo.height gte facebookSharedImageHeight>
		<!--- Use the larger social media format. --->
		<cfset socialMediaImageType = "facebookSharedImage">
	<cfelse>
		<cfif imageInfo.width gte facebookLinkRectangleImageWidth and imageInfo.height gte facebookLinkRectangleImageHeight>
			<cfset socialMediaImageType = "facebookLinkRectangleImage">
		<cfelse><!---<cfif imageInfo.width gte facebookLinkRectangleImageWidth and imageInfo.height gte facebookLinkRectangleImageHeight>--->
			<!--- Use the facebookLinkSquareImage --->
			<cfset socialMediaImageType = "facebookLinkSquareImage">
		</cfif><!---<cfif imageInfo.width gte facebookLinkRectangleImageWidth and imageInfo.height gte facebookLinkRectangleImageHeight>--->
	</cfif>
</cfcase>

First, we will double-check the images again to make sure that the uploaded image has a larger size than the social media sharing image that we will create. If the uploaded image is larger, we'll set the width and height to match the larger image type. If the uploaded image is smaller than the largest recommended size, we will use the minimum size recommended by the social media platform, and we may set a pre-crop variable to true if necessary. We'll cover this logic next.

<cfcase value="facebookSharedImage">
	<!--- Is the original image larger or smaller than the large image size? If larger, use the larger image dimensions specified by the social media platform. If the original image is smaller, use the miniumum size. We are going to use the same logic for every social media type. --->
	<cfif imageInfo.width gte facebookSharedImageWidth and imageInfo.height gte facebookSharedImageHeight>
		<!--- Use the larger social media format. --->
		<cfset thisImageWidth = facebookSharedImageWidth>
		<cfset thisImageHeight = facebookSharedImageHeight>
	<cfelse>
		<!--- Use the rectangular facebook format. --->
		<cfset thisImageWidth = facebookLinkRectangleImageWidth>
		<cfset thisImageHeight = facebookLinkRectangleImageHeight>
		<cfset preCrop = true>
	</cfif>
</cfcase>

Resizing a copy of the original uploaded image

Next we'll check to see if the original image is twice as wide as the targetted social media size. If it is, or if the preCrop variable was set in the previous switch statements, we will create a copy of the original image, and then resize the new image. The code below illustrates this. I removed all of the code other than the Facebook code.

<cfif preCrop>

	<!--- Create a new image --->
	<cfset shareImage = imageNew(socialMediaImagePath)>

	<!--- Handle small images. --->
	<!--- This logic is only invoked for Facebook rectangle links. --->
	<cfif socialMediaImageType eq 'facebookLinkRectangleImage'>

		<!--- Resize the new image. For portrait images, we are going to resize the image to 550 pixels wide. --->
		<cfset imageResize(shareImage, 550, '')>
		<!--- We know the width of the new image that was just created (550), now get it's height --->
		<cfset shareImageWidth = imageGetHeight(shareImage)>
		<!--- Crop the resized image from the center (centerCrop(path/image, originalWidth, originalHeight, newWidth, newHeight). We don't need to determine an aspect ratio. It is a square. --->
		<cfset shareImage = centerCrop(shareImage, 550, shareImageWidth, thisImageWidth, thisImageHeight)>

	</cfif><!---<cfif (socialMediaImageType eq 'facebookLinkRectangleImage'>--->
</cfif>

Maintaining the aspect ratio using our nifty ColdFusion ratio calculator function

One of the most critical requirements is having the ability to resize images while maintaining the targeted aspect ratio. I could not find a ColdFusion function that did this, so I had to build my own. If you play around with manipulating images and aspect ratios, this type of function should belong in your own toolbox. Our ratioCalculator function below takes 3 arguments. The aspectRatioWidth and aspectRatioHeight arguments should match the recommended width and height of our targetted social media image that is indicated in the prior post. For the large Facebook Shared Image, the ratio aspect is 1200 pixels wide, and 630 pixels in height. We'll go ahead and plug these values in for the first two arguments as this is the aspect ratio that we want to keep, no matter what size we eventually resize the image to. The third argument is the newWidth argument. Here, the newWidth argument will either be: the original width of the uploaded image: or, the new width when we resized the image in the step above when the size of the uploaded image was twice the width of the recommended Facebook image size. The ratio calculator function will take these three values, and return the height that is needed to maintain the original aspect ratio. To get the new height of the image, all that we need to specify is the recommended width and height, provided by the social media platform, and the new width that we want to resize an image to be. The new width argument can be smaller, or larger, than the aspect ratio size. No matter what you plugin for the new width, the aspect ratio will be maintained.

<cffunction name="ratioCalculator" access="public" output="true" returnType="numeric" hint="This is used to determine the new dimensions needed to fit a certain width while maintaining the specified aspect ratio. I am using this to determine how to resize an image to meet the aspect ratio used by varius social media sites.">
	<cfargument name="aspectRatioWidth" required="yes" hint="Specify the original width of the image.">
	<cfargument name="aspectRatioHeight" required="yes" hint="Specify the original height of the image.">
	<cfargument name="newWidth" required="yes" hint="Specify the desired width of the new image.">

	<cfset newHeight = (arguments.aspectRatioHeight / arguments.aspectRatioWidth) * arguments.newWidth>

	<cfreturn newHeight>
</cffunction>

Cropping the images

The code has two cropping functions, centerCrop, and horizontalCrop. The centerCrop function is used when we have a landscape image, and the horizontalCrop function is used when using a portrait image. The centerCrop function takes five arguments, we need to specify the full path of the image, or the variable of the image if we are creating a new image using the newImage ColdFusion function. The original width and original height arguments using the social media recommended size. Here, we are using the large Facebook size of 1200 for the originalWidth, and 630 for the originalHeight. The fourth argument, width, is either the width of the uploaded image, or the width of the newly resized image, and finally, new height, which is provided by the ratioCalculator function that we just covered above. This function will crop the image from the center.

<cffunction name="centerCrop" access="public" output="true" returnType="string" hint="Used to crop an image with a desired size that is smaller both horizontally and vertically than the original image. This will crop the image from the center.">
	<cfargument name="imagePath" required="yes" hint="Provide either the full original path of the image, or the actual ColdFusion image using the newImage function.">
	<cfargument name="originalWidth" required="yes" hint="Provide the original width of the image.">
	<cfargument name="originalHeight" required="yes" hint="Provide the original width of the image.">
	<cfargument name="newWidth" required="yes" hint="Provide the desired width of the cropped image.">
	<cfargument name="newHeight" required="yes" hint="Provide the desired height of the new cropped image.">
	<!--- Local debugging carriage. If something goes awry, set this to true. --->
	<cfset debug = true>
		
	<!--- This algorithm was found at https://www.raymondcamden.com/2010/02/03/Cropping-to-the-center-of-an-image --->
	<cfset originalImage = "#arguments.imagePath#"> 
	<!--- Make a copy of the original image. --->
	<cfset croppedImage = imageNew(originalImage)> 
	<!--- Get the coordinates. We will subtract the orinal width minus the new width to grab the center of the new image.  --->
	<cfset xCoordinate = (originalWidth - newWidth) / 2>
	<cfset yCoordinate  = (originalHeight - newHeight) / 2>
			
	<cfif debug>
		<cfoutput>
			originalWidth: #originalWidth#<br/>
			originalHeight: #originalHeight#<br/>
			newWidth: #newWidth#<br/>
			newHeight: #newHeight#<br/>
			xCoordinate #xCoordinate#<br/> 
			yCoordinate" #yCoordinate#<br/>
		</cfoutput>
	</cfif>
			
	<!--- Crop the image. --->
	<cfset imageCrop(croppedImage, xCoordinate, yCoordinate, newWidth, newHeight)> 
			
	<!--- And return it. --->
	<cfreturn croppedImage>
</cffunction>

The horizontalCrop, used when we are uploading a portrait image, leaves the width intact, but crops the top and the bottom of the picture equally. This function takes three arguments, the imagePath (or the variable name of the new image when we use the imageNew ColdFusion function), the original height of the uploaded image, and the new height. I am using our ratioCalculator function to provide the new height again while maintaining the original aspect ratio recommended by the social media platform. Again, this example uses the large Facebook size of 1200 for the originalWidth, and 630 for the originalHeight.

<cffunction name="horizontalCrop" access="public" output="true" returnType="string" hint="Used to crop a horizontal image that has a horizontally size that is greater than the desired size of the new image. This will crop the image from the horizontal center.">
	<cfargument name="imagePath" required="yes" hint="Provide the full original path of the image.">
	<cfargument name="originalHeight" required="yes" hint="Provide the original width of the image.">
	<cfargument name="newHeight" required="yes" hint="Provide the desired height of the new cropped image.">
	<!--- Local debugging carriage. If something goes awry, set this to true. --->
	<cfset debug = true>
		
	<!--- This algorithm was found at https://www.raymondcamden.com/2010/02/03/Cropping-to-the-center-of-an-image --->
	<cfset originalImage = "#arguments.imagePath#"> 
	<!--- Make a copy of the original image. --->
	<cfset croppedImage = imageNew(originalImage)> 
	<!--- Get the coordinates. The x coordinate starts at 0. The image only needs to be cropped vertically.  --->
	<cfset xCoordinate = 0>
	<cfset yCoordinate  = (originalHeight - newHeight) / 2>
			
	<cfif debug>
		<cfoutput>
			originalHeight: #originalHeight#<br/>
			newHeight: #newHeight#<br/>
			xCoordinate #xCoordinate#<br/> 
			yCoordinate" #yCoordinate#<br/>
		</cfoutput>
	</cfif>
			
	<!--- Crop the image. --->
	<cfset imageCrop(croppedImage, xCoordinate, yCoordinate, newWidth, newHeight)>
			
	<!--- And return it. --->
	<cfreturn croppedImage>
			
</cffunction>

This is a rather long and complex post. In my next post, I'll provide some concise examples of social media images that this function creates.

Get the code

The code is published as a git hub repository. This component will also become a part of Galaxie Blog in the next release.

Further Reading

Some of the logic in the center crop function was taken from Raymond Camden's article at https://www.raymondcamden.com/2010/02/03/Cropping-to-the-center-of-an-image