

#target photoshop
function showBleedDialog() {
if (app.documents.length === 0) {
alert("សូមបើក Document នៅក្នុង Photoshop ជាមុនសិន!");
return;
}
var doc = app.activeDocument;
// --- UI Window Style ---
var dlg = new Window('dialog', 'BitePoint - Multi-Position Bleed Label Generator');
dlg.orientation = 'column';
dlg.alignChildren = ['fill', 'top'];
dlg.spacing = 10;
dlg.margins = 15;
// System Font Setup
var uiFont;
try {
uiFont = ScriptUI.newFont("Segoe UI", "Regular", 12);
} catch (e) {
uiFont = ScriptUI.newFont("dialog", "Regular", 12);
}
function setFont(container) {
for (var i = 0; i < container.children.length; i++) {
var child = container.children[i];
try { child.graphics.font = uiFont; } catch (err) {}
if (child.type === 'panel' || child.type === 'group') setFont(child);
}
}
// SECTION 1: Bleed Side Selection (L, R, T, B)
var pnlSide = dlg.add('panel', undefined, ' 1. ជ្រើសរើសជ្រុង Bleed 1cm (Bleed Side) ');
pnlSide.orientation = 'row';
pnlSide.margins = [12, 12, 12, 12];
pnlSide.spacing = 15;
var radSideLeft = pnlSide.add('radiobutton', undefined, 'Left (ឆ្វេង)');
var radSideRight = pnlSide.add('radiobutton', undefined, 'Right (ស្ដាំ)');
var radSideTop = pnlSide.add('radiobutton', undefined, 'Top (លើ)');
var radSideBottom = pnlSide.add('radiobutton', undefined, 'Bottom (ក្រោម)');
radSideBottom.value = true; // Default ខាងក្រោម
// SECTION 2: Font Size & Color
var pnlFont = dlg.add('panel', undefined, ' 2. Font Size & Color ');
pnlFont.orientation = 'row';
pnlFont.margins = [12, 12, 12, 12];
pnlFont.spacing = 15;
pnlFont.add('statictext', undefined, 'ទំហំ Font (pt):');
var txtFontSize = pnlFont.add('edittext', undefined, '24');
txtFontSize.preferredSize = [60, 26];
pnlFont.add('statictext', undefined, ' ពណ៌:');
var radBlack = pnlFont.add('radiobutton', undefined, 'Black (ខ្មៅ)');
var radWhite = pnlFont.add('radiobutton', undefined, 'White (ស)');
var radRed = pnlFont.add('radiobutton', undefined, 'Red (ក្រហម)');
radBlack.value = true;
// SECTION 3: Multi-Position Count Selection (1, 2, 3, or N Locations)
var pnlPos = dlg.add('panel', undefined, ' 3. ចំនួនកន្លែងដាក់អក្សរលើជ្រុង Bleed (Label Positions) ');
pnlPos.alignChildren = 'left';
pnlPos.margins = [12, 12, 12, 12];
pnlPos.spacing = 6;
var radPos1 = pnlPos.add('radiobutton', undefined, '1 កន្លែង (Center / ចំកណ្ដាល)');
var radPos2 = pnlPos.add('radiobutton', undefined, '2 កន្លែង (Start & End / ដើម និង ចុង)');
var radPos3 = pnlPos.add('radiobutton', undefined, '3 កន្លែង (Start, Center, End / ដើម កណ្ដាល ចុង)');
var grpPosCustom = pnlPos.add('group');
var radPosCustom = grpPosCustom.add('radiobutton', undefined, 'កំណត់ចំនួនកន្លែងច្រើនទៀត:');
var txtPosCustomCount = grpPosCustom.add('edittext', undefined, '4');
txtPosCustomCount.preferredSize = [60, 26];
txtPosCustomCount.enabled = false;
radPos3.value = true; // Default 3 កន្លែង
radPosCustom.onClick = function() { txtPosCustomCount.enabled = true; };
radPos1.onClick = function() { txtPosCustomCount.enabled = false; };
radPos2.onClick = function() { txtPosCustomCount.enabled = false; };
radPos3.onClick = function() { txtPosCustomCount.enabled = false; };
// SECTION 4: File Info Options
var pnlOpts = dlg.add('panel', undefined, ' 4. ព័ត៌មានដើមរបស់ហ្វាល (File Info) ');
pnlOpts.alignChildren = 'left';
pnlOpts.margins = [12, 12, 12, 12];
pnlOpts.spacing = 6;
var chkSize = pnlOpts.add('checkbox', undefined, 'Size (ខ្នាត cm)');
var chkDpi = pnlOpts.add('checkbox', undefined, 'Resolution (DPI)');
var chkFileName = pnlOpts.add('checkbox', undefined, 'File Name (ឈ្មោះហ្វាលដើម)');
var chkDate = pnlOpts.add('checkbox', undefined, 'Date (ថ្ងៃ-ខែ-ឆ្នាំ)');
chkSize.value = true;
chkDpi.value = false;
chkFileName.value = true;
chkDate.value = true;
// SECTION 5: Multi-Text Inputs (Dropdowns & Custom Text 1 & 2)
var pnlMulti = dlg.add('panel', undefined, ' 5. បន្ថែមអក្សរច្រើនទៀត (Multiple Custom Texts) ');
pnlMulti.alignChildren = 'left';
pnlMulti.margins = [12, 12, 12, 12];
pnlMulti.spacing = 8;
var listOptions = [
"-- មិនជ្រើសរើស --",
"Vinyl Banner",
"Sticker Label",
"Print & Cut",
"Flex Print",
"Urgent (ប្រញាប់)",
"Sample Test",
"Frontlit",
"Backlit",
"Approved"
];
// Dropdown 1
var grpDrop1 = pnlMulti.add('group');
grpDrop1.add('statictext', undefined, 'List ១:');
var drop1 = grpDrop1.add('dropdownlist', undefined, listOptions);
drop1.selection = 0;
drop1.preferredSize = [180, 26];
// Dropdown 2
var grpDrop2 = pnlMulti.add('group');
grpDrop2.add('statictext', undefined, 'List ២:');
var drop2 = grpDrop2.add('dropdownlist', undefined, listOptions);
drop2.selection = 0;
drop2.preferredSize = [180, 26];
// Custom Text 1
var grpCustom1 = pnlMulti.add('group');
var chkCustom1 = grpCustom1.add('checkbox', undefined, 'អក្សរបន្ថែម ១:');
var txtCustom1 = grpCustom1.add('edittext', undefined, '');
txtCustom1.preferredSize = [180, 26];
txtCustom1.enabled = false;
chkCustom1.onClick = function() { txtCustom1.enabled = chkCustom1.value; };
// Custom Text 2
var grpCustom2 = pnlMulti.add('group');
var chkCustom2 = grpCustom2.add('checkbox', undefined, 'អក្សរបន្ថែម ២:');
var txtCustom2 = grpCustom2.add('edittext', undefined, '');
txtCustom2.preferredSize = [180, 26];
txtCustom2.enabled = false;
chkCustom2.onClick = function() { txtCustom2.enabled = chkCustom2.value; };
// SECTION 6: Buttons
var btnGroup = dlg.add('group');
btnGroup.alignment = 'center';
btnGroup.spacing = 15;
var btnOk = btnGroup.add('button', undefined, 'OK (យល់ព្រម)', {name: 'ok'});
var btnCancel = btnGroup.add('button', undefined, 'Cancel (បោះបង់)', {name: 'cancel'});
btnOk.preferredSize = [110, 32];
btnCancel.preferredSize = [110, 32];
setFont(dlg);
if (dlg.show() !== 1) return;
// Process Configuration
var fontSizeVal = parseFloat(txtFontSize.text) || 24;
var fontColor = new SolidColor();
if (radWhite.value) {
fontColor.rgb.red = 255; fontColor.rgb.green = 255; fontColor.rgb.blue = 255;
} else if (radRed.value) {
fontColor.rgb.red = 255; fontColor.rgb.green = 0; fontColor.rgb.blue = 0;
} else {
fontColor.rgb.red = 0; fontColor.rgb.green = 0; fontColor.rgb.blue = 0;
}
var bleedSide = "BOTTOM";
if (radSideLeft.value) bleedSide = "LEFT";
if (radSideRight.value) bleedSide = "RIGHT";
if (radSideTop.value) bleedSide = "TOP";
var posCount = 3;
if (radPos1.value) posCount = 1;
if (radPos2.value) posCount = 2;
if (radPos3.value) posCount = 3;
if (radPosCustom.value) posCount = parseInt(txtPosCustomCount.text, 10) || 4;
var cfg = {
fontSize: fontSizeVal,
textColor: fontColor,
bleedSide: bleedSide,
posCount: posCount,
incSize: chkSize.value,
incDpi: chkDpi.value,
incFileName: chkFileName.value,
incDate: chkDate.value,
dropText1: (drop1.selection && drop1.selection.index > 0) ? drop1.selection.text : "",
dropText2: (drop2.selection && drop2.selection.index > 0) ? drop2.selection.text : "",
customText1: (chkCustom1.value) ? txtCustom1.text : "",
customText2: (chkCustom2.value) ? txtCustom2.text : ""
};
processBleedAndMultiLabel(doc, cfg);
}
function processBleedAndMultiLabel(doc, cfg) {
var origRuler = app.preferences.rulerUnits;
var origType = app.preferences.typeUnits;
app.preferences.rulerUnits = Units.CM;
app.preferences.typeUnits = TypeUnits.POINTS;
try {
var origW = doc.width.value;
var origH = doc.height.value;
var imgDpi = Math.round(doc.resolution);
// Set Photoshop Background color to White (Canvas extension will automatically fill with white)
var whiteColor = new SolidColor();
whiteColor.rgb.red = 255; whiteColor.rgb.green = 255; whiteColor.rgb.blue = 255;
app.backgroundColor = whiteColor;
// 1. Calculate Canvas Expansion
var newW = origW;
var newH = origH;
var anchorPos = AnchorPosition.MIDDLERIGHT;
if (cfg.bleedSide === "LEFT") {
newW = origW + 1;
anchorPos = AnchorPosition.MIDDLERIGHT;
} else if (cfg.bleedSide === "RIGHT") {
newW = origW + 1;
anchorPos = AnchorPosition.MIDDLELEFT;
} else if (cfg.bleedSide === "TOP") {
newH = origH + 1;
anchorPos = AnchorPosition.BOTTOMCENTER;
} else if (cfg.bleedSide === "BOTTOM") {
newH = origH + 1;
anchorPos = AnchorPosition.TOPCENTER;
}
// Expand Canvas (Fills expanded background with active white color directly)
doc.resizeCanvas(new UnitValue(newW, "cm"), new UnitValue(newH, "cm"), anchorPos);
// 2. Construct Label String
var textParts = [];
if (cfg.incFileName) {
var docName = doc.name.replace(/\.[^\.~]+$/, "");
textParts.push(docName);
}
if (cfg.incSize) {
var wClean = Math.round(origW * 100) / 100;
var hClean = Math.round(origH * 100) / 100;
textParts.push(wClean + " x " + hClean + " cm");
}
if (cfg.incDpi) textParts.push(imgDpi + "dpi");
if (cfg.dropText1 !== "") textParts.push(cfg.dropText1);
if (cfg.dropText2 !== "") textParts.push(cfg.dropText2);
if (cfg.customText1 !== "") textParts.push(cfg.customText1);
if (cfg.customText2 !== "") textParts.push(cfg.customText2);
if (cfg.incDate) {
var today = new Date();
var dd = String(today.getDate()); if (dd.length < 2) dd = '0' + dd;
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var mmm = months[today.getMonth()];
var yyyy = today.getFullYear();
textParts.push(dd + "-" + mmm + "-" + yyyy);
}
var fullText = textParts.join(" - ");
if (fullText === "") fullText = "Bleed 1cm";
// 3. Create and Distribute Multiple Text Labels Along Bleed Strip
var isVertical = (cfg.bleedSide === "LEFT" || cfg.bleedSide === "RIGHT");
var totalLength = isVertical ? origH : origW;
var margin = 1.5; // Safety margin in CM
for (var idx = 0; idx < cfg.posCount; idx++) {
var textLayer = doc.artLayers.add();
textLayer.kind = LayerKind.TEXT;
textLayer.name = "Bleed Info " + (idx + 1);
var textItem = textLayer.textItem;
textItem.contents = fullText;
textItem.size = cfg.fontSize;
textItem.color = cfg.textColor;
textItem.justification = Justification.CENTER;
// Calculate position along edge
var currentPos = 0;
if (cfg.posCount === 1) {
currentPos = totalLength / 2;
} else {
var step = (totalLength - (margin * 2)) / (cfg.posCount - 1);
currentPos = margin + (idx * step);
}
var posX = 0, posY = 0, rotDeg = 0;
if (isVertical) {
posX = (cfg.bleedSide === "LEFT") ? 0.5 : (origW + 0.5);
posY = currentPos;
rotDeg = -90;
} else { // TOP or BOTTOM
posX = currentPos;
posY = (cfg.bleedSide === "TOP") ? 0.5 : (origH + 0.5);
rotDeg = 0;
}
textItem.position = [new UnitValue(posX, "cm"), new UnitValue(posY, "cm")];
if (rotDeg !== 0) textLayer.rotate(rotDeg, AnchorPosition.MIDDLECENTER);
// Bounds Correction to prevent text spilling off edges
var b = textLayer.bounds;
var curCenterX = (b[0].value + b[2].value) / 2;
var curCenterY = (b[1].value + b[3].value) / 2;
var targetX = posX;
var targetY = posY;
if (isVertical) {
if (b[1].value < margin) targetY += (margin - b[1].value);
if (b[3].value > (origH - margin)) targetY -= (b[3].value - (origH - margin));
} else {
if (b[0].value < margin) targetX += (margin - b[0].value);
if (b[2].value > (origW - margin)) targetX -= (b[2].value - (origW - margin));
}
var deltaX = targetX - curCenterX;
var deltaY = targetY - curCenterY;
if (deltaX !== 0 || deltaY !== 0) {
textLayer.translate(new UnitValue(deltaX, "cm"), new UnitValue(deltaY, "cm"));
}
}
} catch (err) {
alert("Error: " + err.message);
} finally {
app.preferences.rulerUnits = origRuler;
app.preferences.typeUnits = origType;
}
}
showBleedDialog();