Shape Burst
Got a feeling this is one of the steps of bevel. Well I like being able to do every step by hand so made this.
It um....creates a gradient that matches the shape...yeah, that sounds about right
Notes
The source came from the extremely cool.....
http://www.jhlabs.com/ip/filters/index.html
...Ive lost count how many times Ive converted bits of that to other languages. Java is one of the nicer languages to convert. This conversion was a snap and so far doesn't even look like I'm going to have to worry about type conversions (the biggest prob converting any other language to JS). I love converting this stuff because there's heaps to play with and even better there's an app with all those filters that you can use to compare with your own codes results. Please note tho, that if your going to convert that stuff you might want to check it first. Recently I converted his error diffusion stuff only to find it had errors, big ones, but I fixed them and sent them to him....wish the polar coordinate stuff worked like I thought it should, REALLY want that function.
Blur and Restore Alpha
http://www.rw-designer.com/forum/2682
This script is useful after using this one on a shape that was drawn on a transparent background. You can use it to blur out the jaggies while keeping the anti-aliasing on the edges of the shape.
Speed
All the scripts are slow, but this one is nuts. On a 256x256 fine, 512x512 that was a bit, 1024x768 God Knows! it was taking so long (minutes and minutes and minutes) I stopped it. But then I havent tested many of these scripts above 512x512.
Code
Configuration
var options = ["Linear", "Circle Up", "Circle Down", "Smooth"];
Configuration.Add1ofNPicker("type", "Type", "Choose the stepping type", options, 3);
Configuration.AddCheckBox("alpha", "Use Alpha", "", true);
Configuration.AddCheckBox("invert", "Invert", "", false);
Configuration.AddCheckBox("merge", "Merge", "", false);
Execution
var image = Document.RasterImage;
var w = image.sizeX;
var width = w;
var h = image.sizeY;
var height = h;
var map = [];
var LINEAR = 0;
var CIRCLE_UP = 1;
var CIRCLE_DOWN = 2;
var SMOOTH = 3;
var factor = 1.0;
// protected Colormap colormap;
var colormap = false;
var useAlpha = Configuration.alpha;
var invert = Configuration.invert;
var merge = Configuration.merge;
var type = Configuration.type;
var one = 41;
var sqrt2 = /*(int)*/ (41 * Math.sqrt(2));
var sqrt5 = /*(int)*/ (41 * Math.sqrt(5));
var ImageMath = {
clamp: function(x, a, b) {
return (x < a) ? a : (x > b) ? b : x;
},
smoothStep: function(a, b, x) {
if (x < a)
return 0;
if (x >= b)
return 1;
x = (x - a) / (b - a);
return x * x * (3 - 2 * x);
},
circleUp: function(x) {
x = 1 - x;
return /*(float)*/ Math.sqrt(1 - x * x);
},
circleDown: function(x) {
return 1.0 - /*(float)*/ Math.sqrt(1 - x * x);
}
};
// Do ya thing.....
makeMap(image, map, width, height);
var max = distanceMap(map, width, height);
applyMap(map, image, width, height, max);
function makeMap(pixels, map, width, height) {
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var offset = x + y * width;
var b = useAlpha ? pixels.getPixelAlpha(x, y, 0, 0) : pixels.getPixelL(x, y, 0, 0);
// map[offset] = b * one;
map[offset] = b * one / 10; // This may be needed to converted to an int
}
}
}
function distanceMap(map, width, height) {
var xmax = width - 3;
var ymax = height - 3;
var max = 0;
var v, x, y, offset;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
offset = x + y * width;
if (map[offset] > 0) {
if (x < 2 || x > xmax || y < 2 || y > ymax)
v = setEdgeValue(x, y, map, width, offset, xmax, ymax);
else
v = setValue(map, width, offset);
if (v > max)
max = v;
}
}
}
for (y = height - 1; y >= 0; y--) {
for (x = width - 1; x >= 0; x--) {
offset = x + y * width;
if (map[offset] > 0) {
if (x < 2 || x > xmax || y < 2 || y > ymax)
v = setEdgeValue(x, y, map, width, offset, xmax, ymax);
else
v = setValue(map, width, offset);
if (v > max)
max = v;
}
}
}
return max;
}
function applyMap(map, pixels, width, height, max) {
var x, y, offset, n, v, sa, sr, sg, sb, c, transp, col, a, r, g, b;
if (max === 0)
max = 1;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
offset = x + y * width;
m = map[offset];
v = 0;
sa = 0, sr = 0, sg = 0, sb = 0;
if (m === 0) {
// default color
sa = sr = sg = sb = 0;
sa = pixels.getPixelAlpha(x, y, 0, 0);
} else {
// get V from map
v = ImageMath.clamp(factor * m / max, 0, 1);
switch (type) {
case CIRCLE_UP:
v = (ImageMath.circleUp(v));
break;
case CIRCLE_DOWN:
v = (ImageMath.circleDown(v));
break;
case SMOOTH:
v = (ImageMath.smoothStep(0, 1, v));
break;
}
if (colormap === false) {
sr = sg = sb = /*(int)*/ (v * 255);
} else {
c = (colormap.getColor(v));
sr = (c >> 16) & 0xFF;
sg = (c >> 8) & 0xFF;
sb = (c) & 0xFF;
}
sa = useAlpha ? pixels.getPixelAlpha(x, y, 0, 0) : pixels.getPixelL(x, y, 0, 0);
// invert v if necessary
if (invert) {
sr = 255 - sr;
sg = 255 - sg;
sb = 255 - sb;
}
}
// write results
if (merge) {
// merge with source
transp = 255;
//col = pixels[offset];
col = pixels.getPixel(x, y, 0, 0);
a = (col & 0xFF000000) >> 24;
r = (col & 0xFF0000) >> 16;
g = (col & 0xFF00) >> 8;
b = (col & 0xFF);
r = /*(int)*/ ((sr * r / transp));
g = /*(int)*/ ((sg * g / transp));
b = /*(int)*/ ((sb * b / transp));
// clip colors
if (r < 0)
r = 0;
if (r > 255)
r = 255;
if (g < 0)
g = 0;
if (g > 255)
g = 255;
if (b < 0)
b = 0;
if (b > 255)
b = 255;
//pixels[offset] = (a << 24) | (r << 16) | (g << 8) | b;
pixels.setPixel(x, y, 0, 0, (a << 24) | (r << 16) | (g << 8) | b);
} else {
// write gray shades
//pixels[offset] = (sa << 24) | (sr << 16) | (sg << 8) | sb;
pixels.setPixel(x, y, 0, 0, (sa << 24) | (sr << 16) | (sg << 8) | sb);
}
}
}
}
function setEdgeValue(x, y, map, width, offset, xmax, ymax) {
var min, v;
var r1, r2, r3, r4, r5;
r1 = offset - width - width - 2;
r2 = r1 + width;
r3 = r2 + width;
r4 = r3 + width;
r5 = r4 + width;
if (y === 0 || x === 0 || y == ymax + 2 || x == xmax + 2)
return map[offset] = one;
v = map[r2 + 2] + one;
min = v;
v = map[r3 + 1] + one;
if (v < min)
min = v;
v = map[r3 + 3] + one;
if (v < min)
min = v;
v = map[r4 + 2] + one;
if (v < min)
min = v;
v = map[r2 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r2 + 3] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 3] + sqrt2;
if (v < min)
min = v;
if (y == 1 || x == 1 || y == ymax + 1 || x == xmax + 1)
return map[offset] = min;
v = map[r1 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r1 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r2 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r4 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r4] + sqrt5;
if (v < min)
min = v;
v = map[r2] + sqrt5;
if (v < min)
min = v;
return map[offset] = min;
}
function setValue(map, width, offset) {
var min, v;
var r1, r2, r3, r4, r5;
r1 = offset - width - width - 2;
r2 = r1 + width;
r3 = r2 + width;
r4 = r3 + width;
r5 = r4 + width;
v = map[r2 + 2] + one;
min = v;
v = map[r3 + 1] + one;
if (v < min)
min = v;
v = map[r3 + 3] + one;
if (v < min)
min = v;
v = map[r4 + 2] + one;
if (v < min)
min = v;
v = map[r2 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r2 + 3] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 3] + sqrt2;
if (v < min)
min = v;
v = map[r1 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r1 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r2 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r4 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r4] + sqrt5;
if (v < min)
min = v;
v = map[r2] + sqrt5;
if (v < min)
min = v;
return map[offset] = min;
}
License
/*
Copyright 2006 Jerry Huxtable
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// original code Copyright (C) Jerry Huxtable 1998
//
// customizations (C) Michele Puccini 19/12/2001
// - conversion from float to int math
// - complete rewrite of applyMap()
// - implemented merge to dest function
Unfortunately I cant Modify old posts?...so heres an update.
As requested it now allows you to pick the colours used for the gradient.
Code
Configuration
var options = ["Linear", "Circle Up", "Circle Down", "Smooth"];
Configuration.Add1ofNPicker("type", "Type", "Choose the stepping type", options, 3);
Configuration.AddCheckBox("alpha", "Use Alpha", "", true);
Configuration.AddCheckBox("invert", "Invert", "", false);
Configuration.AddCheckBox("merge", "Merge", "", false);
Configuration.AddColorButton("startColour", "Starting Colour", "", 0x000000);
Configuration.AddColorButton("endColour", "End Colour", "", 0xffffff);
Execution
var image = Document.RasterImage;
var w = image.sizeX;
var width = w;
var h = image.sizeY;
var height = h;
var map = [];
var LINEAR = 0;
var CIRCLE_UP = 1;
var CIRCLE_DOWN = 2;
var SMOOTH = 3;
var factor = 1.0;
var gradient=[];
var gradientSize=512;
var colormap = true;
var useAlpha = Configuration.alpha;
var invert = Configuration.invert;
var merge = Configuration.merge;
var type = Configuration.type;
var one = 41;
var sqrt2 = /*(int)*/ (41 * Math.sqrt(2));
var sqrt5 = /*(int)*/ (41 * Math.sqrt(5));
var lerp = function( a, b, percent ) {
return a + percent * ( b - a );
};
var ImageMath = {
clamp: function(x, a, b) {
return (x < a) ? a : (x > b) ? b : x;
},
smoothStep: function(a, b, x) {
if (x < a)
return 0;
if (x >= b)
return 1;
x = (x - a) / (b - a);
return x * x * (3 - 2 * x);
},
circleUp: function(x) {
x = 1 - x;
return /*(float)*/ Math.sqrt(1 - x * x);
},
circleDown: function(x) {
return 1.0 - /*(float)*/ Math.sqrt(1 - x * x);
}
};
// Do ya thing.....
makeColourMap(Configuration.startColour,Configuration.endColour);
makeMap(image, map, width, height);
var max = distanceMap(map, width, height);
applyMap(map, image, width, height, max);
function makeColourMap(start,end){
var sb = (start >> 16) & 0xFF;
var sg = (start >> 8) & 0xFF;
var sr = (start) & 0xFF;
var db = (end >> 16) & 0xFF;
var dg = (end >> 8) & 0xFF;
var dr = (end) & 0xFF;
var r,g,b,c,pos;
for (var i=0,end=gradientSize;i<end;i++){
pos=i/(gradientSize-1);
r=lerp(sr,dr,pos);
g=lerp(sg,dg,pos);
b=lerp(sb,db,pos);
c=(r << 16) | (g << 8)| b;
gradient.push(c);
}
}
function makeMap(pixels, map, width, height) {
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var offset = x + y * width;
var b = useAlpha ? pixels.getPixelAlpha(x, y, 0, 0) : pixels.getPixelL(x, y, 0, 0);
// map[offset] = b * one;
map[offset] = b * one / 10; // This may be needed to converted to an int
}
}
}
function distanceMap(map, width, height) {
var xmax = width - 3;
var ymax = height - 3;
var max = 0;
var v, x, y, offset;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
offset = x + y * width;
if (map[offset] > 0) {
if (x < 2 || x > xmax || y < 2 || y > ymax)
v = setEdgeValue(x, y, map, width, offset, xmax, ymax);
else
v = setValue(map, width, offset);
if (v > max)
max = v;
}
}
}
for (y = height - 1; y >= 0; y--) {
for (x = width - 1; x >= 0; x--) {
offset = x + y * width;
if (map[offset] > 0) {
if (x < 2 || x > xmax || y < 2 || y > ymax)
v = setEdgeValue(x, y, map, width, offset, xmax, ymax);
else
v = setValue(map, width, offset);
if (v > max)
max = v;
}
}
}
return max;
}
function applyMap(map, pixels, width, height, max) {
var x, y, offset, n, v, sa, sr, sg, sb, c, transp, col, a, r, g, b;
if (max === 0)
max = 1;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
offset = x + y * width;
m = map[offset];
v = 0;
sa = 0, sr = 0, sg = 0, sb = 0;
if (m === 0) {
// default color
sa = sr = sg = sb = 0;
sa = pixels.getPixelAlpha(x, y, 0, 0);
} else {
// get V from map
v = ImageMath.clamp(factor * m / max, 0, 1);
switch (type) {
case CIRCLE_UP:
v = (ImageMath.circleUp(v));
break;
case CIRCLE_DOWN:
v = (ImageMath.circleDown(v));
break;
case SMOOTH:
v = (ImageMath.smoothStep(0, 1, v));
break;
}
if (colormap === false) {
sr = sg = sb = /*(int)*/ (v * 255);
} else {
c = (gradient[Math.round(v*gradientSize-1)]);
sr = (c >> 16) & 0xFF;
sg = (c >> 8) & 0xFF;
sb = (c) & 0xFF;
}
sa = useAlpha ? pixels.getPixelAlpha(x, y, 0, 0) : pixels.getPixelL(x, y, 0, 0);
// invert v if necessary
if (invert) {
sr = 255 - sr;
sg = 255 - sg;
sb = 255 - sb;
}
}
// write results
if (merge) {
// merge with source
transp = 255;
//col = pixels[offset];
col = pixels.getPixel(x, y, 0, 0);
a = (col & 0xFF000000) >> 24;
r = (col & 0xFF0000) >> 16;
g = (col & 0xFF00) >> 8;
b = (col & 0xFF);
r = /*(int)*/ ((sr * r / transp));
g = /*(int)*/ ((sg * g / transp));
b = /*(int)*/ ((sb * b / transp));
// clip colors
if (r < 0)
r = 0;
if (r > 255)
r = 255;
if (g < 0)
g = 0;
if (g > 255)
g = 255;
if (b < 0)
b = 0;
if (b > 255)
b = 255;
//pixels[offset] = (a << 24) | (r << 16) | (g << 8) | b;
pixels.setPixel(x, y, 0, 0, (a << 24) | (r << 16) | (g << 8) | b);
} else {
// write gray shades
//pixels[offset] = (sa << 24) | (sr << 16) | (sg << 8) | sb;
pixels.setPixel(x, y, 0, 0, (sa << 24) | (sr << 16) | (sg << 8) | sb);
}
}
}
}
function setEdgeValue(x, y, map, width, offset, xmax, ymax) {
var min, v;
var r1, r2, r3, r4, r5;
r1 = offset - width - width - 2;
r2 = r1 + width;
r3 = r2 + width;
r4 = r3 + width;
r5 = r4 + width;
if (y === 0 || x === 0 || y == ymax + 2 || x == xmax + 2)
return map[offset] = one;
v = map[r2 + 2] + one;
min = v;
v = map[r3 + 1] + one;
if (v < min)
min = v;
v = map[r3 + 3] + one;
if (v < min)
min = v;
v = map[r4 + 2] + one;
if (v < min)
min = v;
v = map[r2 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r2 + 3] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 3] + sqrt2;
if (v < min)
min = v;
if (y == 1 || x == 1 || y == ymax + 1 || x == xmax + 1)
return map[offset] = min;
v = map[r1 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r1 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r2 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r4 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r4] + sqrt5;
if (v < min)
min = v;
v = map[r2] + sqrt5;
if (v < min)
min = v;
return map[offset] = min;
}
function setValue(map, width, offset) {
var min, v;
var r1, r2, r3, r4, r5;
r1 = offset - width - width - 2;
r2 = r1 + width;
r3 = r2 + width;
r4 = r3 + width;
r5 = r4 + width;
v = map[r2 + 2] + one;
min = v;
v = map[r3 + 1] + one;
if (v < min)
min = v;
v = map[r3 + 3] + one;
if (v < min)
min = v;
v = map[r4 + 2] + one;
if (v < min)
min = v;
v = map[r2 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r2 + 3] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 1] + sqrt2;
if (v < min)
min = v;
v = map[r4 + 3] + sqrt2;
if (v < min)
min = v;
v = map[r1 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r1 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r2 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r4 + 4] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 3] + sqrt5;
if (v < min)
min = v;
v = map[r5 + 1] + sqrt5;
if (v < min)
min = v;
v = map[r4] + sqrt5;
if (v < min)
min = v;
v = map[r2] + sqrt5;
if (v < min)
min = v;
return map[offset] = min;
}