Color
The creation, blending, and application of colors to shapes and text is a common task performed in all Omni applications. This page details how to work with color values in various color spaces.
Color Functions
The following functions are used to create instances of the Color class:
RGB(redValue, greenValue, blueValue, alphaValue or nil) (Color) • Makes a new color in the RGB colorspace, with the given components. If the alpha component is not given, 1.0 is used.
HSB(hueValue, saturationValue, brillianceValue, alphaValue or nil) • Makes a new color in the HSB colorspace, with the given components. If the alpha component is not given, 1.0 is used.
White(whiteValue, alphaValue or nil) • Makes a new color in the White colorspace, with the given components. If the alpha component is not given, 1.0 is used. A White value of: 0 is black, .5 is 50% gray.
Here’s an OmniGraffle script example that creates a green circle (in the RGB color space) with a 50% transparency (alpha value) overlaid on a blue square:
Create Shapes with Color Fills
var cnvs = document.windows[0].selection.canvas
var square = cnvs.addShape('Rectangle', new Rect(72,72,200,200))
square.fillColor = Color.RGB(0, 0, 1, 1)
var circle = cnvs.addShape('Circle', new Rect(150,150,200,200))
circle.fillColor = Color.RGB(0, 1, 0, 0.5)
Here’s an OmniGraffle script example that adds grayscale tint swatches, from black to white in increments of 10%, to the current canvas:
Grayscale Bar - 10% Increments
var cnvs = document.windows[0].selection.canvas
var objSize = 48
var offset = 0
var swatches = new Array()
for(i = 0; i < 11; i++){
offset = offset + objSize
var aRect = new Rect(offset, objSize, objSize, objSize)
var graphic = cnvs.addShape('Rectangle', aRect)
var color = Color.White(i*.1,1)
graphic.fillColor = color
swatches.push(graphic)
}
var swatchStrip = new Group(swatches)
Color Class Properties
Some common colors can be represented with the following property values instead of using one of the Color methods.
Common Color Values
graphic.fillColor = Color.blue
black (Color) • A color in the White colorspace with white component of 0.0.
blue (Color) • A color in the RGB colorspace with components (0, 0, 1, 1).
brown (Color) • A color in the RGB colorspace with components (0.6, 0.4, 0.2, 1).
clear (Color) • A color in the White colorspace with white component of 0.0 and alpha of 0.0 (“transparent black”).
cyan (Color) • A color in the RGB colorspace with components (0, 1, 1, 1).
darkGray (Color) • A color in the White colorspace with white component of 0.333.
gray (Color) • A color in the White colorspace with white component of 0.5.
green (Color) • A color in the RGB colorspace with components (0, 1, 0, 1).
lightGray (Color) • A color in the White colorspace with white component of 0.667.
magenta (Color) • A color in the RGB colorspace with components (1, 0, 1, 1).
orange (Color) • A color in the RGB colorspace with components (1, 0.5, 0, 1).
purple (Color) • A color in the RGB colorspace with components (1, 0, 1, 1).
red (Color) • A color in the RGB colorspace with components (1, 0, 0, 1).
white (Color) • A color in the White colorspace with white component of 1.0.
yellow (Color) • A color in the RGB colorspace with components (1, 1, 0, 1).
Color Instance Properties
Once a Color object has been created, you can use the following instance properties to gather information about the color object.
alpha (Number r/o) • Returns the alpha component of the color.
blue (Number r/o) • Returns the blue component of the color, after converting to a RGB colorspace.
brightness (Number r/o) • Returns the brightness component of the color, after converting to a HSB colorspace.
colorSpace (ColorSpace r/o) • Returns the colorspace of the instance.
green (Number r/o) • Returns the green component of the color, after converting to a RGB colorspace.
hue (Number r/o) • Returns the hue component of the color, after converting to a HSB colorspace.
red (Number r/o) • Returns the red component of the color, after converting to a RGB colorspace.
saturation (Number r/o) • Returns the saturation component of the color, after converting to a HSB colorspace.
white (Number r/o) • Returns the white component of the color, after converting to a White colorspace.
Color Instance Functions
Color objects can be blended to create new colors, using the blend() method:
blend(otherColor, fractionNumber) (Color or nil) • Returns a new color that is a linear combination of the receiver and fraction of the other color (so, a fraction of 1.0 would just return the otherColor. If the colors cannot be blended (for example, if they cannot be converted to the same colorspace), then null is returned.
Here’s an example of blending colors: creating an orange circle by blending red and yellow
New Shape with Blended Colors
var cnvs = document.windows[0].selection.canvas
var graphic = cnvs.addShape('Circle', new Rect(0, 0, 200, 200))
var colorA = Color.red
var colorB = Color.yellow
var blendColor = colorA.blend(colorB, 0.5)
graphic.fillColor = blendColor
ColorSpace
A color space is a specific organization of colors.
CMYK (ColorSpace r/o) • A colorspace with cyan, magenta, yellow, black, and alpha components.
HSB (ColorSpace r/o) • A colorspace with hue, saturation, and value (or brightness) components.
Named (ColorSpace r/o) • A space for named colors, like system defined colors, or specific color palette spaces.
Pattern (ColorSpace r/o) • A colorspace that wraps a pattern image.
RGB (ColorSpace r/o) • The sRGB colorspace with red, green, blue, and alpha components.
White (ColorSpace r/o) • A colorspace with white and alpha components.
Examples
Here are some script examples using the Color class:
Hex Color Value for Color Object
function componentToHex(c){
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function HEXforColor(clrObj){
rv = clrObj.red
gv = clrObj.green
bv = clrObj.blue
r = Math.round(rv * 255)
g = Math.round(gv * 255)
b = Math.round(bv * 255)
colorHEX = "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
return colorHEX.toUpperCase()
}
Calling the Functions
var clrObj = Color.RGB(0.22574300483333884, 0.7168752888153417, 0.996078431372549, 1)
HEXforColor(clrObj) //--> "#3ab7fe"
Do Colors Match?
function RGBMatch(colorA, colorB){
return (
colorA.red === colorB.red &&
colorA.green === colorB.green &&
colorA.blue === colorB.blue
) ? true:false
}
Color Info Plug-In
An OmniGraffle plug-in for displaying the color information of the selected graphic. Color object constructor statements for each of the colors (stroke, fill, text) will be logged to the console.
Color Info of Selected Graphic
/*{
"type": "action",
"targets": ["omnigraffle"],
"author": "Otto Automator",
"identifier": "com.omni-automation.og.color-info",
"version": "1.0",
"description": "Present the color information for the selected graphic.",
"label": "Color Info",
"shortLabel": "Color Info"
}*/
(() => {
function componentToHex(c){
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function HEXforColor(clrObj){
rv = clrObj.red
gv = clrObj.green
bv = clrObj.blue
r = Math.round(rv * 255)
g = Math.round(gv * 255)
b = Math.round(bv * 255)
colorHEX = "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
return colorHEX
}
var action = new PlugIn.Action(function(selection, sender){
// action code
var graphic = selection.graphics[0]
// console.clear()
if(graphic.fillColor){
var graphicFillColor = graphic.fillColor
var fillColorHEX = HEXforColor(graphicFillColor).toUpperCase()
var red = String(graphicFillColor.red)
var green = String(graphicFillColor.green)
var blue = String(graphicFillColor.blue)
var alpha = String(graphicFillColor.alpha)
var fillValues = "R: " + red + "\n" + "G: " + green + "\n" + "B: " + blue + "\n" + "A: " + alpha
console.log(`FILL: ${fillColorHEX}`, `Color.RGB(${red}, ${green}, ${blue}, ${alpha})`)
} else {
var fillValues = "No Fill"
var fillColorHEX = "N/A"
}
if(graphic.strokeColor){
var graphicStrokeColor = graphic.strokeColor
var strokeColorHEX = HEXforColor(graphicStrokeColor).toUpperCase()
var red = String(graphicStrokeColor.red)
var green = String(graphicStrokeColor.green)
var blue = String(graphicStrokeColor.blue)
var alpha = String(graphicStrokeColor.alpha)
var strokeValues = "R: " + red + "\n" + "G: " + green + "\n" + "B: " + blue + "\n" + "A: " + alpha
console.log(`STROKE: ${strokeColorHEX}`, `Color.RGB(${red}, ${green}, ${blue}, ${alpha})`)
} else {
var strokeValues = "No Stroke"
var strokeColorHEX = "N/A"
}
if(graphic instanceof Shape && graphic.textColor){
var graphicTextColor = graphic.textColor
var textColorHEX = HEXforColor(graphicTextColor).toUpperCase()
var red = String(graphicTextColor.red)
var green = String(graphicTextColor.green)
var blue = String(graphicTextColor.blue)
var alpha = String(graphicTextColor.alpha)
var colorValues = "R: " + red + "\n" + "G: " + green + "\n" + "B: " + blue + "\n" + "A: " + alpha
console.log(`TEXT: ${textColorHEX}`, `Color.RGB(${red}, ${green}, ${blue}, ${alpha})`)
} else {
var colorValues = "No Color"
var textColorHEX = "N/A"
}
var message = `FILL: ${fillColorHEX}\n` + fillValues + `\n\nSTROKE: ${strokeColorHEX}\n` + strokeValues + `\n\nTEXT: ${textColorHEX}\n` + colorValues
new Alert("Graphic Colors", message).show()
});
action.validate = function(selection, sender){
// validation code
// One single graphic selected (not a group)
if (selection.graphics.length === 1){
if (selection.graphics[0] instanceof Group){
return false
} else {
return true
}
} else { return false}
};
return action;
})();
Find/Change Colors
This OmniGraffle plug-in will find and replace all occurrences of a specified HEX color used in any of the selected ways (fill color, stroke color, text color) in all of graphics of the current canvas. If some graphics are already selected, they will be processed, otherwise if no graphics are selected, all graphics on the canvas will be processed.
Find/Replace HEX Color
/*{
"type": "action",
"targets": ["omnigraffle"],
"author": "Otto Automator",
"identifier": "com.omni-automation.og.find-change-color",
"version": "1.7",
"description": "Will replace the indicated HEX color value for fill, stroke, and text in either the selected graphics, or if no graphics are selected, all graphics on the current canvas.",
"label": "Find/Change Color",
"shortLabel": "Find/Change Color"
}*/
(() => {
var changeCount = 0
function incrementChangeCount(){
changeCount = changeCount + 1
}
function componentToHex(c){
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function HEXforColor(clrObj){
rv = clrObj.red
gv = clrObj.green
bv = clrObj.blue
r = Math.round(rv * 255)
g = Math.round(gv * 255)
b = Math.round(bv * 255)
colorHEX = componentToHex(r) + componentToHex(g) + componentToHex(b);
return colorHEX.toUpperCase()
}
function hexToRGBColorObject(hexStr) {
var r = 0, g = 0, b = 0;
r = "0x" + hexStr[0] + hexStr[1];
g = "0x" + hexStr[2] + hexStr[3];
b = "0x" + hexStr[4] + hexStr[5];
var red = (+r / 255).toFixed(10)
var green = (+g / 255).toFixed(10)
var blue = (+b / 255).toFixed(10)
return Color.RGB(Number(red), Number(green), Number(blue), 1)
}
function colorMatch(hexColor, clrObj){
var objHEXvalue = HEXforColor(clrObj)
var hexValue = objHEXvalue
return (hexColor === hexValue) ? true:false
}
function RGBMatch(colorA, colorB){
return (
colorA.red === colorB.red &&
colorA.green === colorB.green &&
colorA.blue === colorB.blue
) ? true:false
}
function processGroup(aGroup, shouldChangeFill, shouldChangeStroke, shouldChangeText, targetHEX, replacementColor){
processItems(aGroup.graphics, shouldChangeFill, shouldChangeStroke, shouldChangeText, targetHEX, replacementColor)
}
function processItems(items, shouldChangeFill, shouldChangeStroke, shouldChangeText, targetHEX, replacementColor){
items.forEach(item => {
if (item instanceof Shape){
var itemName = (item.name) ? item.name : ""
console.log("Shape", item.id, itemName)
if(shouldChangeText && item.textColor){
if (colorMatch(targetHEX, item.textColor)){
item.textColor = replacementColor
incrementChangeCount()
console.log("Shape", item.id, "text changed")
}
}
if(shouldChangeFill && item.fillColor){
if (colorMatch(targetHEX, item.fillColor)){
item.fillColor = replacementColor
incrementChangeCount()
console.log("Shape", item.id, "fill changed")
}
}
if(shouldChangeStroke && item.strokeColor){
if (colorMatch(targetHEX, item.strokeColor)){
item.strokeColor = replacementColor
incrementChangeCount()
console.log("Shape", item.id, "stroke changed")
}
}
}
else if (item instanceof Line){
var itemName = (item.name) ? item.name : ""
console.log("Line", item.id, itemName)
if(shouldChangeStroke && item.strokeColor){
if (colorMatch(targetHEX, item.strokeColor)){
item.strokeColor = replacementColor
incrementChangeCount()
console.log("Line", item.id, "stroke changed")
}
}
}
else if (item instanceof Group){
var itemName = (item.name) ? item.name : ""
console.log("Group", itemName)
processGroup(item, shouldChangeFill, shouldChangeStroke, shouldChangeText, targetHEX, replacementColor)
}
else {
var itemName = (item.name) ? item.name : ""
console.log("Unknown", item.id, itemName)
}
})
}
var action = new PlugIn.Action(function(selection, sender){
// action code
var targetColorField = new Form.Field.String(
"targetColor",
"Search for",
"FFFFFF"
)
var replaceColorField = new Form.Field.String(
"replaceColor",
"Replace with",
"000000"
)
var fillCheckbox = new Form.Field.Checkbox(
"shouldProcessFill",
"Fill Color",
false
)
var strokeCheckbox = new Form.Field.Checkbox(
"shouldProcessStroke",
"Stroke Color",
false
)
var textCheckbox = new Form.Field.Checkbox(
"shouldProcessText",
"Text Color",
false
)
var inputForm = new Form()
inputForm.addField(targetColorField)
inputForm.addField(replaceColorField)
inputForm.addField(fillCheckbox)
inputForm.addField(strokeCheckbox)
inputForm.addField(textCheckbox)
var formPrompt = "Enter 6-character HEX colors (no #):"
var buttonTitle = "Continue"
var formPromise = inputForm.show(formPrompt,buttonTitle)
inputForm.validate = function(formObject){
var processFill = formObject.values['shouldProcessFill']
var processStroke = formObject.values['shouldProcessStroke']
var processText = formObject.values['shouldProcessText']
var values = [processFill, processStroke, processText]
var targetColor = formObject.values['targetColor']
if(!targetColor){return false}
if (/^[a-f0-9]+$/i.test(targetColor)){
var targetStatus = (targetColor.length === 6) ? true:false
} else {var targetStatus = false}
var replaceColor = formObject.values['replaceColor']
if (!replaceColor){return false}
if (/^[a-f0-9]+$/i.test(replaceColor)){
var replacetStatus = (replaceColor.length === 6) ? true:false
} else {var replacetStatus = false}
return (values.includes(true) && targetStatus === true && replacetStatus === true) ? true:false
}
formPromise.then(function(formObject){
try {
console.clear()
var shouldChangeFill = formObject.values['shouldProcessFill']
var shouldChangeStroke = formObject.values['shouldProcessStroke']
var shouldChangeText = formObject.values['shouldProcessText']
var targetHEX = formObject.values['targetColor']
console.log("targetHEX",targetHEX)
var targetColor = hexToRGBColorObject(targetHEX)
var replaceHEX = formObject.values['replaceColor']
console.log("replaceHEX",replaceHEX)
var replacementColor = hexToRGBColorObject(replaceHEX)
console.log("fill:" + shouldChangeFill,"stroke:" + shouldChangeStroke,"text:" + shouldChangeText)
// use selected graphics or if none, all graphics
var targetGraphics = selection.graphics
if (targetGraphics.length === 0){
var cnvs = selection.canvas
var targetGraphics = cnvs.graphics
}
changeCount = 0
processItems(targetGraphics, shouldChangeFill, shouldChangeStroke, shouldChangeText, targetHEX, replacementColor)
console.log("// Script to locate an item by ID:")
console.log("cnvs = document.windows[0].selection.canvas")
console.log("graphic = cnvs.graphicWithId(*idNumber*)")
console.log("document.windows[0].selection.view.select([graphic],false)")
var message = String(changeCount) + " items were altered."
new Alert("COMPLETED",message).show()
}
catch(err){console.error(err)}
})
formPromise.catch(function(err){
console.error("form cancelled", err.message)
})
});
action.validate = function(selection, sender){
// validation code
return (selection.canvas.graphics.length > 0)
};
return action;
})();
Opacity
The opacity of a graphic is controlled by the alpha value of its fill or stroke color. For example, this script will generate an instance of the Color class whose color is red with 50% transparency:
Color with 50% Opacity
Color.RGB(1, 0, 0, 0.5)
//--> [object Color] {alpha: 0.5, blue: 0, brightness: 1, colorSpace: [object ColorSpace: RGB], green: 0, hue: 1, red: 1, saturation: 1, white: 0.3}
Set Graphic Opacity
Here is an Omni Automation plug-in for OmniGraffle that will change the opacity of the selected items (shapes, lines, and groups) to the percentage value provided by the plug-in user:
Set Opacity of Selected Items
/*{
"type": "action",
"targets": ["omnigraffle"],
"author": "Otto Automator",
"identifier": "com.omni-automation.og.set-opacity-of-selection",
"version": "1.0",
"description": "This action will set the opacity of the selected graphics to the indicated percentage.",
"label": "Set Opacity",
"shortLabel": "Opacity"
}*/
(() => {
function processStroke(item,opacity){
var c = item.strokeColor
var newColor = Color.RGB(c.red, c.green, c.blue, opacity)
item.strokeColor = newColor
}
function processFill(item,opacity){
var c = item.fillColor
var newColor = Color.RGB(c.red, c.green, c.blue, opacity)
item.fillColor = newColor
}
function processGroup(group,opacity,shouldIncludeStroke){
group.graphics.forEach(item => {
if(item instanceof Shape){
processFill(item,opacity)
if (shouldIncludeStroke){processStroke(item,opacity)}
}
if (item instanceof Line){
processStroke(item,opacity)
}
if (item instanceof Group){
processGroup(item,opacity,shouldIncludeStroke)
}
})
}
var action = new PlugIn.Action(function(selection, sender){
// action code
// selection options: canvas, document, graphics, lines, solids, view
var textInputField = new Form.Field.String(
"textInput",
null,
"50"
)
var checkSwitchField = new Form.Field.Checkbox(
"shouldIncludeStroke",
"Apply opacity setting to shape’s stroke",
true
)
var inputForm = new Form()
inputForm.addField(textInputField)
inputForm.addField(checkSwitchField)
var formPrompt = "Enter an opacity value (0-100):"
var buttonTitle = "Continue"
var formPromise = inputForm.show(formPrompt,buttonTitle)
inputForm.validate = function(formObject){
inputText = formObject.values['textInput']
if (!inputText) {return false}
var isnum = /^[0-9]+$/i.test(inputText)
if (isnum){
var opacityValue = Number(inputText)
return ((opacityValue >= 0 && opacityValue <= 100)? true:false)
}
return false
}
formPromise.then(function(formObject){
try {
var textValue = formObject.values['textInput']
console.log('textValue: ',textValue)
var shouldIncludeStroke = formObject.values['shouldIncludeStroke']
var opacityValue = Number(inputText) * .01
selection.graphics.forEach(item => {
if (item instanceof Shape){
processFill(item,opacityValue)
if (shouldIncludeStroke){processStroke(item,opacityValue)}
}
if (item instanceof Line){
processStroke(item,opacityValue)
}
if (item instanceof Group){
processGroup(item,opacityValue,shouldIncludeStroke)
}
})
}
catch(err){
console.error(err.message)
new Alert("ERROR",err.message).show()
}
})
formPromise.catch(function(err){
console.error("form cancelled", err.message)
})
});
action.validate = function(selection, sender){
// validation code
// selection options: canvas, document, graphics, lines, solids, view
return (selection.graphics.length > 0)
};
return action;
})();