Image EXIF Orientation support

We have a couple of customers that has user generated content, one problem we see here is that images that are posted often have wrong orientation. Has anyone extended image formtool to handle this? I think this should be a part of FarCry Core.

Read more about EXIF orientation here:
http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/

This shouldn’t be too hard to fix in core (and I agree that it should be in core).

If I have time I’ll see if I can make the change and submit a pull request. Not sure when I can get to it though as I’m a bit swamped with work (so it might be a good while until I can get to it). But if you want to submit a pull request with the changes, feel free.

I’ve thrown together some code to test this:
http://amerika.no/tests/exif-test.zip

The final output/test (column 3) are rotated and should display correct in all image viewers/browsers but are missing EXIF meta data. I guess EXIF should be kept, but EXIF orientation should be deleted or modified?

@modius / @justincarter: What do you think? Should we rotate and remove EXIF orientation for the source image, or should we do this per image that are generated from the source image?

So I wrote code in core (in my dev environment) that same day to fix the issue. The problem is that ColdFusion doesn’t allow you to target specific exif metadata fields. It only allows you to wipe all of them. So, yes, the issue can be addressed, but it introduces a new problem. Not sure what the best approach is here. Maybe there is a java solution that can be used?

I have had good luck with this on the front end side. I have forms that allow users to post images so this script is purely based on that, but maybe someone can see some value in this for FarCry.

I basically upload all the images, and pop the source path into an array to process 2 mins later in a cfthread, this keeps the user from having to wait on the labor intensive process of image processing. I also check for proper sizings, (min and max) as well as deletion if the image doesn’t meet the requirements we need, but I let that out for the purpose of this example.

The ImageGetEXIFTag returns the human readable string to me, something like “ORIENTATION_ROTATE_180”, I just “kill” the human readable part with a rereplace, and get the number that it was rotated, then pass that in an array to the thread as a value to rotate back to normal.

<cfset imagesPathArray = ArrayNew(1)>
<cfset rotationArray = ArrayNew(1)>

<cfif isDefined("Form.image")> 
<cfset path="my_path">
<cfif NOT DirectoryExists(path)>
	<cfdirectory action="create" directory="#path#">
</cfif>

<!--- upload all the images --->
<cffile action="uploadAll" filefield="image" destination="#path#" nameConflict="makeUnique" accept="image/jpeg,image/png,image/gif,multipart/form-data" result="uploads">  
		
<!--- loop through the images, just as a double check to make sure everything is good, and the image is not too small--->
<cfloop index="i" from="1" to="#ArrayLen(uploads)#">
	<cfset cfImage = imageNew(#uploads[i].SERVERDIRECTORY# & "\" & #uploads[i].SERVERFILE#)>
		
	<!--- make sure the image is rotated properly --->
    <cfset orientation  = ImageGetEXIFTag(cfImage, 'orientation')>

    <cfif isDefined('orientation') AND orientation NEQ ''>
        <cfset hasRotate = findNoCase('rotate',orientation)>
        
        <cfif isDefined('hasRotate')>
            <!--- I just want the angle number of rotation, not the human readable text part --->
            <cfset rotateValue = reReplace(orientation,'[^0-9]','','all')>
        </cfif>
        
        <!--- if we need to rotate an image --->
        <cfif rotateValue NEQ ''>
            <cfset ArrayAppend(rotationArray, rotateValue)>
        <cfelse>
            <cfset ArrayAppend(rotationArray, 'none')>
        </cfif>
    <cfelse>
        <cfset ArrayAppend(rotationArray, 'none')>
    </cfif>
    
        <cfset ArrayAppend(imagesPathArray, #imageData.source#)>
</cfloop>   
		 
<!--- Process the images after a 2 min delay --->
<cfthread name="rotateImages" action="run" rotationArray="#rotationArray#" imagesArray="#imagesPathArray#">
	<cfscript>
		Sleep(120000);
	</cfscript>
	
	<cfloop index="a" from="1" to="#ArrayLen(rotationArray)#"> 
		<cfif rotateImagesArray[a] NEQ 'none'>
			<cfimage action="rotate" source="#imagesArray[a]#" destination="#imagesArray[a]#" angle="#rotateImagesArray[a]#" overwrite="yes" />
		</cfif>
	</cfloop>
</cfthread>    
</cfif>
1 Like

@tangerineinds: It’s not in your example, but do you update orientation metadata?

Your code does not handle:
Top, right side (Mirror horizontal) = needs to be flipped horizontal,
Bottom, left side (Mirror vertical) = needs to be flipped vertical
Left side, top (Mirror horizontal and rotate 270 CW) = needs to be flipped diagonal
Right side, bottom (Mirror horizontal and rotate 90 CW) = needs to be flipped antidiagonal

@jorgenskogas I dont manipulate the meta at all, I just replace the image with the proper rotation (overwrite the file), which in turn “replaces” the exif meta. I have not come across the examples you illustrate, so I have not accounted for them.

I know this isen’t what you all intended for a solution, but I posted some code in an effort to spurn an idea, or help someone that may just want to manipulate an image for display purposes.