Add Padding to an image with an offset

Hey,

I’m trying to add black padding to just the bottom of an image. Using the crop function in Image Events seems to get me Black at the top and bottom.

I would really like to do this pure AppleScript/ASObj-C no ImageMagik as I don’t want to have to deal with installing that on all of the clients that will be using this.

Any ideas?

Can you explain in a bit more detail what you’re trying to do?

Use image events to:

  1. Get the image size in pixels
  2. Use the “Pad” command to pad both the top and the bottom with black pixels, to leave the amount of black you want on the bottom.
  3. Use the crop command to exactly crop the black padding back off the top of the image, leaving it on the bottom.

Oops, sorry, that doesn’t work. I mistakenly thought Image Events’ “Crop” argument accepted four arguments as parameters and let you crop arbitrarily, but apparently, it always crops to center. “Pad” always pads based on the center. Seems ludicrous, but I think you’re out of luck doing this in pure Applescript. There’s probably an ASObjC solution, but it’s beyond me. I could only do this in Applescript with shell commands to ImageMagik or similar, or a “tell application” to Photoshop, GraphicConverter, or whatever. That would involve installing something on every computer. Even Preview doesn’t seem to have a “crop” command.

Sorry.

I checked SIPS to see if the limitation is Image Events or SIPS iteself, and it’s SIPS itself, so a “do shell script” addressing SIPS can’t help you here either.

I’m pretty sure that without installing anything else, ASObjC using Core Image is your only shot.

Core Image can certainly handle this, its crop parameters look like this:

let cropRect = CGRect(x: 350, y: 350, width: 150, height: 150)

So it’s giving you a position as well as a width and a height.

Best of luck, I’ll be interested if Shane or one of the other ASObjC gurus chimes in, it would be great to have an example of the basic code to use Core Image via Applescript.

Shane - while it would obviously be better if mwright answered, since he alone knows the objective, I expect he’s just looking for any code that adds some arbitrary amount of black pixels to only the bottom of an image file. It would be nice, for the sake of prototype code, to know if he always wants to add [x# of pixels] or [x% of the image height] or [pad to equal a fixed total height] or [pad to achieve given aspect ratio], etc. But once there’s any functioning example of padding an image asymmetrically, adapting it to any scenario is just basic math.

There’s a bit more to than that, but OK, this will just add a black area at the bottom to the depth you specify:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

on padBottomOfImageAt:POSIXPath byPoints:padDepth
	-- build path for new file
	set anNSString to current application's NSString's stringWithString:POSIXPath
	set newPath to anNSString's stringByDeletingPathExtension()
	set theExt to anNSString's pathExtension() as text
	set newPath to (newPath's stringByAppendingString:"-2")'s stringByAppendingPathExtension:theExt
	-- load image as bitmap and get its size
	set oldRep to current application's NSBitmapImageRep's imageRepWithContentsOfFile:POSIXPath
	set {width:theWidth, height:theHeight} to oldRep's |size|()
	set newHeight to theHeight + padDepth
	-- make new bitmapImageRep
	set newRep to (current application's NSBitmapImageRep's alloc()'s initWithBitmapDataPlanes:(missing value) pixelsWide:theWidth pixelsHigh:newHeight bitsPerSample:8 samplesPerPixel:4 hasAlpha:true isPlanar:false colorSpaceName:(current application's NSCalibratedRGBColorSpace) bitmapFormat:(current application's NSAlphaFirstBitmapFormat) bytesPerRow:0 bitsPerPixel:32)
	-- store the existing graphics context
	current application's NSGraphicsContext's saveGraphicsState()
	-- set graphics context to new context based on the new bitmapImageRep
	(current application's NSGraphicsContext's setCurrentContext:(current application's NSGraphicsContext's graphicsContextWithBitmapImageRep:newRep))
	-- set the color to black
	current application's NSColor's blackColor()'s |set|()
	-- fill the bottom area with black
	current application's NSRectFill({origin:{x:0, y:0}, |size|:{width:theWidth, height:padDepth}})
	-- draw from the original bitmapImageRep to the new one above the black area
	oldRep's drawInRect:{origin:{x:0, y:padDepth}, |size|:{width:theWidth, height:theHeight}} fromRect:{origin:{x:0, y:0}, |size|:{width:theWidth, height:theHeight}} operation:(current application's NSCompositeSourceOver) fraction:1.0 respectFlipped:true hints:(missing value)
	-- restore graphics state
	current application's NSGraphicsContext's restoreGraphicsState()
	-- save bitmapImageRep as image
	if {"tif", "tiff"} contains {theExt} then
		set theData to (newRep's representationUsingType:(current application's NSTIFFFileType) |properties|:{NSTIFFCompression:(current application's NSTIFFCompressionLZW)})
	else if {"jpg", "jpeg"} contains {theExt} then
		set theData to (newRep's representationUsingType:(current application's NSJPEGFileType) |properties|:{NSImageCompressionFactor:0.8, NSImageProgressive:true})
	else if theExt = "png" then
		set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:true})
	else -- unsupported type
		return false
	end if
	set theResult to (theData's writeToFile:newPath atomically:true)
	return (theResult as boolean)
end padBottomOfImageAt:byPoints:

set thePath to POSIX path of (choose file)
my padBottomOfImageAt:(thePath) byPoints:100

Thanks Shane.

I see mrwright only has one post - I don’t know if he missed the fact you have to manually subscribe to threads in this forum, or just pulled a disappearing act. But I appreciate the code anyway. I don’t have an immediate use, but it’s a great example for me to use to start playing with Core Image via Applescript, and I expect I’ll need this exact functionality sooner or later, so I think I’ll try to adapt the handler to accept arguments for which side is being padded and what color it’s padding with, and keep it around.

It can be done a little more simply, but that’s reasonably flexible code. One thing that might not be obvious is that the two bitmaps don’t have to be the same size; drawing from a larger one into a smaller one is how you resize an image, for example.

And there are other options apart from NSCompositeSourceOver, for blending and what-not.

Hey, sorry to have left this thread like this. My life interrupted things for me for a little while.

So, you guys figured it out. I basically only needed black at the bottom of my image and doing it by inputting pixels works great. I can math everything else. I’ve lurked the forums for quite a while and just never posted till now.

I’m going to try that code and see if I can get it to work. I’ll respond back soon. Sorry again about disappearing on you guys.

:slight_smile:

Just tried it and got it to work. Thanks so much! This is a life saver and works exactly as I need it to. I just started dipping my toes into ASObjC and these little snippet’s have been super helpful. You’re the man Shane!

(Next time I’ll try to be more on it in terms of my reply’s, thanks for keeping up with it anyways guys.)