/* Creates a package and files for import into Papirfly FlashApps. Extra files are: - fonts.json, list of families and font files used, - graphics.json, list of auto-generated graphic files of non-editable content - template.json, template file for flash editor. */ app.doScript(ExtractContent, ScriptLanguage.javascript, null, UndoModes.FAST_ENTIRE_SCRIPT); function ExtractContent() { app.scriptPreferences.userInteractionLevel = UserInteractionLevels.interactWithAll; var debugFlagFile = new File('/Users/tcaspersen/Desktop/indesignDebug.txt'); debugFlagFile.encoding = 'UTF-8'; debugFlagFile.open("r", null, null); var debugText = debugFlagFile.read(); var allowDebugMode = debugText.length > 0; var production = true; if (allowDebugMode) production = false; var packageLocation; var hasBleed = false; var generatedCode = new Array(); var generatedFontCode = new Array(); var curDoc; // holds current document to avoid need for transporting it all over var pauseOutput = true; var generatedFontData = []; var generatedGraphicsData = []; var templateData = { pdfOutputType: pdfOutputType, hasBleed: hasBleed }; var fontData = { fonts: [] }; var fontFamiliesUsed = {}; var colorsUsed = {}; var paragraphStylesUsed = {}; var tagsUsed = []; var labelsUsed = []; var pagesJson = {}; var textFramesWarnings = []; var documentBleed = {}; var userBleed = {}; function initDataHolders() { generatedCode = new Array(); generatedFontCode = new Array(); pauseOutput = true; generatedFontData = []; generatedGraphicsData = []; templateData = { pdfOutputType: pdfOutputType, hasBleed: hasBleed }; fontData = { fonts: [] }; fontFamiliesUsed = {}; colorsUsed = {}; paragraphStylesUsed = {}; tagsUsed = []; labelsUsed = []; pagesJson = {}; textFramesWarnings = []; } BLEED_SIDES = { TOP: 1, LEFT: 2, RIGHT: 4, BOTTOM: 8, ALL: 15 } // DO INITIAL PARSING TO BE ABLE TO ALERT USER IF SETUP IS STRANGE. initDataHolders(); var supressFileCreatetionOnCodeDoc = true; docDoc(app.activeDocument); supressFileCreatetionOnCodeDoc = false; if (labelsUsed.length == 0) { alert('Document has no editable elements, use "Script Label" to make elements editable in Papirfly'); return; } if (textFramesWarnings.length > 0) { var warnText = ""; for (var i = 0; i < textFramesWarnings.length; i++) { warnText += "\r'" + textFramesWarnings[i].label + "'\r " + textFramesWarnings[i].warnings.join("\r "); } alert('Some editable text frame have style overrides or character styles. Please remove them before exporting to papirfly' + warnText); return; } var userMeasurementUnit = { horizontal: app.activeDocument.viewPreferences.horizontalMeasurementUnits, vertical: app.activeDocument.viewPreferences.verticalMeasurementUnits }; app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.points; app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.points; if (production) { /**** CREATE DIALOG *******************************/ var myPresets = app.pdfExportPresets.everyItem().name; // myPresets.unshift("- Select Preset -"); var myWin = new Window('dialog', 'PDF Export Presets'); // myWin.orientation = 'stack'; myWin.alignChildren = 'left'; with(myWin) { var inf = myWin.add('group'); inf.orientation = 'column'; inf.alignChildren = 'left'; inf.add('statictext', [0, 0, 440, 50], 'This will prepare and package the open document for use in Papirfly.\rText fields and images with script label will be editable.\rThe editable text fields will have all paragraph style overrides cleared.', { multiline: true }); var preset = myWin.add('group'); preset.orientation = 'row'; preset.add('statictext', undefined, 'Select PDF Export preset:'); preset.myPDFExport = preset.add('dropdownlist', undefined, undefined, { items: myPresets }); preset.myPDFExport.onChange = function(e) { // alert(e); } preset.myPDFExport.selection = 0; var papirout = myWin.add('group'); papirout.orientation = 'column'; papirout.alignChildren = 'left'; papirout.add('statictext', undefined, 'Output type from Papirfly, should match PDF export.'); papirout.rgb = papirout.add('radiobutton', undefined, 'RGB'); papirout.cmyk = papirout.add('radiobutton', undefined, 'CMYK'); papirout.newspaper = papirout.add('radiobutton', undefined, 'Newspaper'); papirout.rgb.value = true; var fields = myWin.add('group'); // fields.preferredSize = [440, 10]; fields.add('statictext', [0, 0, 440, 50], (labelsUsed.length + ' Script labels used: ' + labelsUsed.join(', ')), { multiline: true }); var btns = myWin.add('group'); btns.orientation = 'row'; btns.btnOK = btns.add('button', undefined, 'OK'); btns.btnCancel = btns.add('button', undefined, 'cancel'); }; myWin.center(); //Show the dialog box. var userClickedOK = myWin.show() == 1; function getSelectedPresetIndex() { var s = preset.myPDFExport.selection; if (!isNaN(s)) return s; for (var i = 0; i < myPresets.length; i++) { if (s == myPresets[i]) { return i; } } return -1; } var pdfOutputType = papirout.newspaper.value ? 'newspaper' : (papirout.cmyk.value ? 'cmyk' : 'rgb'); var myPDFExportPreset = app.pdfExportPresets[preset.myPDFExport.selection.index]; calculateDocBleed(); //alert(pdfOutputType); if (userClickedOK == true) { // alert("You clicked the OK button."); } else { return; // alert("You clicked the Cancel button."); } var loc = File.saveDialog("Save Papirfly package as:"); if (loc == null || loc.absoluteURI == null) return; // user clicked cancel packageLocation = loc.absoluteURI; var f = new Folder(loc).create(); var isPackageOk = createPackage(loc); } else { var pdfOutputType = 'rgb'; var myPDFExportPreset = app.pdfExportPresets[6]; calculateDocBleed(); // var outputPath = '/Users/tcaspersen/Desktop/Indesign\ herjing/'; // for debug, trenger ikke velge fil hver gang; var outputPath = '/Users/tcaspersen/Desktop/aa/'; // for debug, trenger ikke velge fil hver gang; var packageFolderName = ''; packageLocation = outputPath + packageFolderName; var outConsole = new File(packageLocation + '/out.txt'); outConsole.encoding = 'UTF-8'; outConsole.open("w", null, null); outConsole.close(); } function calculateDocBleed() { //ale/rt("documentBleed top " + myPDFExportPreset.bleedTop + " , " + myPDFExportPreset.useDocumentBleedWithPDF + ", " + app.activeDocument.documentPreferences.documentBleedTopOffset) if (myPDFExportPreset.useDocumentBleedWithPDF) { documentBleed.left = app.activeDocument.documentPreferences.documentBleedInsideOrLeftOffset; documentBleed.right = app.activeDocument.documentPreferences.documentBleedOutsideOrRightOffset; documentBleed.top = app.activeDocument.documentPreferences.documentBleedTopOffset; documentBleed.bottom = app.activeDocument.documentPreferences.documentBleedBottomOffset; } else { // For some reason, pdf preset bleed values are all in Picas documentBleed.left = myPDFExportPreset.bleedInside * 12; documentBleed.right = myPDFExportPreset.bleedOutside * 12; documentBleed.top = myPDFExportPreset.bleedTop * 12; documentBleed.bottom = myPDFExportPreset.bleedBottom * 12; // need to set active document's bleed in order to get png export to have correct size userBleed.left = app.activeDocument.documentPreferences.documentBleedInsideOrLeftOffset; userBleed.right = app.activeDocument.documentPreferences.documentBleedOutsideOrRightOffset; userBleed.top = app.activeDocument.documentPreferences.documentBleedTopOffset; userBleed.bottom = app.activeDocument.documentPreferences.documentBleedBottomOffset; app.activeDocument.documentPreferences.documentBleedInsideOrLeftOffset = documentBleed.left; app.activeDocument.documentPreferences.documentBleedOutsideOrRightOffset = documentBleed.right; app.activeDocument.documentPreferences.documentBleedTopOffset = documentBleed.top; app.activeDocument.documentPreferences.documentBleedBottomOffset = documentBleed.bottom; } if (documentBleed.left + documentBleed.right + documentBleed.top + documentBleed.bottom > 0) { hasBleed = true; alert('hasBleed ' + hasBleed) } // alert("bleed" + documentBleed.left + ", " + documentBleed.right + ", " + documentBleed.top + ", " + documentBleed.bottom) } var out = new File(packageLocation + '/template.json'); out.encoding = 'UTF-8'; var outFont = new File(packageLocation + '/fonts.json'); outFont.encoding = 'UTF-8'; var outGraphics = new File(packageLocation + '/graphics.json'); outGraphics.encoding = 'UTF-8'; function consoleLog(txt) { if (outConsole) { outConsole.open("a", null, null); outConsole.write(txt + '\n'); outConsole.close(); } } initDataHolders(); function getDPI(wantedWidth) { return (wantedWidth * 72) / app.activeDocument.pages[0].bounds[3]; } with(app.pngExportPreferences) { transparentBackground = true; anitAlias = true; exportResolution = getDPI(1600); } docDoc(app.activeDocument); if (out != null) { out.open("w", null, null); out.write(formatAsJson(templateData)); out.close(); } if (outFont != null) { outFont.open("w", null, null); outFont.write(formatAsJson(fontData)); outFont.close(); } if (outGraphics != null) { outGraphics.open("w", null, null); outGraphics.write(formatAsJson(generatedGraphicsData)); outGraphics.close(); } app.pngExportPreferences.exportResolution = getDPI(800); app.pngExportPreferences.pngExportRange = PNGExportRangeEnum.EXPORT_RANGE; app.pngExportPreferences.pageString = "1"; app.pngExportPreferences.useDocumentBleeds = false; app.activeDocument.exportFile(ExportFormat.PNG_FORMAT, File(packageLocation + '/icon.png'), false); app.pngExportPreferences.exportResolution = getDPI(1600); app.pngExportPreferences.useDocumentBleeds = true; if (production) { var fold = new Folder(packageLocation); var dest = new File(packageLocation + ".zip") app.packageUCF(fold, dest); } // set users units and bleed back to values before export started app.activeDocument.viewPreferences.horizontalMeasurementUnits = userMeasurementUnit.horizontal; app.activeDocument.viewPreferences.verticalMeasurementUnits = userMeasurementUnit.vertical; if (userBleed.left != undefined) { app.activeDocument.documentPreferences.documentBleedInsideOrLeftOffset = userBleed.left; app.activeDocument.documentPreferences.documentBleedOutsideOrRightOffset = userBleed.right; app.activeDocument.documentPreferences.documentBleedTopOffset = userBleed.top; app.activeDocument.documentPreferences.documentBleedBottomOffset = userBleed.bottom; } // create package with all images, etc. function createPackage(dir) { var to = dir; var copyingFonts = true; var copyingLinkedGraphics = false; var copyingProfiles = true; var updatingGraphics = true; var includingHiddenLayers = false; var ignorePreflightErrors = true; var creatingReport = true; var versionComments = "a"; var forceSave = false; app.activeDocument.packageForPrint( to, copyingFonts, copyingLinkedGraphics, copyingProfiles, updatingGraphics, includingHiddenLayers, ignorePreflightErrors, creatingReport, true, true, versionComments, versionComments, forceSave ); } function docDoc(doc) { curDoc = doc; docAllProps(doc); docCollection(doc.pages, "pages", docPage); docCollection(doc.paragraphStyles, "paragraphStyles", docParagraphStyle); docCollection(doc.fonts, "fontSwfs", docFont); docCollection(doc.colors, "colors", docColor); templateData.tags = tagsUsed; // list of tags used in editable text, ie. "Hello [username]" // create one entry for font swfs pr. font family in document var fontSwfs = {}; for (var i in fontFamiliesUsed) { fontSwfs[i] = i; } templateData.fontSwfs = fontSwfs; // create one object pr. family with reference to font files for regular, bold, etc. var fontHash = {}; var f; var fh; for (var i = 0; i < generatedFontData.length; i++) { //if (fontData.fonts[]) f = generatedFontData[i]; if (fontHash[f.family] == null) { fontHash[f.family] = { family: f.family }; } fh = fontHash[f.family]; if (f.isBold && f.isItalic) fh.boldItalic = f.fontFile; else if (f.isBold) fh.bold = f.fontFile; else if (f.isItalic) fh.italic = f.fontFile; else fh.regular = f.fontFile; } for (var item in fontHash) { fontData.fonts.push(fontHash[item]) } } function createFontData(font) { var o try { //consoleLog('CreateFontData start'); var file = getFileName(font.location); var family = font.fontFamily; var isBold = font.fontStyleName == "Bold"; var isCFF = font.fontType == FontTypes.OPENTYPE_CFF; var className = toClassName(font.platformName); o = {}; o.fontFile = "Document fonts\\\\" + file; o.family = className; // use classname instead of fontFamily. Indesign cannot report which font is regular, so // knowing what a font is a bold variant of is impossible. Thus family = fontFamily + style. // o.isBold = font.fontStyleName.toLowerCase().indexOf("bold") >= 0; // o.isItalic = font.fontStyleName.toLowerCase().indexOf("italic") >= 0; // consoleLog('CreateFontData ' + formatAsJson(o)); } catch (ex) { consoleLog('createFontData failed ' + ex.toString()) } return o; } function docFont(font) { //consoleLog('doc font start '); try { // consoleLog(font.platformName); var fontFamily = toClassName(font.platformName); if (fontFamiliesUsed[fontFamily]) generatedFontData.push(createFontData(font)); } catch (ex) { consoleLog('docFont failed on font ' + font.toSource()) } // consoleLog('doc font finished'); } function docParagraphStyle(paragraphStyle) { docCode("textStyles", codeParagraphStyle(paragraphStyle)); } var tabAlignmentLookup; function createTabLookup() { tabAlignmentLookup = {}; tabAlignmentLookup[TabStopAlignment.CENTER_ALIGN] = 'center'; tabAlignmentLookup[TabStopAlignment.CHARACTER_ALIGN] = 'decimal'; tabAlignmentLookup[TabStopAlignment.LEFT_ALIGN] = 'start'; tabAlignmentLookup[TabStopAlignment.RIGHT_ALIGN] = 'end'; } function createJackTabStops(tabstops) { var ts; var tabstopsOut = []; if (tabAlignmentLookup == undefined) createTabLookup(); for (var i = 0; i < tabstops.length; i++) { ts = tabstops[i]; to = {}; to.alignment = tabAlignmentLookup[ts.alignment]; to.position = ts.position; if (ts.alignment == TabStopAlignment.CHARACTER_ALIGN) to.decimalAlignmentToken = ts.alignmentCharacter; tabstopsOut.push(to); } return tabstopsOut; } function codeParagraphStyle(paragraphStyle) { var styleName = paragraphStyle.name; if (paragraphStylesUsed[styleName] !== true) return null; consoleLog('\n ' + paragraphStyle.name) var fs = paragraphStyle.fontStyle.toString().toUpperCase(); var description = null; var fontFamily; var fontWeight = "" + (fs.indexOf("BOLD") >= 0 ? "bold" : "normal"); var fontStyle = "" + (fs.indexOf("ITALIC") >= 0 ? "italic" : "normal"); var fontSize = paragraphStyle.pointSize; var lineHeight = paragraphStyle.leading == Leading.AUTO ? "120%" : paragraphStyle.leading + "px"; // consoleLog("paragraphStyle.fillColor " + paragraphStyle.fillColor.name); // consoleLog("paragraphStyle.fillColor.name " + (paragraphStyle.fillColor.name == "")); var tabStops if (paragraphStyle.tabStops && paragraphStyle.tabStops.length > 0) { tabStops = createJackTabStops(paragraphStyle.tabStops); } var colorIsNotSwatch = paragraphStyle.fillColor.name == ""; var col = paragraphStyle.fillColor; // user can set unnamed colours to paragraph. If we find one of those, we add it as a swatch and update paragraphStyle. if (colorIsNotSwatch) { var color_by_hand = app.activeDocument.colors.add({ model: col.model, space: col.space, colorValue: col.colorValue }); paragraphStyle.fillColor = color_by_hand; } var color = paragraphStyle.fillColor.name; //consoleLog('fontStyle ' + fs); if (paragraphStyle.appliedFont.status == FontStatus.NOT_AVAILABLE) { if (production) { alert('Font ' + paragraphStyle.appliedFont.toSpecifier() + ' is not properly installed. Try manually installing it.'); return; } else { consoleLog('Font ' + paragraphStyle.appliedFont.toSpecifier() + ' is not properly installed.') } } if (typeof(paragraphStyle.appliedFont) === "object") { /* consoleLog('font is object ' + paragraphStyle.appliedFont.toSource()); consoleLog('font is object ' + paragraphStyle.appliedFont.location); consoleLog('font is isValid ' + paragraphStyle.appliedFont.isValid); consoleLog('font ' + paragraphStyle.appliedFont.platformName); consoleLog('font fontStyleName ' + paragraphStyle.appliedFont.fontStyleName);*/ // try { //consoleLog('font props ' + formatAsJson(paragraphStyle.appliedFont.properties)); // } catch (ex) {} fontFamily = toClassName(paragraphStyle.appliedFont.platformName); } else { // consoleLog('font is class name'); fontFamily = toClassName(paragraphStyle.name); } //consoleLog('adding to fontFamiliesUsed ' + fontFamily) fontFamiliesUsed[fontFamily] = true; var textAlign = ""; switch (paragraphStyle.justification) { case Justification.CENTER_ALIGN: textAlign += "center"; break; case Justification.LEFT_ALIGN: textAlign += "left"; break; case Justification.RIGHT_ALIGN: textAlign += "right"; break; case Justification.CENTER_JUSTIFIED: case Justification.FULLY_JUSTIFIED: case Justification.LEFT_JUSTIFIED: case Justification.RIGHT_JUSTIFIED: textAlign += "justified"; break; case Justification.AWAY_FROM_BINDING_SIDE: case Justification.TO_BINDING_SIDE: textAlign = null; break; } var paragraphSpaceBefore = paragraphStyle.spaceBefore; var paragraphSpaceAfter = paragraphStyle.spaceAfter; var typographicCase = (paragraphStyle.capitalization == Capitalization.ALL_CAPS ? "uppercase" : "default"); var tracking = paragraphStyle.tracking; var ret = { name: styleName, label: styleName, family: fontFamily, size: fontSize + 'px', color: color } if (paragraphStyle.bulletsAndNumberingListType == ListType.BULLET_LIST) { ret.bulletStyle = codeBulletStyle(paragraphStyle); } colorsUsed[color] = true; if (textAlign != "left") ret.textAlign = textAlign; if (lineHeight != "120%") ret.lineHeight = lineHeight; if (paragraphSpaceBefore != 0) ret.paragraphSpaceBefore = paragraphSpaceBefore + "px"; if (paragraphSpaceAfter != 0) ret.paragraphSpaceAfter = paragraphSpaceAfter + "px"; if (typographicCase != "default") ret.typographicCase = typographicCase; if (tracking != 0) ret.trackingRight = (tracking / 10) + "%"; if (tabStops) ret.tabstops = tabStops; return ret; } function codeBulletStyle(paragraphStyle) { var bStyleName = paragraphStyle.name + "_bullet"; var bulletStyle = { name: bStyleName }; bulletStyle.indent = paragraphStyle.leftIndent + "px"; bulletStyle.shape = "text"; bulletStyle.x = (paragraphStyle.leftIndent + paragraphStyle.firstLineIndent) / 2 + "px" bulletStyle.bulletCharId = paragraphStyle.bulletChar.characterValue; docCode("bulletStyles", bulletStyle); return bStyleName; } function codeColor(color) { if (color.name == null || color.name.length < 1 || colorsUsed[color.name] !== true) return null; var rgb = "" var cmyk = []; if (color.space == ColorSpace.RGB) { rgb = toHex(color.colorValue); cmyk = pfCmykValues(toCMYK_values(color)); } else { rgb = toRGB_hex(color); cmyk = pfCmykValues(toCMYK_values(color)); } return { name: color.name, value: rgb, cmyk: cmyk }; } function getFileName(path) { var sep = path.lastIndexOf("\\"); if (sep < 0) sep = path.lastIndexOf("/"); if (sep < 0) return path; return path.substr(sep + 1); } function makeVar(value) { var legalVarChars = "abcdefghijklmnopqrstuvwxyz1234567890"; var c, i, s = "_"; for (i = 0; i < value.length; i++) { c = value[i]; if (legalVarChars.indexOf(c.toLowerCase()) < 0) c = "_"; s += c; } return s; } function docCode(type, code) { if (code != null) { if (templateData[type] == null) templateData[type] = []; templateData[type].push(code); } } function docColor(color) { docCode("colors", codeColor(color)); } function codePage(page) { var c = {}; c.width = round(page.bounds[3]); c.height = round(page.bounds[2]); c.elements = []; // Indesign returns objects top-to-bottom, codeCollections reverses that. But // strangely, indesign returns objects in layers by layer bottom-to-top. // So: // Code collection returns objects in bottom-to-top pr layer, adds layerIndex each object. // Below we sort by layerIndex and index in elements array. // Problem solved var rawElements = codeCollection(page.allPageItems, getItemsCode); for (var i = 0; i < rawElements.length; i++) rawElements[i].index = i; rawElements.sort(sortByLayer); // Optimize and simplify by collapsing non-editable elements into pdfs. // start at bottom, create one pdf for each set of elements that lies between editable elements. function setAllVisible(state) { for (var k = 0; k < rawElements.length; k++) setElementVisible(rawElements[k], state); } function setElementVisible(element, state) { // consoleLog("type "+element.type+" "+(element.label ? element.label : "-")) if (element.type == "media") { // consoleLog("vis "+state) element.pageItem.parent.visible = state; } element.pageItem.visible = state; } // clean up helper vars function removeHelperVars(elem) { delete(elem.index); delete(elem.layerIndex); delete(elem.pageItem); //return elem; } setAllVisible(false); if (myPDFExportPreset == null) myPDFExportPreset = app.pdfExportPresets[0]; var pdfIndexOnPage = 0; var fileName; var hasVisibleElements = false; for (var i = 0; i <= rawElements.length; i++) { /* Set all elements visible = false Loop through all elements on page - if not editable, set as visible - if editable, - create pdf of all currently visible - add editable element - set all to visbile = false again - if at end and there is visible elements - create pdf of all currently visible */ consoleLog('\nelem ' + i + ' l, label ' + rawElements.length + ' ' + (rawElements[i] ? rawElements[i].label + ' ' + rawElements[i].type : '')); if (i == rawElements.length || (rawElements[i].label != null && rawElements[i].label != '')) { if (hasVisibleElements) { // consoleLog('creating pdf layer mergedElements_p' + (page.documentOffset + 1) + 'e' + pdfIndexOnPage) if (!supressFileCreatetionOnCodeDoc) { fileName = 'mergedElements_p' + (page.documentOffset + 1) + 'e' + pdfIndexOnPage; app.pdfExportPreferences.pageRange = (page.documentOffset + 1).toString(); app.pngExportPreferences.pageString = (page.documentOffset + 1).toString(); var backgroundTask = app.activeDocument.asynchronousExportFile(ExportFormat.pdfType, File(packageLocation + '/' + fileName + '.pdf'), false, myPDFExportPreset, ''); backgroundTask.waitForTask(); if (production) { app.activeDocument.exportFile(ExportFormat.PNG_FORMAT, File(packageLocation + '/' + fileName + '.png'), false); } generatedGraphicsData.push({ name: fileName, pdf: fileName + '.pdf', png: fileName + '.png' }); pdfIndexOnPage++; c.elements.push(createMergeToPDF(c, fileName, documentBleed)); } } if (i < rawElements.length) { labelsUsed.push(rawElements[i].label); c.elements.push(rawElements[i]); if (rawElements[i].type == 'media') i++; } setAllVisible(false); hasVisibleElements = false; } else { // consoleLog('element ' + i + ' visible ' + rawElements[i].pageItem.visible); setElementVisible(rawElements[i], true); // rawElements[i].pageItem.visible = true; hasVisibleElements = true; } } setAllVisible(true); for (var j = 0; j < c.elements.length; j++) { removeHelperVars(c.elements[j]); } return c; } function createMergeToPDF(pageProps, fileName, documentBleed) { var o = { type: "media", subtype: "image", assetSupplier: 'FLA', left: 0, top: 0, editable: false, image_x: documentBleed ? -documentBleed.left : 0, image_y: documentBleed ? -documentBleed.top : 0, scaleMode: "none", // bleedType: BLEED_SIDES.ALL // bleed type in flash is a bit map flag, top, left, right, bottom. 15 = all sides }; if (hasBleed) o.bleedType = BLEED_SIDES.ALL; o.assetId = "T[flashTaskId]_ResourceFile:" + fileName; o.width = pageProps.width; o.height = pageProps.height; o.image_w = pageProps.width + (documentBleed ? documentBleed.left + documentBleed.right : 0); o.image_h = pageProps.height + (documentBleed ? documentBleed.top + documentBleed.bottom : 0); return o; } function sortByLayer(a, b) { if (a.layerIndex == b.layerIndex) return a.index - b.index; else return b.layerIndex - a.layerIndex; } function docPage(page) { docCode("pages", codePage(page)); } function docCollection(collection, tag, detailDelegate) { var length = collectionLength(collection); if (length > 0) { for (var index = 0; index < length; index++) detailDelegate(collection[index]); } } function codeCollection(pageItems, detailDelegate, appendTo) { var a = appendTo ? appendTo : []; var l = collectionLength(pageItems); var elem if (l > 0) { for (var index = 0; index < l; index++) { elem = detailDelegate(pageItems[index]); if (elem.type == "Group") { // recurse on group items. codeCollection(elem.items, detailDelegate, a); } else if (elem != null) { a.unshift(elem); } } } return a; } var jackClassHash; function createClassNameHash() { jackClassHash = {}; jackClassHash["Rectangle"] = "rectangle"; jackClassHash["Image"] = "media"; jackClassHash["PDF"] = "media"; jackClassHash["TextFrame"] = "text"; } function getItemsCode(item) { var className = item.reflect.name; if (jackClassHash == null) createClassNameHash(); var ret; var tmpLabel; if (className == "Image" || className == "PDF") { tmpLabel = toLabel(item.parent.label); } else { tmpLabel = toLabel(item.label); } if (tmpLabel != null && tmpLabel != "") { switch (className) { case "Rectangle": ret = jackRectangle(item); break; case "PDF": case "Image": ret = jackImage(item); break; case "TextFrame": ret = jackTextFrame(item); break; case "Group": ret = { type: className, items: item.pageItems } default: ret = { type: className } } } if (ret == null) ret = { type: className } // add layerIndex in order to sort elements by depth ret.layerIndex = item.itemLayer.index; ret.pageItem = item; //ret.layerName = item.itemLayer.name; return ret; } /* TOP:int = 1; static public const LEFT:int = 2; static public const RIGHT:int = 4; static public const BOTTOM:int = 8;*/ function getBoundsAsAttr(bounds) { var b = {} b.left = round(bounds[1]); b.top = round(bounds[0]); b.right = round(bounds[3]); b.bottom = round(bounds[2]); b.width = b.right - b.left; b.height = b.bottom - b.top; return b; } function insertImageBoundsAndBleed(target, bounds_raw, hasBleed) { var bounds = getBoundsAsAttr(bounds_raw); if (hasBleed) { var pageW = round(app.activeDocument.pages[0].bounds[3]); var pageH = round(app.activeDocument.pages[0].bounds[2]); var bleedType = 0; if (bounds.left <= 0) { bleedType += BLEED_SIDES.LEFT; bounds.left = 0; } if (bounds.top <= 0) { bleedType += BLEED_SIDES.TOP; bounds.top = 0; } if (bounds.right >= pageW) { bleedType += BLEED_SIDES.RIGHT; bounds.right = pageW; } if (bounds.bottom >= pageH) { bleedType += BLEED_SIDES.BOTTOM; bounds.bottom = pageH; } consoleLog(bounds.left + ", " + bounds.top + " :: " + bounds.right + ">=" + pageW + " :: " + bounds.bottom + '>=' + pageH) if (bleedType > 0) target.bleedType = bleedType; } target['left'] = bounds.left + 'px'; target['top'] = bounds.top + 'px'; target['width'] = bounds.right - bounds.left + 'px'; target['height'] = bounds.bottom - bounds.top + 'px'; } function geometricBounds_insertProps(target, bounds, leftOffset, widthOffset, absoluteBaseline) { if (leftOffset == null) leftOffset = 0; if (widthOffset == null) widthOffset = 0; target['left'] = round(bounds[1] + leftOffset) + 'px'; target['top'] = (absoluteBaseline ? round(absoluteBaseline) : round(bounds[0])) + 'px'; target['width'] = round(bounds[3] - bounds[1] + widthOffset) + 'px'; target['height'] = round(bounds[2] - bounds[0]) + 'px'; } function jackParagraph(para) { var ret = {}; ret.text = jsonStringify(para.contents); findTags(ret.text); ret.textStyle = para.appliedParagraphStyle.name; ret.type = "text"; ret.editable = "true"; paragraphStylesUsed[para.appliedParagraphStyle.name] = true; return ret; } function jackTextFrame(item) { var className = item.reflect.name; var ret = { type: 'container', layout: 'stacking', editable: 'true', label: toLabel(item.label) }; if (item.label != '') { ret.label = toLabel(item.label); /* flash frames has 2px padding. We add 4px to width and adjust left if align is not left */ var leftOffset = 0; if (item.paragraphs[0].justification == Justification.CENTER_ALIGN) leftOffset = -2; else if (item.paragraphs[0].justification == Justification.RIGHT_ALIGN) leftOffset = -4; var absoluteBaseline = item.characters.firstItem().baseline; geometricBounds_insertProps(ret, item.geometricBounds, leftOffset, 4, absoluteBaseline); ret.yIsBaseline = true; /* Flag for editor to adjust 'top' after loading. Flash and Indesign handles distance from frame top differntly. In Indesign, frame top to baseline == point size. In Flash, frame top to baseline == ascent (which has to be measured) JackPageFrameHelper.createElementPrint() parses .yIsBaseline and adjust accordingly */ delete(ret.height); // want height to be dynamic ret.elements = []; var availableTextStyles = {}; var tmp; var hasOverrides = false; var chrStyles = []; for (var i = 0; i < item.paragraphs.length; i++) { var ps = item.paragraphs[i]; // Check if paragraph has overrides, ie. more than one textStyleRange. Collect info and present to user. if (supressFileCreatetionOnCodeDoc) { var warn = []; if (ps.textStyleRanges.length > 1) { hasOverrides = true; } for (var b = 0; b < ps.textStyleRanges.length; b++) { var chrStyleName = ps.textStyleRanges[b].appliedCharacterStyle.name if (chrStyleName.indexOf("[") == -1 && chrStyles.join(" ").indexOf(chrStyleName) == -1) chrStyles.push(chrStyleName); } } else { item.paragraphs[i].clearOverrides(); } tmp = jackParagraph(item.paragraphs[i]); availableTextStyles[tmp.textStyle] = true; ret.elements.push(tmp); } if (hasOverrides) { warn.push('paragraph style override' + (ps.textStyleRanges.length > 2 ? "s" : "")); if (chrStyles.length > 0) { chrStyles.unshift(""); warn.push('uses character style: ' + chrStyles.join("\r - ")); } if (warn.length > 0) textFramesWarnings.push({ label: item.label, warnings: warn }); } ret.availableTextStyles = []; for (var s in availableTextStyles) ret.availableTextStyles.push(s); ret.defaultTextStyle = ret.availableTextStyles[0]; } if (ret.elements == null || ret.elements.length == 0) { return null; } return ret; } function jackRectangle(item) { var className = item.reflect.name; if (item.fillColor.name == 'None' && item.strokeColor.name == 'None') return null; var ret = { type: jackClassHash[className] }; geometricBounds_insertProps(ret, item.geometricBounds); ret.fillColor = item.fillColor.name; ret.strokeColor = item.strokeColor.name; ret.strokeWeight = item.strokeWeight; if (item.fillColor.name != 'None') colorsUsed[item.fillColor.name] = true; if (item.fillColor.name != 'None') colorsUsed[item.strokeColor.name] = true; return ret; } function jackImage(item) { var className = item.reflect.name; var ret = { type: jackClassHash[className], subtype: 'image' }; insertImageBoundsAndBleed(ret, item.parent.geometricBounds, hasBleed); ret.imageType = item.imageTypeName; ret.editable = "true"; ret.label = toLabel(item.parent.label); findTags(ret.label); consoleLog(formatAsJson(ret)); return ret; } function getItems(item, asCode) { var props = null; var addClass = false; var full = false; if (!full) { props = new Array(); var className = item.reflect.name; var names = new Array(); // here vi add the names of the properties wanted for each class switch (className) { case "Color": names.push("name"); names.push("colorValue"); names.push("space"); break; case "Document": names.push("name"); names.push("fullName"); names.push("zeroPoint"); break; case "Paragraph": names.push("contents"); names.push("ascent"); names.push("baseline"); names.push("descent"); names.push("endBaseline"); names.push("endHorizontalOffset"); names.push("fontStyle"); names.push("pointSize"); names.push("visible"); names.push("appliedParagraphStyle"); break; case "ParagraphStyle": names.push("name"); names.push("appliedFont"); names.push("fontStyle"); names.push("pointSize"); names.push("justification"); names.push("basedOn"); break; case "Font": names.push("name"); names.push("fontStyleName"); names.push("fullName"); names.push("location"); break; case "GraphicLine": addClass = true; names.push("geometricBounds"); names.push("visible"); break; case "Image": addClass = true; names.push("geometricBounds"); names.push("visible"); break; case "Page": names.push("name"); names.push("index"); names.push("side"); names.push("bounds"); break; case "Rectangle": addClass = true; names.push("geometricBounds"); names.push("fillColor"); names.push("strokeColor"); names.push("strokeWeight"); // names.push("visible"); break; case "TextFrame": addClass = true; names.push("geometricBounds"); names.push("visible"); break; } // find the ReflectionInfo objects for (var i = 0; i < names.length; i++) { prop = item.reflect.find(names[i]);; if (prop != null) props.push(prop); } } else props = item.reflect.properties; var sorted = new Array(); if (addClass) sorted.push({ name: "class", value: item.reflect.name }); for (var i = 0; i < props.length; i++) { try { var name = props[i].name; if (name != null && name.indexOf("__") != 0) { // do not show "internal" properties var value = item[props[i].name]; if (value != undefined && value != null) { value = getFormattedValue(value); sorted.push({ name: name, value: value }); } } } catch (ex) {} } sorted.sort(function(a, b) { return a.name == b.name ? 0 : (a.name > b.name ? 1 : -1) }); return sorted; } function getFormattedValue(value) { if (value.reflect.find("toFixed") != null) return round(value); // number if (value.reflect.find("splice") != null && value.length > 0 && value[0].reflect.find("toFixed") != null) { // array of numbers var s = ""; for (var i = 0; i < value.length; i++) { if (i > 0) s += ","; s += round(value[i]); } return s; } if (value.reflect.find("name") != null) return value.name; return value.toString(); } function docAllProps(item) { // if (full) // tagFull("class", item.reflect.name); var items = getItems(item); for (var i = 0; i < items.length; i++) { var item = items[i]; //tagFull(item.name, item.value); } } function collectionLength(collection) { if (collection == null) return 0; try { return collection.length; } catch (ex) {} return collection.count(); } function collectionToString(collection) { var s = ""; var length = collectionLength(collection); for (var index = 0; index < length; index++) { if (index > 0) s += ","; s += collection[index]; } return s; } function findTags(text) { var regex_tag = /\[[\s\S]+?\]/g; var found = text.match(regex_tag); if (found != null) { for (var i = 0; i < found.length; i++) { if (tagsUsed.toString().indexOf(found[i]) == -1) { tagsUsed.push(found[i]); } } } } // *************************************************** utilities ******************************************* function round(value) { // round to 2 decimals return (Math.round(value * 100) / 100); } function toHex(rgb) { var s = "#"; for (var i = 0; i < rgb.length; i++) { var d = rgb[i].toString(16); while (d.length < 2) d = "0" + d; s += d.toUpperCase(); } return s; } /*function cmykToRgbHex(color) { var tempColorName = "temp color for conversion"; var tempColor = app.colors.itemByName(tempColorName); if (tempColor == null) { tempColor = app.colors.add(); // can not use just do "new Color()" tempColor.name = tempColorName; tempColor.model = ColorModel.PROCESS; } tempColor.space = ColorSpace.CMYK; tempColor.colorValue = color.colorValue; tempColor.space = ColorSpace.RGB; // this will change the colorValue property to contain rgb values return toHex(tempColor.colorValue); }*/ function toRGB_hex(color) { var tempColorName = "temp color for conversion"; var tempColor = app.colors.itemByName(tempColorName); if (tempColor == null) { tempColor = app.colors.add(); // can not use just do "new Color()" tempColor.name = tempColorName; } tempColor.model = color.model; tempColor.space = color.space; tempColor.colorValue = color.colorValue; tempColor.model = ColorModel.PROCESS; tempColor.space = ColorSpace.RGB; // this will change the colorValue property to contain rgb values return toHex(tempColor.colorValue); } function toCMYK_values(color) { var tempColorName = "temp color for conversion"; var tempColor = app.colors.itemByName(tempColorName); if (tempColor == null) { tempColor = app.colors.add(); // can not use just do "new Color()" tempColor.name = tempColorName; } tempColor.model = color.model; tempColor.space = color.space; tempColor.colorValue = color.colorValue; tempColor.model = ColorModel.PROCESS; tempColor.space = ColorSpace.CMYK; // this will change the colorValue property to contain rgb values return tempColor.colorValue; } function pfCmykValues(values) { var v = new Array(); for (var i = 0; i < values.length; i++) v.push(Number(round(values[i] / 100))); return v; } function jsonStringify(str) { if (str == null) return null; if (str.charAt(str.length - 1) == '\r') str = str.substring(0, str.length - 1); str = str.replace(/\"/g, "\\\""); str = str.replace(/\n/g, "\\n"); str = str.replace(/\r/g, "\\r"); str = str.replace(/\t/g, "\\t"); return str; } function toLabel(str) { if (str == null) return ""; if (str.charAt(str.length - 1) == '\r') str = str.substring(0, str.length - 1); str = str.replace(/\"/g, "\\\""); str = str.replace(/\n/g, ""); str = str.replace(/\r/g, ""); str = str.replace(/\t/g, ""); return str; } function removeFileType(value) { var dotIndex = value.lastIndexOf("."); if (dotIndex != -1) return value.substring(0, dotIndex); else return value } function toClassName(value) { var c, i, s = "", toUpper = true; for (i = 0; i < value.length; i++) { c = value[i]; if (c == " " || c == "\t" || c == "-") toUpper = true; else { if (toUpper) { c = c.toUpperCase(); toUpper = false; } s += c; } } return s; } // *************************************************** Output to file tools ******************************************* function formatAsJson(o, indent) { if (indent == null) indent = 1; else indent++; if (o == null) return ''; function getIndent(offset) { if (offset = null) offset = 0; var t = "\n"; for (var k = 0; k < (indent + offset); k++) t += " "; return t; } var output = ''; var isObject = typeof(o) == 'object'; var isArray = isObject && o['length'] != null; if (isArray) { output += '[' + getIndent(); for (var j = 0; j < o.length; j++) { output += formatAsJson(o[j], indent, true) + (j < o.length - 1 ? ', ' + getIndent() : ''); } output += getIndent(-1) + ']'; } else if (isObject) { output += '{' + getIndent(); var elems = []; for (var i in o) { elems.push('"' + i + '" : ' + formatAsJson(o[i], indent, true)); } output += elems.join(', ' + getIndent()); output += getIndent(-1) + '}'; } else { if (typeof(o) == 'number') output += o; else output += '"' + o + '"'; } return output; } }