1

I've got an odd query where I need to take all the objects on a certain layer and put them each on a separate new layer so they can be exported as individual PDFs (and converted to png). I've found a script that does this:

var doc = app.activeDocument;
var myLayer = doc.layers.item("Answers");
 
for (var i = myLayer.pageItems.length - 1; i >= 1; i--) {
  var newLayer = doc.layers.add();
  myLayer.pageItems[i].itemLayer = newLayer;
}

This works great, but the layers are just named sequentially. I'm wondering if it's possible to have the new layers named with the page number that the object is on so instead of

Layer 1
Layer 2
etc.

I get:

Page1-1
Page1-2
Page1-3
Page2-1
Page2-2
etc

Is that doable? I've tried finding scripts to get the page number but I can't get it to work (I wish I knew more about Javascript!).

I'm using PageExporterUtility to export all the individual layers as PDFs but because there are many pages that have nothing on a lot of the new layers, I'm getting a lot of blank pages created which I have to sort through and delete manually. I'm thinking if the layers are named with the page numbers I can export just the layers I need for a given page.

I know it's a weird request, any help would be much appreciated.

Thanks, Duncan

Edit: The export process I'm currently using with this is Page Exporter Utility 5.0.1 (here). This exports each layer in the doc as a separate PDF per page. Then I run a Photoshop batch to make them 5500px wide and a png, which is what I need.

  • I think the error is in the script and in what it exports. If it creates new layers for each object on let's say page one, then does the same thing for page two, the page one layers will also be on page two (as layers are global) and you would get those blank exported pages that you describe. If I understand your requirements correcty, then it would make much more sense to export each individual object directly to a (page sized) png and would skip the step of inserting new layers. Or do I misunderstand something? – mdomino Jul 15 at 13:11
  • No, you're not misunderstanding – that would be ideal! The only reason I was going with layers was because I knew I could export them separately, but if there's a way of exporting every object on one layer to an individual page-sized png, that would be amazing. – Duncan Jul 15 at 13:20
  • Still not quite clear, do you need to A) export each and every object individually or do you need to B) export all objects that are on one layer together? – mdomino Jul 15 at 13:22
  • A – Individually. For example, there are 10 objects on a page, all on the same layer. I need 10 pngs. Each png will be the size of the page and have one of the objects in the correct position. – Duncan Jul 15 at 13:23
  • Ok, I think a mixture of my initial suggestion and the original script might be best. The script could do the following: create an export layer, make all other layers non-printable. Then a loop for each page item that does this: duplicate the page item to the export layer, export the document to png, delete the duplicated item, continue with the next item. In the process make sure to give this some sequential naming, either "page1-1.png, page1-2.png, page2-1.png..." or depending on the requirements just "1.png, 2.png, 3.png..." – mdomino Jul 15 at 13:33
1

Ok, here is a solution that should solve your issue or at the very least send you on your way. As I described in the comments below the post, this sets up a layer that is dedicated for exporting, duplicates one item after the other to this layer, exports and removes the element again:

// set the preferences for the PNG export
var pngPrefs = app.pngExportPreferences;

pngPrefs.pngExportRange = PNGExportRangeEnum.EXPORT_RANGE;
pngPrefs.pngQuality = PNGQualityEnum.MAXIMUM;
pngPrefs.exportResolution = 300;
// etc.; for all possible settings see
// https://www.indesignjs.de/extendscriptAPI/indesign8/#PNGExportPreference.html

var doc = app.activeDocument;

// loop over all layers and make them non-printable

for (var i = 0; i < doc.layers.length; i++) {
  doc.layers[i].printable = false;
}


// set up layers
var exportLayer = doc.layers.add();
var sourceLayer = doc.layers.item("Answers");


// loop over each page item, duplicate it to the export layer and then export it

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

  // duplicate the page item
  var dupItem = pageItem.duplicate(exportLayer);

  // set up export file
  var expFile = File('~/Desktop/output/page' +
      pageItem.parentPage.name + '-' + i + '.png');

  // set which page to export
  pngPrefs.pageString = pageItem.parentPage.name;

  // export the document
  doc.exportFile(ExportFormat.PNG_FORMAT, expFile);

  // remove the duplicate item
  dupItem.remove();
}

Edit: To avoid the error with page items on the pastboard, you can quickly check, if the item has a valid parent page. You could add this snippet below the var pageItem ... line:

if(!pageItem.parentPage) continue;

This basically tells the script to skip the current page item and continue with the next.

| improve this answer | |
  • I haven't tried this, but it looks good. If you revert each layers printable property to its initial state and remove the exportLayer in the end the script could be run without altering the document at all. – Wolff Jul 15 at 20:54
  • 1
    Yup. I left this as an exercise for the reader. ;) Another simple way would be to wrap it into a function and just undo it in the user interface, like you did in your post. – mdomino Jul 15 at 20:56
  • 2
    Thank you both so much! I'll have a go at wrapping it into a function with the undo command, that looks neat. One issue though, I'm getting an error message with this script on line 33 (var expFile = File('~/Desktop/output/page' +), Error Number: 21, Error String: Null is not an object. I've tried googling to work it out myself but I'm struggling. Sorry! – Duncan Jul 16 at 8:22
  • Solved it. I had something in the paste-up margin which I hadn't spotted, so that was throwing the error. Additional question, is there a way to control the order in which it outputs, so it starts at the top of the page and works down? If not, no worries, would just take out another step in the process. – Duncan Jul 16 at 8:38
  • 1
    Regarding the error, see my edit. Regarding the sorting: it could be done, but you would first need to sort all page items according to their y-position and then loop over the sorted items. Look into JS sorting functions. The property you would need to sort by is the page item's geometricBounds[0] that describes the y-coordinate of the page item's top bound. – mdomino Jul 16 at 10:26
0

How about just adding as many new layers as the maximum number of items on a page? That way no page would have empty layers.

// main function
function distributeItemsToLayers() {
    // active document
    var doc = app.activeDocument;
    // source layer
    var sourceLayer = doc.layers.item("source layer name");
    // array for new layers
    var newLayers = [];
    // loop through pages
    for (var i = 0; i < doc.pages.length; i++) {
        // page
        var page = doc.pages[i];
        // array for items on page in the source layer
        var items = [];
        // loop through items on page
        for (var j = 0; j < page.pageItems.length; j++) {
            // item on page
            var item = page.pageItems[j];
            // check if item is on source layer
            if (item.itemLayer === sourceLayer) {
                // add item to array of items on source layer
                items.push(item);
            }
        }
        // loop through items on source layer
        for (var j = 0; j < items.length; j++) {
            // item on source layer
            var item = items[j];
            // check if a new layer exists for this number
            if (newLayers.length < j + 1) {
                // add new layer for this number
                newLayers.push(doc.layers.add());
            }
            // set item layer to corresponding new layer
            item.itemLayer = newLayers[j]; 
        }        
    }
}
// run main function as one undoable action
app.doScript(distributeItemsToLayers, ScriptLanguage.javascript, undefined, UndoModes.ENTIRE_SCRIPT, 'Distribute Items To Layers');
| improve this answer | |
  • The script is commented so it should be self explanatory, but feel free to ask for clarifications. I might add some description later. – Wolff Jul 15 at 14:02
  • Thanks, I'll give it a go. And thanks for commenting the script, that's really useful and makes it a lot easier to learn what it's doing rather than just copying it and assuming there must be some sort of magic involved. – Duncan Jul 15 at 14:11
  • Hmm, I said "no page would have empty layers". That's not correct. There will be empty layers on some pages. Just not as many as before. Sigh. – Wolff Jul 15 at 17:12
  • Yes, there are blank pages, but fewer than before and they're grouped together so deleting them is far easier. – Duncan Jul 15 at 17:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.