Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>An example image manipulation script, It's not that fresh anymore but it was laying around when at the sametime some people want to see more examples.<br /> So here is my little contribution.</p> <p>Note to the groovy gurus: find more groovier ways.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> /** * A batch image manipulation utility * * A wrote this script just to get groovy, batch manipulate images in about * 240 lines of code (without this comment)!!!. * * commands: * values ending with '%' means size relative to image size. * values ending with 'px' means values in absolute pixels. * values without postfix use default notation. * * expressions: * scale(width,height) * height is optional(use width) e.g: scale(50%) == scale(50%,50%) * fit(width,height) * relative scale the image until if fits (defaut as scale) * * bounds of the given box, usefull for generating of thumbnails. * rotate(degrees,x,y) * the rotation position x and y are optional (default is 50%) * * TODO: move(x,y) * move the image within its own bounds (can be done with margin) * * y is optional(same height) * TODO: color(type) * color transformation * TODO: shear(degrees,x,y) * x and y is optional * margin(x,y,x2,y2) * add margins to image (resize image canvas), this operation can't * * be used on a headless environment. * parameters: * -d * working directory (default current directory) * -e * execute expressions from command line. * -f * execute expressions from file. * -p * file mathing pattern default is \.png|\.jpg * -q * output file pattern can use {0} .. {9} * * backreferences from the input pattern. default: output/{0} * -h * help, nothing special (maybe this doc using heredoc) * * Example generate thumbnails(take *.png from images fit them in a 100X100 box, * add 10px margin, put them in the thumbnail dir.) * * $ groovy image.groovy -d images -e "fit(100px,100px) margin(5)" -p "(.*)\.png" -q "thumbnail/{1}.png" * * @author Philip Van Bogaert alias tbone */ import java.io.*; import javax.imageio.*; import java.awt.*; import java.awt.image.*; import java.awt.geom.*; import java.util.*; class GroovyImage { File srcDir = new File(".") def operations = [] def pattern = ~".*(\\.png|\\.jpg)" def outputPattern = "output/{0}" void addOperation(command) { def matcher = command =~ "([a-z]+)\\((.*)\\).*"; matcher.find(); def method = matcher.group(1); def args = matcher.group(2).split(",").toList(); switch(method) { case "scale": // vertical,horizontal operations.add([this.&parseAndScale,argsLength(args,2)]); break; case "rotate": // degrees,x,y operations.add([this.&parseAndRotate,argsLength(args,3)]); break; case "margin": // left,top,right,bottom operations.add([this.&parseAndMargin,argsLength(args,4)]); break; case "fit": // width,height operations.add([this.&parseAndFit,argsLength(args,2)]); break; } } BufferedImage parseAndRotate(image,degrees,x,y) { def parsedRadians = 0; try { parsedRadians = Math.toRadians(Double.parseDouble(degrees)); } catch(NumberFormatException except) { } def parsedX = parseValue(x,image.width,true,"50%"); def parsedY = parseValue(y,image.height,true,parsedX); return rotate(image,parsedRadians,parsedX,parsedY); } BufferedImage rotate(image,radians,x,y) { def transform = new AffineTransform(); transform.rotate(radians,x,y); def op = new AffineTransformOp(transform,AffineTransformOp.TYPE_BILINEAR); return op.filter(image,null); } BufferedImage parseAndScale(image,horizontal,vertical) { def parsedHorizontal = parseValue(horizontal,image.width,false,"100%"); def parsedVertical = parseValue(vertical,image.height,false,parsedHorizontal); return scale(image,parsedHorizontal,parsedVertical); } BufferedImage scale(image,horizontal,vertical) { def transform = new AffineTransform(); transform.scale(horizontal,vertical); def op = new AffineTransformOp(transform,AffineTransformOp.TYPE_BILINEAR); return op.filter(image,null); } BufferedImage parseAndMargin(image,left,top,right,bottom) { def parsedLeft = parseValue(left,image.width,true,"0px"); def parsedTop = parseValue(top,image.height,true,parsedLeft); def parsedRight = parseValue(right,image.width,true,parsedLeft); def parsedBottom = parseValue(bottom,image.height,true,parsedTop); return margin(image,parsedLeft,parsedTop,parsedRight,parsedBottom); } BufferedImage margin(image,left,top,right,bottom) { def width = left + image.width + right; def height = top + image.height + bottom; def newImage = new BufferedImage(width.intValue(), height.intValue(),BufferedImage.TYPE_INT_ARGB); // createGraphics() needs a display, find workaround. def graph = newImage.createGraphics(); graph.drawImage(image,new AffineTransform(1.0d,0.0d,0.0d,1.0d,left,top),null); return newImage; } BufferedImage parseAndFit(image,width,height) { def parsedWidth = parseValue(width,image.width,true,"100%"); def parsedHeight = parseValue(height,image.height,true,parsedWidth); def imageRatio = image.width / image.height; def fitRatio = parsedWidth / parsedHeight; if(fitRatio < imageRatio) { parsedHeight = image.height * (parsedWidth/image.width); } else { parsedWidth = image.width * (parsedHeight/image.height); } return parseAndScale(image,parsedWidth+"px",parsedHeight+"px"); } BufferedImage manipulate(image) { for(operation in operations) { image = operation[0].call([image] + operation[1]); } return image; } void batch() { def images = getImages(); for(imageMap in images) { imageMap.image = manipulate(imageMap.image); storeImage(imageMap); } } Object getImages() { def imageMaps = []; for(i in srcDir.listFiles()) { if(!i.isDirectory()) { def subpath = i.path; if(subpath.startsWith(srcDir.path)) { subpath = subpath.substring(srcDir.path.length()); } def matcher = subpath =~ pattern; if(matcher.find()) { imageMaps.add(["file":i,"matcher":matcher]); } } } imageMaps.each({it["image"] = ImageIO.read(it["file"]); }); return imageMaps; } void storeImage(imageMap) { def groupIndex = 0; def name = outputPattern; def matcher = imageMap.matcher; while(groupIndex <= matcher.groupCount()) { name = name.replaceAll("\\{${groupIndex}\\}",matcher.group(groupIndex++)); } def type = name.substring(name.lastIndexOf(".")+1,name.length()); def file = new File(srcDir,name); file.mkdirs(); ImageIO.write(imageMap.image,type,file); } static void main(args) { def argList = args.toList(); def script =''; def groovyImage = new GroovyImage(); // command line parsing bit, NOTE: -h does System.exit(2) def argAndClosure = ['-d':{groovyImage.srcDir = new File(it)}, '-q':{groovyImage.outputPattern = it}, '-p':{groovyImage.pattern = it}, '-h':{groovyImage.help()}]; // parse non-conditional arguments parseMultipleCommandArgs(argList,argAndClosure); // expression,file,nothing if(!parseCommandArg(argList,'-e', {script = it})) { parseCommandArg(argList,'-f',{script = new File(it).text}); } // execution bit def commands = script =~ "([a-z]{1,}\\([^)]*\\))"; while(commands.find()) { groovyImage.addOperation(commands.group(1)); } groovyImage.batch(); } static boolean parseCommandArg(args,arg,closure) { def index = args.indexOf(arg); if(index != -1 && index + 1 < args.size()) { closure.call(args[index + 1]); return true; } else { return false; } } static void parseMultipleCommandArgs(args,argAndClosureMap) { for(argAndClosure in argAndClosureMap) { parseCommandArg(args,argAndClosure.key,argAndClosure.value); } } void help() { println('usage: groovy image.groovy -i <inputDir> -o <outputDir> -e "<expressions>"'); System.exit(2); } /** * absolute true -> returns pixels. * false -> returns relative decimal (e.g 1.0). */ Number parseValue(value,size,absolute,defaultValue="0") { def pattern = "(-?[0-9]+\\.?[0-9]*)(.*)"; def matcher = value =~ pattern; if(!matcher.find()) { matcher = defaultValue =~ pattern; matcher.find(); } def decimalValue = Double.parseDouble(matcher.group(1)); def type = matcher.group(2); if(absolute) { // pixels switch(type) { case "%": return (int) size * (decimalValue / 100); case "px": default: return (int) decimalValue; } } else { // scale switch(type) { case "px": return decimalValue / size; case "%": return decimalValue / 100; default: return decimalValue; } } } Object argsLength(args,length) { if(args.size() < length) { while(args.size() < length) { args.add(""); } } else { args = args.subList(0,length); } return args; } } </pre></td></tr></table>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced