Adobe Photoshop Scripting - How to Select Bounding Box Around Current Selection? - photoshop

Does anyone know whether it's possible, in Photoshop extend script, to convert an irregular selection (e.g. magic wand tool selection) into a rectangular selection encompassing the top, left, bottom and right bounds of the selection?

Here it is, I have documented the code so you can modify it later if you need. Also, check page 166 and following of Photoshop's JS reference manual, you may read more about selections - you can set feather, extend/intersect/etc. the selection if you need to.
Made for CS6, should work with latter.
#target photoshop
if (documents.length == 0) {
alert("nothing opened");
} else {
// start
//setup
var file = app.activeDocument;
var selec = file.selection;
//run
var bnds = selec.bounds; // get the bounds of current selection
var // save the particular pixel values
xLeft = bnds[0],
yTop = bnds[1],
xRight = bnds[2],
yBottom = bnds[3];
var newRect = [ [xLeft,yTop], [xLeft,yBottom], [xRight,yBottom], [xRight,yTop] ]; // set coords for selection, counter-clockwise
selec.deselect;
selec.select(newRect);
// end
}

Related

Script measurement tool in Photoshop to measure distance between two points

Can the measurement tool be scripted to measure a custom distance? Not an existing measurement, that is.
I would have thought it possible, but Abobe's documentation are sketchy
and there's not much info when it comes down to scripting the measurement tool. Or ruler, as it use to be known. More specifically a lack of examples using the ruler in a script.
Ideally I'd like to:
Script a measurement from x1,y1 to x2,y2
Determine its length, (preferably from a variable, not from a text file - see below)
Clear the ruler tool (so no ruler line appears)
Delete any measurements (so there are no recordings in the ruler window)
That's basic trig, right? But if you can't set the initial ruler then this is all for nothing.
The only thing on the list I've done is the last. :(
I stumble at the first hurdle not being able to set the ruler, which I thought would be app.activeDocument.recordMeasurements(); Only it gets returned as undefined or Unable to record measurements for selection.
As minimal working, this is pretty minimal:
// Let's stick to pixels as the units to make things easier.
// Switch off any dialog boxes
displayDialogs = DialogModes.ERROR; // OFF
// Get and set the units to pixels
var currentUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// delete existing measurements
app.measurementLog.deleteMeasurements(); // THIS WORKS!!
// call the source document
var srcDoc = app.activeDocument;
// Set array to record measurements
var rulerArr = [];
// Set ruler measurement
measure_it(x1,y1,x2,y2); // this a fictional function
// not even the ScriptListener records the ruler tool in a useful form
// var d = app.activeDocument.recordMeasurements(MeasurementSource.MEASURESELECTION, rulerArr); // Unable to record measurements for selection
// var d = app.activeDocument.recordMeasurements(MeasurementSource.MEASURESELECTION); // Unable to record measurements for selection
var d = app.activeDocument.recordMeasurements(); // undefined
var ruler = app.measurementLog; // Is an object!
alert(ruler.length); // undefined
// There's an option to export to a text file
// Is that the only way to get the measurements?
// Can't this be don't internally?
var f = "D:\\temp\\ruler.txt";
ruler.exportMeasurements(f, MeasurementRange.ACTIVEMEASUREMENTS)
alert(app.measurementLog);
// put the units back to how it was
app.preferences.rulerUnits = currentUnits;
// Set Display Dialogs back to normal
displayDialogs = DialogModes.ALL; // NORMAL

how to add arcgis button in a windows form

I am new in ArcGis. I came across a requirement that I need a command on the ArcGis Toolbar. On click the command, a Windows Form will open and there one region selector button is there. upon clicking on the button, the current Form UI must be minimized and the user will be allowed to draw a polygon. Can you please help on how to do that. Here is the code. I took normal windows button and wrote the below code in the click event.
_application = ((IApplication)_hookHelper.Hook);
IMxDocument pMxDoc = (IMxDocument)_application.Document;
IMap pMap = (IMap)pMxDoc.FocusMap;
IActiveView pActiveView = (IActiveView)pMap;
if (pActiveView == null)
{
return;
}
//// Changing the state of the Window.
if (this.WindowState == FormWindowState.Normal || this.WindowState == FormWindowState.Maximized)
{
this.WindowState = FormWindowState.Minimized;
// this.Hide();
}
ESRI.ArcGIS.Display.IScreenDisplay screenDisplay = pActiveView.ScreenDisplay;
// Constant
screenDisplay.StartDrawing(screenDisplay.hDC, (System.Int16)ESRI.ArcGIS.Display.esriScreenCache.esriNoScreenCache); // Explicit Cast
ESRI.ArcGIS.Display.IRgbColor rgbColor = new ESRI.ArcGIS.Display.RgbColorClass();
rgbColor.Blue = 111;
ESRI.ArcGIS.Display.IColor color = rgbColor; // Implicit Cast
ESRI.ArcGIS.Display.ISimpleFillSymbol simpleFillSymbol = new ESRI.ArcGIS.Display.SimpleFillSymbolClass();
simpleFillSymbol.Color = color;
ESRI.ArcGIS.Display.ISymbol symbol = simpleFillSymbol as ESRI.ArcGIS.Display.ISymbol; // Dynamic Cast
ESRI.ArcGIS.Display.IRubberBand rubberBand = new ESRI.ArcGIS.Display.RubberRectangularPolygonClass();
// ESRI.ArcGIS.Display.IRubberBand rubberBand = new ESRI.ArcGIS.Display.RubberPolygonClass();
ESRI.ArcGIS.Geometry.IGeometry geometry = rubberBand.TrackNew(screenDisplay, symbol);
screenDisplay.SetSymbol(symbol);
screenDisplay.DrawPolygon(geometry);
screenDisplay.FinishDrawing();
I am also not getting any mouse event and the UI is not minimized while starting drawing the polygon. Can anyone please help.
Have we check the white paper for ArcGIS runtime SDK for .Net?
http://resources.arcgis.com/en/help/runtime-wpf/concepts/index.html#/Essential_vocabulary/01700000004z000000/

How to programmatically add an active graphics layer to a map?

I'm writing a WPF applicating, in C#, using ArcObjects.
I have an ESRI.ArcGIS.Controls.AxMapControl on my form, and I'm trying to draw some graphics elements on top of it.
The map I'm developing with is a customer-provided mdf of the state of Georgia.
I'm trying an example I found here: How to interact with map elements.
public void AddTextElement(IMap map, double x, double y)
{
IGraphicsContainer graphicsContainer = map as IGraphicsContainer;
IElement element = new TextElementClass();
ITextElement textElement = element as ITextElement;
//Create a point as the shape of the element.
IPoint point = new PointClass();
point.X = x;
point.Y = y;
element.Geometry = point;
textElement.Text = "Hello World";
graphicsContainer.AddElement(element, 0);
//Flag the new text to invalidate.
IActiveView activeView = map as IActiveView;
activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
It took while to figure out how to project the lat/long of Atlanta to the coordinate system of the map, but I'm pretty sure that I've got it right. The x/y values I'm passing into AddTextElement() are clearly within the Atlanta area, according to the Location data I see when I use the Identify tool on the map.
But I'm not seeing the text. Everything seems to be working correctly, but I'm not seeing the text.
I can see a number of possibilities:
The layer I'm adding the TextElement to isn't visible, or doesn't exist.
I need to apply a spatial reference system to the point I'm setting as the TextElement's geometry
The text is drawing fine, but there's something wrong with the font - it's invisibly small, or in a transparent color, etc.
Haven't a clue, which.
I was hoping there was something obvious I was missing.
===
As I've continued to play with this, since my original posting, I've discovered that the problem is the scaling - the text is showing up where it should, only unreadably small.
This is what Rich Wawrzonek had suggested.
If I set a TextSymbol class, with a specified Size, the size does apply, and I see me text larger or smaller. Unfortunately, the text still resizes as the map zooms in and out, and my trying to set ScaleText = false doesn't fix it.
My latest attempt:
public void AddTextElement(IMap map, double x, double y, string text)
{
var textElement = new TextElementClass
{
Geometry = new PointClass() { X = x, Y = y },
Text = text,
ScaleText = false,
Symbol = new TextSymbolClass {Size = 25000}
};
(map as IGraphicsContainer)?.AddElement(textElement, 0);
(map as IActiveView)?.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
I recognize that the above is organized very differently than the way is usually done with ESRI sample code. I find the way ESRI does it to be every difficult to read, but switch from one to another is pretty mechanical.
This is the same function, organized in a more traditional manner. The behavior should be identical, and I'm seeing exactly the same behavior - the text is drawn to a specified size, but scales as the map zooms.
public void AddTextElement(IMap map, double x, double y, string text)
{
IPoint point = new PointClass();
point.X = x;
point.Y = y;
ITextSymbol textSymbol = new TextSymbolClass();
textSymbol.Size = 25000;
var textElement = new TextElementClass();
textElement.Geometry = point;
textElement.Text = text;
textElement.ScaleText = false;
textElement.Symbol = textSymbol;
var iGraphicsContainer = map as IGraphicsContainer;
Debug.Assert(iGraphicsContainer != null, "iGraphicsContainer != null");
iGraphicsContainer.AddElement(textElement, 0);
var iActiveView = (map as IActiveView);
Debug.Assert(iActiveView != null, "iActiveView != null");
iActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
Any ideas as to why ScaleText is being ignored?
You are only setting the geometry and the text of the text element. You also need to set the Symbol and ScaleText properties. The ScaleText property boolean will determine whether or not it scales with the map. The Symbol property needs to be created and set via the ITextSymbol interface.
See here for an example by Esri.

Cannot stamp certain PDFs

PDF stamping works for nearly every document I have tried. However, a client scanned some pages and his computer generated a PDF document that is resistant to stamping. The embedded image files are in JBIG2 format, but I am not sure if that is important. I have debugged the PDF with Apache's pdfbox, and I can see the text is embedded. It just doesn't show up.
Here is the PDF that won't stamp: http://demo.clearvillageinc.com/plans.pdf
And my code:
static void Main(string[] args) {
string stamp = "<div style=\"color:#F00;\">Reviewed for Code Compliance</div>";
string fileName = #"C:\temp\source.pdf";
string outputFileName = #"C:\temp\source-output.pdf";
// Open a destination stream.
using (var destStream = new System.IO.MemoryStream()) {
using (var sourceReader = new PdfReader(fileName)) {
// Convert the HTML into a stamp.
using (var stampData = FromHtml(stamp)) {
using (var stampReader = new PdfReader(stampData)) {
using (var stamper = new PdfStamper(sourceReader, destStream)) {
stamper.Writer.CloseStream = false;
// Add the stamp stream to the source document.
var stampPage = stamper.GetImportedPage(stampReader, 1);
// Process all of the pages in the source document.
for (int i = 1; i <= sourceReader.NumberOfPages; i++) {
var canvas = stamper.GetOverContent(i);
canvas.AddTemplate(stampPage, 0, -50);
}
}
}
}
}
// Finished. Save the file.
using (var fs = new System.IO.FileStream(outputFileName, FileMode.Create)) {
destStream.Position = 0;
destStream.CopyTo(fs);
}
}
}
public static System.IO.Stream FromHtml(string html) {
var ms = new System.IO.MemoryStream();
// Convert html to pdf.
using (var document = new iTextSharp.text.Document()) {
var writer = iTextSharp.text.pdf.PdfWriter.GetInstance(document, ms);
writer.CloseStream = false;
document.Open();
using (var sr = new System.IO.StringReader(html)) {
XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, sr);
}
}
ms.Position = 0; // Reset for reading.
return ms;
}
One part of a page definition is the "MediaBox" which controls the page's size. This property takes two locations that specify the coordinates of two opposite corners of a rectangle. Although not required, most PDFs specify the lower left corner first followed by the upper right corner. Also, most PDF use 0x0 for the lower left and then whatever the page's width and height for the top corner. So an 8.5x11 inch PDF would be 0,0 and 612,792 (8.5 * 72 = 612 and 11 * 72 = 792) and this would be written as 0,0,612,792.
Your scanned PDF, however, has for whatever reason decided to treat 0,7072 as the lower left corner and 614,7864 as the top right corner. That still gives us (almost) an 8.5x11 page size but if you try to draw something at 0,0 it will be 7,072 pixels below the actual page. You can see this in Acrobat Pro by zooming out very far (1% for me), picking Tools, Edit Object and then doing a Select All. You should see something way far down selected, too.
To get around this, you need to respect the page's boundaries.
for (int i = 1; i <= sourceReader.NumberOfPages; i++) {
//Get the page to be stamped
var pageToBeStamped = sourceReader.GetPageSize(i);
var canvas = stamper.GetOverContent(i);
//Offset our new page by 50 pixels off of the destination page's bottom
canvas.AddTemplate(stampPage, pageToBeStamped.Left, pageToBeStamped.Bottom - 50);
}
The code above gets the rectangle for the imported page and uses bottom offset by 50 pixels (from your original code). Also, although not a problem in your case, we use the imported page's actual left edge instead of just zero.
This code can still break, however. The math in the first paragraph uses 72 which is the default for PDFs but this can be changed. Most people don't change it but most people also don't change 0,0. Currently your -50 assumes the 72 which gives the visual perception of moving the stamp about seven-tenths of an inch from the top edge. If you run into this scenario you'll want to look into retrieving the user unit.
Also, as I said in the first paragraph, most applications use lower left upper right but this isn't a hard rule. Someone could specify upper right and bottom left or even top left and bottom right. This is a hard one to take into account but it is something that you should at least be aware of.

Using extendscript (javascript) how can I get the color values from the Photoshop color table

I'm writing a Photoshop script in extendscript/javascript and I'm trying to verify that the document is using just one color (plus transparency). What I would like to do is change the document mode to Indexed Color and then get the values in the color table.
I have successfully changed the document mode to Indexed Color but can't figure out how to access the color table or the color values inside of it.
My working alternative is to use a colorSampler to compare the values of each pixel, but that can take a couple of minutes to run on larger documents and speed is an issue for this project.
Please let me know if there is a way to access the color table or if you see a way to reduce the time it takes to run this function.
function sample_color(doc, sample_rate) {
var status = 'PASS'
var color_sampler = doc.colorSamplers.add([0,0])
var color_val = false //first (and hopefully only) color value in the document
var broke = false
for (x=1; x < doc.width; x+=sample_rate){
if (broke){
break
}
for (y=1; y < doc.height; y+=sample_rate){
color_sampler.move([UnitValue(x, 'px'), UnitValue(y, 'px')])
try{
var color = color_sampler.color //color of the current pixel
} catch(e) {
var color = false //color_sampler.color fails if the pixel is transparent
}
if (color != false){
if (color_val != false){
if (!color.isEqual(color_val)){
status = 'FAIL'
broke = true
break
}
} else {
color_val = color
}
}
}
}
color_sampler.remove()
return status
}
xbytor has written a couple of scripts for accessing colour tables. This link may be of use to you.