AEM 62 - InDesign CC 2015 - Create PDF Catalog in InDesign with Assets downloaded from AEM

Goal


This post is on developing a Adobe CC HTML Extension to login to AEM 62, search and download AEM assets (content fragments, images) and place them on a new InDesign document page,  effectively creating PDF catalogs with the assets uploaded (and managed in AEM); CC HTML Extensions run on Common Extensibility Platform (CEP) of CC products like InDesign, Photoshop, Illustrator...

Check this post for detailed instructions on how to create and debug CEP panels (MAC and Windows) and these CEP samples

For integrating AEM with InDesign Server to extract media etc. check documentationCatalog Producer to generate product catalogs in AEM Assets is documented here

Signing toolkit ZXPSignCmd can be downloaded at Adobe Labs (windows version available in the extension source)

Download the Extension Manager command line tool for installing ZXP extensions (Adobe Extension Manager CC no longer supported in CC 2015)
           
             Windows - https://www.adobeexchange.com/ExManCmd_win.zip
             MAC - https://www.adobeexchange.com/ExManCmd_mac.zip

Some of the logic in this post was coded by me, some copied shamelessly (written by various Adobe colleagues)

Demo | InDesign AEM ZXP | AEM Sling Referrer Package Install | Source Code


Sling Referrer Filter "Allow Empty" set to "true"

             Configuration - http://localhost:4502/system/console/configMgr/org.apache.sling.security.impl.ReferrerFilter



ZXP Installation

             Self-Signed Certificates - For dev purposes use OpenSSL and generate a self-signed certificate for signing the ZXP

                          openssl req -x509 -days 3650 -newkey rsa:2048 -keyout experience-aem-cep-key.pem -out experience-aem-cep-cert.pem

                          openssl pkcs12 -export -in  experience-aem-cep-cert.pem -inkey experience-aem-cep-key.pem -out experience-aem-cep.p12

             Build - Use ant to build the zxp using command > ant zxp

             Install - ExManCmd.exe /install "C:\dev\code\projects\cq62-extensions\eaem-aem-assets-on-indesign-page\temp\eaem-aem-assets-on-indesign-page.zxp"

             Installed to location (windows) - C:\Program Files (x86)\Common Files\Adobe\CEP\extensions


             Remove - ExManCmd.exe /remove com.experience.aem.cep.idsn



Place AEM Assets Panel - Login



Place AEM Assets Panel - Search, Download and & Place

              Assets selected are downloaded to C:\Users\<user>\Documents\eaem folder (created if not exists) on windows; The downloaded assets are placed on new InDesign page



Place AEM Assets Panel - Generate & Upload PDF

              PDF generated and saved to C:\Users\<user>\Documents\eaem folder (created if not exists) on windows



PDF Catalog in AEM



Solution


1) Folder structure:

                           For creating InDesign CEP extensions (html panels), the following is a simple source code folder structure

                           eaem-aem-assets-on-indesign-page
                                         css
                                                     style.css
                                         CSXS
                                                     manifest.xml
                                         html
                                                     place-aem-assets.html
                                         img
                                                     txt.png
                                         js
                                                     aem-service.js
                                                     init-service.js
                                                     place-controller.js
                                                     CSInterface-5.2.js
                                         jsx
                                                     place-assets.jsx
                                         lib
                                                     exmancmd_win
                                                     experience-aem-cep.p12
                                                     ZXPSignCmd
                                         .debug
                                         build.xml

2) Debugging Panels:

                a) Debug url for the panel Place AEM Assets as specified in .debug file is http://localhost:8098/ (available only when the panel is open in InDesign).

                    Check this post for detailed instructions on how to code & debug CEP panels (MAC and Windows)

<?xml version="1.0" encoding="UTF-8"?>
<ExtensionList>
    <Extension Id="com.experience.aem.cep.idsn.place">
        <HostList>
           <Host Name="IDSN" Port="8098"/>
        </HostList>
    </Extension>
</ExtensionList>

                b) Logging available in C:\Users\<user>\AppData\Local\Temp\CEP6-IDSN.log. Default is INFO, for debugging make sure you have the PlayerDebugMode set to 1 and LogLevel 4 (DEBUG) in

                          MAC - /Users/<user>/Library/Preferences/com.adobe.CSXS.6.plist
                          Windows registry key  - Computer\HKEY_CURRENT_USER\Software\Adobe\CSXS.6




                c) ZXP when installed using ExManCmd gets installed to C:\Program Files (x86)\Common Files\Adobe\CEP\extensions (Windows)

3) CSXS/manifest.xml file is required for every extension and provides necessary configuration information for the extension

<Resources>
     <MainPath>./html/place-aem-assets.html</MainPath>
     <ScriptPath>./jsx/place-assets.jsx</ScriptPath>
     <CEFCommandLine>
         <Parameter>--enable-nodejs</Parameter>
         <Parameter>--mixed-context</Parameter>
     </CEFCommandLine>
</Resources>

          a) #2 specifies the home page/splash screen of the CEP html extension

          b) #3 contains the path to file containing extendscript logic for interacting with the host, here InDesign (to create document and place assets on page)

          c) #4 to #7 direct CEP engine to make nodejs module available for the extension panel (used for upload/download of relatively large assets in chunks eg. to download a 1 GB image from AEM)

4) Place AEM Assets extension is a SPA (Single Page Application) using angularjs for building the application and give it dynamic behavior, so the single html page place-aem-assets.html consists of angular directives and controller to provide login screen, show search page etc.

<!DOCTYPE html>
<html lang="en" ng-app="SearchAEM">

<head>
    <meta charset="utf-8">

    <title>Place AEM Assets</title>

    <link rel="stylesheet" href="../css/style.css">
</head>

<body>
<div ng-controller="placeController">
    <div class="sign-in" ng-show="showLogin">
        <div>
            <h3>DIGITAL ASSET MANAGEMENT</h3>
        </div>
        <div>
            <label>User Name</label>
            <input type="text" ng-model="j_username" ng-enter="login()"/>
        </div>
        <div>
            <label>Password</label>
            <input type="password" ng-model="j_password" ng-enter="login()"/>
        </div>
        <div>
            <label>DAM Host</label>
            <input type="text" value="{{damHost}}" ng-model="damHost" ng-enter="login()"/>
        </div>

        <button type="button" ng-click="login()">Sign In</button>
    </div>

    <div ng-show="!showLogin">
        <div class="top">
            <div class="top-left">
                <input type="text" placeholder="AEM PDF Upload Path" ng-model="uploadPath"/>
                <input type="text" placeholder="Search text" ng-model="term" ng-enter="search()"/>
            </div>
            <div class="top-right">
                <button ng-click="search()">Search</button>
            </div>
        </div>
        <div class="results">
            <div class="result-block" ng-class="{ selected : result.selected } "
                 ng-repeat="result in results" ng-click="select(result)">
                <div>
                    <img ng-src="{{result.imgPath}}"/>
                </div>
                <div>
                    {{result.name}}
                </div>
            </div>
        </div>
        <div class="bottom">
            <div class="bottom-left" ng-show="results.length > 0">
                <button ng-click="place()">Place</button>
            </div>
            <div class="bottom-right">
                <button ng-click="generatePDFAndUpload()">Generate PDF & Upload</button>
            </div>
        </div>
    </div>
</div>

<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.js"></script>
<script src="../js/CSInterface-5.2.js"></script>
<script src="../js/init-service.js"></script>
<script src="../js/aem-service.js"></script>
<script src="../js/place-controller.js"></script>
</body>
</html>

5) The necessary modules and services are defined in js/init-service.js
'use strict';

(function () {
    var underscore = angular.module('underscore', []);
    underscore.factory('_', function () {
        return window._;
    });

    var cep = angular.module('cep', []);
    cep.service('csi', CSInterface);
    cep.factory('cep', ['$window', function ($window) {
        return $window.cep;
    }]);
    cep.factory('fs', ['cep', function (cep) {
        return cep.fs;
    }]);
    cep.factory('nfs', ['cep', function (cep) {
        return require("fs");
    }]);
    cep.factory('nhttp', function () {
        return require("http");
    });
    cep.factory('nqs', function () {
        return require('querystring')
    });
    cep.factory('nbuffer', function () {
        return require('buffer');
    });
}());

6) js/aem-service.js defines all the necessary services and functions for interacting with AEM (login, search, download, upload etc.)

                     a) Use CSInterface.evalScript() function to execute extend script functions in the host engine (InDesign) eg. #42 EAEM.placeAssets(), #59 EAEM.exportAsPDF() ES functions

                     b) #95 loginWithNJS() for AEM login, read the login_token from cookies (#122), get the csrfToken (#132) and make them available for other services (search, download, upload etc)
                         by setting in angular $rootScope (#130)

                     c) #159 downloadWithNJS() for downloading large files in chunks (tested with files upto 10GB)

                     d) #220 uploadWithNJS() to upload generated PDFs in 5MB chunks (utilizing AEM chunk upload feature)

                     e) #307 SearchService() with necessary functions to search for assets in AEM using Query Builder

'use strict';

(function () {
    var aem = angular.module('aem', ['underscore', 'cep']);
    aem.service('aemService', AEMService);
    aem.factory('searchService', SearchService);

    AEMService.$inject = [ '_', 'csi', 'fs', '$http', '$rootScope' ,'nhttp', 'nqs', 'nfs', 'nbuffer', '$q' ];

    function AEMService(_, csi, fs, $http, $rootScope, nhttp, nqs, nfs, nbuffer, $q){
        return {
            getFilename: getFilename,
            loginWithNJS: loginWithNJS,
            appendLoginToken: appendLoginToken,
            getDownloadPath: getDownloadPath,
            downloadWithNJS: downloadWithNJS,
            uploadWithNJS: uploadWithNJS,
            placeAssets: placeAssets,
            generatePDF: generatePDF
        };

        function isCEPError(error){
            return _.isEmpty(error) || (error.toUpperCase() == "ERROR");
        }

        function placeAssets(filePaths) {
            if (_.isEmpty(filePaths)) {
                return $q.when({});
            }

            var deferred = $q.defer();

            function handler(result) {
                if (isCEPError(result)) {
                    deferred.reject("Error placing assets");
                    return;
                }

                deferred.resolve(result);
            }

            csi.evalScript("EAEM.placeAssets('" + _.values(filePaths).join(",") + "')", handler);

            return deferred.promise;
        }

        function generatePDF() {
            var deferred = $q.defer();

            function handler(result) {
                if (isCEPError(result)) {
                    deferred.reject("Error generating PDF");
                    return;
                }

                deferred.resolve(result);
            }

            csi.evalScript("EAEM.exportAsPDF()", handler);

            return deferred.promise;
        }

        function getFilename(path) {
            path = path ? path.replace(/\\/g, '/') : '';
            return path.substring(path.lastIndexOf('/') + 1);
        }

        function getDownloadPath(){
            var folderPath = csi.getSystemPath(SystemPath.MY_DOCUMENTS) + "/eaem";
            fs.makedir(folderPath);

            return folderPath;
        }

        function getHostPort(host){
            var arr = [];

            if(host.indexOf("/") >= 0){
                host = host.substring(host.lastIndexOf("/") + 1);
            }

            if(host.indexOf(":") < 0){
                arr.push(host);
                arr.push("80")
            }else{
                arr.push(host.split(":")[0]);
                arr.push(host.split(":")[1]);
            }

            return arr;
        }

        //login with nodejs to capture login cookie
        function loginWithNJS(username, password, damHost){
            var hp = getHostPort(damHost);

            if(!_.isEmpty($rootScope.dam)){
                return $q.when($rootScope.dam);
            }

            var deferred = $q.defer(), dam = { host : damHost };

            var options = {
                hostname: hp[0],
                port: hp[1],
                path: "/libs/granite/core/content/login.html/j_security_check",
                headers: {
                    'Content-type': 'application/x-www-form-urlencoded'
                },
                method: 'POST'
            };

            var req = nhttp.request(options, function(res) {
                var cookies = res.headers["set-cookie"];

                _.each(cookies, function(cookie){
                    if(cookie.indexOf("login-token") == -1){
                        return;
                    }

                    dam.loginToken = cookie.split('login-token=')[1];
                });

                if(_.isEmpty(dam.loginToken)){
                    deferred.reject("Trouble logging-in, Invalid Credentials?");
                    return;
                }

                $rootScope.dam = dam;

                $http.get( appendLoginToken(dam.host + '/libs/granite/csrf/token.json')).then(function(data){
                    dam.csrfToken = data.data.token;
                    deferred.resolve(dam);
                })
            });

            req.on('error', function(e) {
                deferred.reject("Trouble logging-in, Invalid Credentials?");
            });

            var data = nqs.stringify({
                _charset_: "UTF-8",
                j_username: username,
                j_password: password,
                j_validate: true
            });

            req.write(data);
            req.end();

            return deferred.promise;
        }

        function appendLoginToken(url){
            return url + (url.indexOf("?") == -1 ? "?" : "&") + "j_login_token=" + $rootScope.dam.loginToken;
        }

        function downloadWithNJS(damPaths){
            if(_.isEmpty(damPaths)){
                return $q.when({});
            }

            damPaths = _.uniq(damPaths);

            var deferred = $q.defer(), filePaths = {},
                count = damPaths.length, dam = $rootScope.dam;

            _.each(damPaths, handler);

            return deferred.promise;

            function handler(damPath){
                damPath = decodeURIComponent(damPath);

                var url = appendLoginToken(dam.host + damPath),
                    filePath = getDownloadPath() + "/" + getFilename(damPath);

                if (nfs.existsSync(filePath)) {
                    nfs.unlinkSync(filePath);
                }

                var file = nfs.openSync(filePath, 'w');

                var req = nhttp.get(url, function(res) {
                    if(res.statusCode == 404){
                        handle404(damPath);
                        return;
                    }

                    res.on('data', function(chunk) {
                        nfs.writeSync(file, chunk, 0, chunk.length);
                    });

                    res.on('end', function() {
                        nfs.closeSync(file);

                        count--;

                        filePaths[damPath] = filePath;

                        if(count != 0){
                            return;
                        }

                        deferred.resolve(filePaths);
                    });
                });

                req.on('error', function(e) {
                    deferred.reject("Error downloading file");
                });
            }

            function handle404(damPath){
                alert("Asset Not Found - " + damPath);
            }
        }

        function uploadWithNJS(localPath, damFolderPath){
            if(_.isEmpty(localPath) || _.isEmpty(damFolderPath)){
                return $q.when( { "error" : "Empty paths"} );
            }

            var BUFFER_SIZE =  5 * 1024 * 1024, // 5MB
                dam = $rootScope.dam,
                uploadPath = appendLoginToken(dam.host + damFolderPath + ".createasset.html"),
                file = nfs.openSync(localPath, 'r'),
                deferred = $q.defer();

            readNextBytes(0);

            return deferred.promise;

            function readNextBytes(offset){
                var buffer = nbuffer.Buffer(BUFFER_SIZE, 'base64'),
                    bytes = nfs.readSync(file, buffer, 0, BUFFER_SIZE, null),
                    complete = false;

                if (bytes < BUFFER_SIZE) {
                    buffer = buffer.slice(0, bytes);
                    complete = true;
                }

                uploadBlob(getBlob(buffer), offset, complete);
            }

            function uploadBlob(blob, offset, complete) {
                var fd = new FormData();

                fd.append('file', blob);
                fd.append("fileName", getFilename(localPath));
                fd.append("file@Offset", offset);
                fd.append("file@Length", 0);
                fd.append("file@Completed", complete);
                fd.append("_charset_", "utf-8");

                return $http.post(uploadPath, fd, {
                    transformRequest: angular.identity, //no transformation return data as-is
                    headers: {
                        'CSRF-Token' : dam.csrfToken,
                        'Content-Type': undefined //determine based on file type
                    }
                }).then(function () {
                    if (complete) {
                        nfs.closeSync(file);
                        deferred.resolve(damFolderPath + "/" + getFilename(localPath));
                        return;
                    }
                    readNextBytes(offset + BUFFER_SIZE);
                }, failure);

                function failure() {
                    nfs.closeSync(file);
                    alert("Error upoading");
                }
            }

            function getBlob(fileOrBytes){
                var bytes = fileOrBytes.data ? atob(decodeURIComponent(escape(fileOrBytes.data)).replace(/\s/g, ''))
                    : fileOrBytes;

                var bArrays = [];
                var SLICE_LEN = 1024, end, slice, nums;

                for (var offset = 0; offset < bytes.length; offset = offset + SLICE_LEN) {
                    end = offset + SLICE_LEN;
                    slice = bytes.slice(offset, end < bytes.length ? end : bytes.length);
                    nums = new Array(slice.length);

                    for (var i = 0; i < slice.length; i++) {
                        nums[i] = fileOrBytes.data ? slice.charCodeAt(i) : slice[i];
                    }

                    bArrays.push(new Uint8Array(nums));
                }

                return new Blob(bArrays, {
                    type: "application/octet-binary"
                });
            }
        }
    }

    SearchService.$inject = [ '_', '$http', '$rootScope' ];

    function SearchService(_, $http, $rootScope){
        return function (defaults) {
            this.aem = "http://localhost:4502";
            this.params = _.extend( { j_login_token : $rootScope.dam.loginToken }, defaults);
            this.numPredicates = 0;

            this.host = function(aem){
                this.aem = aem;
                return this;
            };

            this.fullText = function (value) {
                if (!value) {
                    return this;
                }

                this.params[this.numPredicates + '_fulltext'] = value;
                this.numPredicates++;

                return this;
            };

            this.http = function(){
                var builder = this;

                return $http({
                    method: 'GET',
                    url: builder.aem + "/bin/querybuilder.json",
                    params: builder.params
                });
            }
        }
    }
}());

7) Angular controller placeController for binding the logic to html page is defined in js/place-controller.js

'use strict';

(function () {
    var app = angular.module('SearchAEM', ['aem']);
    app.directive('ngEnter', ngEnterFn);
    app.controller('placeController', PlaceController);

    function ngEnterFn(){
        return function(scope, element, attrs) {
            element.bind("keydown keypress", function(event) {
                if (event.which === 13) {
                    scope.$apply(function() {
                        scope.$eval(attrs.ngEnter);
                    });

                    event.preventDefault();
                }
            });
        };
    }

    PlaceController.$inject = [ '$scope', 'aemService', 'searchService', '$http', 'csi', 'cep' ];

    function PlaceController($scope, aemService, searchService, $http, csi, cep){
        $scope.damHost = "localhost:4502";
        $scope.showLogin = true;

        var searchDefaults = {
            'path': "/content/dam",
            'type': 'dam:Asset',
            'orderby': '@jcr:content/jcr:lastModified',
            'orderby.sort': 'desc',
            'p.hits': 'full',
            'p.nodedepth': 2,
            'p.limit': 25,
            'p.offset': 0
        };

        $scope.login = login;

        $scope.search = search;

        $scope.select = select;

        $scope.place = place;

        $scope.generatePDFAndUpload = generatePDFAndUpload;

        function login() {
            if (!$scope.j_username || !$scope.j_password || !$scope.damHost) {
                alert("Enter credentials");
                return;
            }

            $scope.damHost = $scope.damHost.trim();

            if ($scope.damHost.indexOf("http://") == -1) {
                $scope.damHost = "http://" + $scope.damHost;
            }

            function success(){
                $scope.showLogin = false;
            }

            function error(message){
                alert(message);
            }

            aemService.loginWithNJS($scope.j_username, $scope.j_password, $scope.damHost)
                    .then(success, error);
        }

        function search(){
            if (!$scope.term) {
                alert("Enter search term");
                return;
            }

            $scope.results = [];

            var mapHit = function(hit) {
                var result;

                result = {};

                result.selected = false;
                result.name = aemService.getFilename(hit["jcr:path"]);
                result.path = hit["jcr:path"];
                result.imgPath = aemService.appendLoginToken($scope.damHost + hit["jcr:path"]
                                        + "/jcr:content/renditions/cq5dam.thumbnail.140.100.png");
                result.format = hit["jcr:content"]["metadata"]["dc:format"];

                if(result.format == "text/html"){
                    result.imgPath = "../img/txt.png";
                }

                return result;
            };

            new searchService(searchDefaults).host($scope.damHost)
                .fullText($scope.term)
                .http()
                .then(function(resp) {
                    $scope.results = _.compact(_.map(resp.data.hits, mapHit));
                });
        }

        function select(result){
            result.selected = !result.selected;
        }

        function place(){
            var toDownload = _.reject($scope.results, function(result){
                return !result.selected;
            });

            aemService.downloadWithNJS(_.pluck(toDownload, 'path'))
                        .then(setDownloadedPaths)
                        .then(aemService.placeAssets)
                        .then(aemService.uploadWithNJS)
        }

        function setDownloadedPaths(filePaths){
            _.each($scope.results, function(result){
                result.localPath = filePaths[result.path] || '';
            });

            return filePaths;
        }

        function generatePDFAndUpload(){
            if(_.isEmpty($scope.uploadPath)){
                alert("Enter PDF upload location in AEM");
                return;
            }

            aemService.generatePDF()
                        .then(upload)
                        .then(function(damFilePath){
                            alert("Uploaded - " + damFilePath);
                        });

            function upload(pdfPath){
                return aemService.uploadWithNJS(pdfPath, $scope.uploadPath);
            }
        }
    }
}());

8) InDesign extend script logic for creating a new document and place the downloaded assets on pages is defined in jsx/place-assets.jsx
(function () {
    if (typeof EAEM == "undefined") {
        EAEM = {
            COLUMNS_PER_SPREAD: 3,
            ROWS_PER_SPREAD: 2
        };
    }

    function collectionToArray(theCollection) {
        return (theCollection instanceof Array) ? theCollection.slice(0)
            : theCollection.everyItem().getElements().slice(0);
    }

    function getContainerAssetCount(spreadOrGroup){
        var pageItems = collectionToArray(spreadOrGroup.pageItems),
            count = 0;

        for (var pageItemIdx = 0; pageItemIdx < pageItems.length; pageItemIdx++) {
            var pageItem = pageItems[pageItemIdx];

            if (pageItem instanceof Group) {
                count = count + getContainerAssetCount(pageItem);
            }else {
                count++;
            }
        }

        return count;
    }

    function getPlaceSpread(document){
        var lastSpread = document.spreads.lastItem();

        var count = getContainerAssetCount(lastSpread),
            spread;

        if (count < (EAEM.COLUMNS_PER_SPREAD * EAEM.ROWS_PER_SPREAD)) {
            spread = lastSpread;
        }else{
            spread = document.spreads.add();
        }

        return spread;
    }

    function getNextGridPos(spread) {
        var gridPos = {
            row: 0,
            column: 0
        };

        var count = getContainerAssetCount(spread);

        if(count > 0){
            gridPos.row = Math.floor(count / EAEM.COLUMNS_PER_SPREAD);
            gridPos.column = count % EAEM.COLUMNS_PER_SPREAD;
        }

        return gridPos;
    }

    function createPageItem(spread) {
        var rect = spread.textFrames.add();

        var y1 = 0; // upper left  Y-Coordinate
        var x1 = 0; // upper left  X-Coordinate
        var y2 = 275; // lower right Y-Coordinate
        var x2 = 160; // lower right X-Coordinate

        rect.geometricBounds = [ y1 , x1 , y2 , x2 ];

        return rect;
    }

    function movePageItem(document, spread, gridPos, rect){
        var marginTop = document.marginPreferences.top;
        var marginBottom = document.marginPreferences.bottom;
        var marginLeft = document.marginPreferences.left;
        var marginRight = document.marginPreferences.right;

        var spreadLeftTop = spread.pages.firstItem().resolve(
            AnchorPoint.TOP_LEFT_ANCHOR, CoordinateSpaces.SPREAD_COORDINATES)[0];
        var spreadRightBottom = spread.pages.lastItem().resolve(
            AnchorPoint.BOTTOM_RIGHT_ANCHOR, CoordinateSpaces.SPREAD_COORDINATES)[0];

        var spreadWidth = spreadRightBottom[0] - spreadLeftTop[0] - marginLeft - marginRight;
        var spreadHeight = spreadRightBottom[1] - spreadLeftTop[1] - marginTop - marginBottom;

        var stepH = spreadWidth / EAEM.COLUMNS_PER_SPREAD;
        var stepV = spreadHeight / EAEM.ROWS_PER_SPREAD;

        var xPos = spreadLeftTop[0] + gridPos.column * stepH + marginLeft + 10;
        var yPos = spreadLeftTop[1] + gridPos.row * stepV + marginTop + 25;

        var rectTop = rect.resolve(AnchorPoint.TOP_LEFT_ANCHOR, CoordinateSpaces.SPREAD_COORDINATES)[0];

        var deltaX = xPos - rectTop[0];
        var deltaY = yPos - rectTop[1];

        rect.move(null,[deltaX, deltaY]);
    }

    function placeImage(rect, pdfPath){
        rect.contents = "";
        rect.contentType = ContentType.UNASSIGNED;
        rect.place(pdfPath);
        rect.fit(FitOptions.PROPORTIONALLY);
    }

    EAEM.placeAssets = function(commaSepPaths){
        var result = "ERROR", document,
            units = app.scriptPreferences.measurementUnit;

        try{
            app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

            if(app.documents.length == 0){
                document = app.documents.add();
            }else{
                document = app.activeDocument;
            }

            var assetsArray = commaSepPaths.split(",");

            for(var i = 0; i < assetsArray.length; i++){
                var spread = getPlaceSpread(document);

                var gridPos = getNextGridPos(spread);

                var rect = createPageItem(spread);

                movePageItem(document, spread, gridPos, rect);

                placeImage(rect, assetsArray[i]);
            }

            result = "SUCCESS";
        }catch(err){
            result = "ERROR";
        }

        app.scriptPreferences.measurementUnit = units;

        return result;
    };

    EAEM.exportAsPDF = function(){
        var document, result = "ERROR";

        try{
            if(app.documents.length == 0){
                document = app.documents.add();
            }else{
                document = app.activeDocument;
            }

            var pdfPath = Folder.myDocuments.fsName.replace(/\\/g, '/') + "/eaem/" + document.name + ".pdf";

            document.exportFile(ExportFormat.pdfType, new File(pdfPath), false,
                        app.pdfExportPresets.item("[High Quality Print]"));

            result = pdfPath;
        }catch(err){
            result = "ERROR";
        }

        return result;
    };
})();



2 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. I have one question, that is If I will click logout in AEM panel, Links panel shows the image path is missing or $placeholder at the beginning instead of URL?

    ReplyDelete