Histogram passed and drawn into a Layer. Done!
Hi, I have made an exercise that can be usefull to someone.
On a active image, it builds and draws the histograms on several layers.
This works only on RGB images and if they have more than 8bits/channel, it will reduce to 8bit/channel before proced.
I used this on windows 10 and CC(2017)
Enjoy or complete and develop it as you want.
This next code will build 4 layers
1 - the 3 rgb channels coloured histogram
2 - the Max(
3 - the 8bit Lightness channel Lab histogram (the image will be reverted again to RGB afterwards)
4 - 8bit Luminosity RGB histogram
addHistogram(true); // this draws a layer with a coloured 8bit RGB histogram
addHistogram(false, false, true); // this draws the Max(
, , ) Luminosity RGB histogram (gets the max value of each channel) addHistogram(false, true); // this draws a layer with 8bit Lightness channel Lab histogram
addHistogram(false, false); // this draws a layer with 8bit Luminosity RGB histogram
/////////////////////////////// HISTOGRAM IN LAYER ///////////////////////////////////
function addHistogram(RGB, Lab, MaxRGB) {
///////////////////////////////////////////////// createProgressWindow
var createProgressWindow = function(title, message, hasCancelButton) {
var win;
if (title == null) title = "Work in progress";
if (message == null) message = "Please wait...";
if (hasCancelButton == null) hasCancelButton = false;
win = new Window("palette", "" + title, undefined);
win.bar = win.add("progressbar", {x: 20, y: 12, width: 300, height: 20 }, 0, 100);
win.stMessage = win.add("statictext", { x: 10, y: 36, width: 320, height: 20 }, "" + message);
win.stMessage.justify = 'center';
if (hasCancelButton) {
win.cancelButton = win.add('button', undefined, 'Cancel');
win.cancelButton.onClick = function() {
win.close();
throw new Error('User canceled the pre-processing!');
};
}
this.reset = function(message) {
win.bar.value = 0;
win.stMessage.text = message;
return win.update();
};
this.updateProgress = function(perc, message) {
if (perc != null) win.bar.value = perc;
if (message != null) win.stMessage.text = message;
return win.update();
};
this.close = function() {
return win.close();
};
win.center(win.parent);
return win.show();
};
//
// the other layer histograms, if exist, should be invisible so the reading is only on the pixels of the image itself
if (getLayer("RGB histogram")) activeDocument.artLayers.getByName ("RGB histogram").visible = false;
if (getLayer("Lightness Lab histogram")) activeDocument.artLayers.getByName ("Lightness Lab histogram").visible = false;
if (getLayer("Luminosity RGB")) activeDocument.artLayers.getByName ("Luminosity RGB").visible = false;
if (getLayer("Luminosity Max
")) activeDocument.artLayers.getByName ("Luminosity Max ").visible = false; //
var layerName = (RGB) ? "RGB histogram" : ((Lab) ? "Lightness Lab histogram" : ((MaxRGB) ? "Luminosity Max
" : "Luminosity RGB")); //
if (!getLayer(layerName)) {
// it works only on RGB images
if (activeDocument.mode == DocumentMode.RGB) {
// if the image is 16bit/channel or more it sets 8bits/channel before read the histogram
if (!activeDocument.bitsPerChannel == BitsPerChannelType.EIGHT) activeDocument.bitsPerChannel = BitsPerChannelType.EIGHT;
$.writeln(layerName);
var wasHereLayer = activeDocument.activeLayer;
var unitsAntes = app.preferences.rulerUnits;
var foregroundPreviousColor = app.foregroundColor;
app.preferences.rulerUnits = Units.PIXELS; // importante
activeDocument.quickMaskMode = false;
activeDocument.selection.deselect();
//
// read histogram:
var hL = activeDocument.histogram;
var hR = activeDocument.channels["Red"].histogram;
var hG = activeDocument.channels["Green"].histogram;
var hB = activeDocument.channels["Blue"].histogram;
// if you want the Luminosity of Lab, export it to Lab, read it, and revert it to RGB
if (Lab) {
activeDocument.changeMode (ChangeMode.LAB);
// read Lightness channel histogram of Lab
var hL = activeDocument.channels["Lightness"].histogram;
// revert to RGB
activeDocument.changeMode (ChangeMode.RGB);
} else {
// read Luminosity composite channel histogram of RGB
var hL = activeDocument.histogram;
}
//
var ww = activeDocument.width.as('px');
var hh = activeDocument.height.as('px');
var totalPixels = ww*hh;
var totalPixels1Col = totalPixels/256;
//
var pBar = new createProgressWindow("Histogram building...", "Please wait", false);
//
activeDocument.artLayers.add();
activeDocument.activeLayer.name = layerName;
activeDocument.activeLayer.move( activeDocument, ElementPlacement.PLACEATBEGINNING );
activeDocument.activeLayer.blendMode = BlendMode.NORMAL; // blending mode "normal"
activeDocument.activeLayer.opacity = 60; // opacity 60%
//
var hhGraph = 60;
var hY = 400; // base y of graph
var hX = 100; // base x of graph
// base transparent
app.foregroundColor.rgb.red = 0;
app.foregroundColor.rgb.green = 0;
app.foregroundColor.rgb.blue = 0;
//
drawSelectionScreen (hX-2, hY+2, 258+hX, hY-322);
// fill (filltype [, mode] [, opacity] [, preserveTransparency]) // filltype: SolidColor | mode: ColorBlendMode | opacity: [1..100]
app.activeDocument.selection.fill(app.foregroundColor, ColorBlendMode.SCREEN, 40, false);
activeDocument.selection.deselect();
//
var myHist = [];
//
if (RGB) {
for (var a in activeDocument.componentChannels) {
// criar as 3 cores R, G e B e o graph da cada uma
(a==0) ? app.foregroundColor.rgb.red = 255 : app.foregroundColor.rgb.red = 0;
(a==1) ? app.foregroundColor.rgb.green = 255 : app.foregroundColor.rgb.green = 0;
(a==2) ? app.foregroundColor.rgb.blue = 255 : app.foregroundColor.rgb.blue = 0;
//
if (a==0) myHist = hR;
if (a==1) myHist = hG;
if (a==2) myHist = hB;
//
for ( i = 0; i <= 255; i++ ) {
var col = i+hX;
var YYY = Math.min(Math.floor(myHist*hhGraph/totalPixels1Col), 320);
drawSelectionScreen (col, hY, col+1, hY-YYY);
//
var percent = Math.floor(((i+1)+(a*256))*100/768);
pBar.updateProgress (percent, activeDocument.componentChannels.name.toUpperCase() + " Channel " + percent+ " % completed");
}
// fill (filltype [, mode] [, opacity] [, preserveTransparency]) // filltype: SolidColor | mode: ColorBlendMode | opacity: [1..100]
app.activeDocument.selection.fill(app.foregroundColor, ColorBlendMode.SCREEN, 100, false);
activeDocument.selection.deselect();
}
} else {
app.foregroundColor.rgb.red = 255;
app.foregroundColor.rgb.green = 255;
app.foregroundColor.rgb.blue = 255;
myHist = hL;
for ( i = 0; i <= 255; i++ ) {
var col = i+hX;
if (MaxRGB) {
var YYY = Math.min(Math.floor(Math.max(hR, hG, hB)*hhGraph/totalPixels1Col), 320);
} else {
var YYY = Math.min(Math.floor(myHist*hhGraph/totalPixels1Col), 320);
}
drawSelectionScreen (col, hY, col+1, hY-YYY);
//
var percent = Math.floor((i+1)*100/256);
pBar.updateProgress (percent, "Luminosity Channel " + percent+ " % completed");
}
// fill (filltype [, mode] [, opacity] [, preserveTransparency]) // filltype: SolidColor | mode: ColorBlendMode | opacity: [1..100]
app.activeDocument.selection.fill(app.foregroundColor, ColorBlendMode.SCREEN, 100, false);
activeDocument.selection.deselect();
}
pBar.close();
// activeDocument.activeLayer = wasHereLayer;
app.preferences.rulerUnits = unitsAntes;
app.foregroundColor = foregroundPreviousColor;
$.gc();
} else {
alert("Must be an RGB image");
}
} else {
alert("Already has created this '" + layerName + "' layer!");
return;
}
function drawSelectionScreen(x1, y1, x2, y2) {
$.level = 0;
try {
// SelectionType.SELECTEDAREA | DIMINISH | EXTEND | INTERSECT | REPLACE
activeDocument.selection.select([[ x1, y1], [x2, y1], [x2, y2], [x1,y2]], SelectionType.EXTEND, 0, false);
} catch(e) {}
$.level = 1;
}
function drawLineScreen(x1, y1, x2, y2, width, transparency) {
$.level = 0;
try {
var desc = new ActionDescriptor();
var lineDesc = new ActionDescriptor();
var startDesc = new ActionDescriptor();
startDesc.putUnitDouble( charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x1 );
startDesc.putUnitDouble( charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y1 );
lineDesc.putObject( charIDToTypeID('Strt'), charIDToTypeID('Pnt '), startDesc );
var endDesc = new ActionDescriptor();
endDesc.putUnitDouble( charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x2 );
endDesc.putUnitDouble( charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y2 );
lineDesc.putObject( charIDToTypeID('End '), charIDToTypeID('Pnt '), endDesc );
lineDesc.putUnitDouble( charIDToTypeID('Wdth'), charIDToTypeID('#Pxl'), width ); //
desc.putObject( charIDToTypeID('Shp '), charIDToTypeID('Ln '), lineDesc );
desc.putEnumerated( charIDToTypeID( "Md " ), charIDToTypeID( "BlnM" ), charIDToTypeID( "Scrn" ) ); // mode: Screen
desc.putUnitDouble( charIDToTypeID( "Opct" ), charIDToTypeID( "#Prc" ), transparency ); // [0-100] transparency
desc.putBoolean( charIDToTypeID('AntA'), false ); // important antialias should be false
executeAction( charIDToTypeID('Draw'), desc, DialogModes.NO );
} catch(e) {}
$.level = 1;
}
//////////////////////////////////
function getLayer(layername) {
var result = false;
for (var a=0; a<activeDocument.artLayers.length ; a++) {
if (String(activeDocument.artLayers.name) == layername) {
result = true;
break;
}
}
return result;
}
}