/** * generate_inner_shadow_dataset.jsx * * Purpose: * Generate a systematic Inner Shadow effect dataset in Adobe Photoshop. * * Logic & Workflow: * 1. Creates a new transparent RGB document. * 2. Adds a raster layer and fills a centered rectangle with black. * 3. Applies one Inner Shadow effect via Photoshop ActionDescriptor. * 4. Saves the result as a transparent PNG. * * Arguments: * None (interactive). The user selects an output folder via dialog. * * Side Effects: * - Creates and closes many temporary Photoshop documents. * - Writes PNG files to the selected folder. */ var outFolder = Folder.selectDialog("Select output folder for Inner Shadow dataset"); if (!outFolder) { alert("No output folder selected. Exiting."); throw new Error("No output folder"); } var angles = [0, 90, 180, 270]; var distances = [5, 15, 30]; var sizes = [10, 30]; var chokes = [0, 20]; var fxOpacities = [75, 100]; var fxBlendModes = [ { key: "Nrml", name: "normal" }, { key: "Mltp", name: "multiply" } ]; function pxValue(v) { if (v === undefined || v === null) return 0; if (typeof v === "number") return v; if (typeof v.as === "function") return v.as("px"); if (typeof v.value !== "undefined") return v.value; return Number(v); } function createDocument(name, width, height) { try { return app.documents.add(width, height, 72, name, NewDocumentMode.RGB, DocumentFill.TRANSPARENT); } catch (e) { return app.documents.add(width, height, 72, name, NewDocumentMode.RGB); } } function addBlackRectangle(doc) { var w = pxValue(doc.width); var h = pxValue(doc.height); var margin = Math.round(Math.min(w, h) * 0.25); var layer = doc.artLayers.add(); layer.name = "shape"; var region = [ [margin, margin], [w - margin, margin], [w - margin, h - margin], [margin, h - margin] ]; doc.selection.select(region); var black = new SolidColor(); black.rgb.red = 0; black.rgb.green = 0; black.rgb.blue = 0; doc.selection.fill(black); doc.selection.deselect(); return layer; } function blendModeTypeID(mode) { try { return charIDToTypeID(mode); } catch (e) { return stringIDToTypeID(mode); } } function applyInnerShadow(params) { var desc = new ActionDescriptor(); var ref = new ActionReference(); ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("Lefx")); ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt")); desc.putReference(charIDToTypeID("null"), ref); var fxDesc = new ActionDescriptor(); var isDesc = new ActionDescriptor(); isDesc.putBoolean(charIDToTypeID("enab"), true); isDesc.putBoolean(charIDToTypeID("present"), true); isDesc.putBoolean(charIDToTypeID("showInDialog"), true); isDesc.putEnumerated(charIDToTypeID("Blnd"), charIDToTypeID("BlnM"), blendModeTypeID(params.blendMode)); var clr = new ActionDescriptor(); clr.putDouble(charIDToTypeID("Rd "), 0); clr.putDouble(charIDToTypeID("Grn "), 0); clr.putDouble(charIDToTypeID("Bl "), 0); isDesc.putObject(charIDToTypeID("Clr "), charIDToTypeID("RGBC"), clr); isDesc.putInteger(charIDToTypeID("Opct"), params.opacity); isDesc.putInteger(charIDToTypeID("lagl"), params.angle); isDesc.putBoolean(charIDToTypeID("uglg"), false); isDesc.putInteger(charIDToTypeID("Dstn"), params.distance); isDesc.putInteger(charIDToTypeID("Ckmt"), params.choke); isDesc.putInteger(charIDToTypeID("blur"), params.size); isDesc.putInteger(charIDToTypeID("Nose"), 0); fxDesc.putObject(charIDToTypeID("IrSh"), charIDToTypeID("IrSh"), isDesc); desc.putObject(charIDToTypeID("T "), charIDToTypeID("Lefx"), fxDesc); executeAction(charIDToTypeID("setd"), desc, DialogModes.NO); } function saveTransparentPng(doc, file) { var pngOptions = new PNGSaveOptions(); pngOptions.compression = 6; pngOptions.interlaced = false; doc.saveAs(file, pngOptions, true, Extension.LOWERCASE); } var count = 0; var errors = 0; var total = angles.length * distances.length * sizes.length * chokes.length * fxOpacities.length * fxBlendModes.length; for (var a = 0; a < angles.length; a++) { for (var d = 0; d < distances.length; d++) { for (var s = 0; s < sizes.length; s++) { for (var c = 0; c < chokes.length; c++) { for (var o = 0; o < fxOpacities.length; o++) { for (var b = 0; b < fxBlendModes.length; b++) { var params = { angle: angles[a], distance: distances[d], size: sizes[s], choke: chokes[c], opacity: fxOpacities[o], blendMode: fxBlendModes[b].key }; var fileName = "is_" + "a" + params.angle + "_" + "d" + params.distance + "_" + "s" + params.size + "_" + "c" + params.choke + "_" + "op" + params.opacity + "_" + "bm" + fxBlendModes[b].name + ".png"; var file = new File(outFolder + "/" + fileName); if (file.exists) { count++; continue; } var doc = createDocument("inner_shadow_test", 256, 256); var layer = addBlackRectangle(doc); try { applyInnerShadow(params); saveTransparentPng(doc, file); } catch (e) { $.writeln("Error: " + fileName + " — " + e); errors++; } finally { doc.close(SaveOptions.DONOTSAVECHANGES); } count++; if (count % 10 === 0) { $.writeln("Progress: " + count + " / " + total + " (errors: " + errors + ")"); } } } } } } } alert("Done. Generated " + count + " images, " + errors + " errors.\n" + outFolder.fsName);