javascript - 如何在 acrobat PDF 中使用 javascript 创建嵌套 OCG/图层并将其附加到父级?

标签 javascript pdf adobe layer acrobat

我发帖的一半原因是在这里放一些对其他人有用的东西,因为网上几乎没有关于 PDF OCG/图层的好东西,但我还需要一些帮助才能使其正常工作。 90% 好,还需要完成 10%。

我有一个图层/OCG 列表,我希望其中一些可以嵌套。我想关闭整个组。我可以通过分成 2 个以上数组并将我想要嵌套的列表插入到基本列表中来嵌套层/OCG。

如果嵌套数组的第一个元素是字符串,则会在树结构中创建一个组。我可以单击“+”来打开和关闭该组,但没有“眼睛”框来打开或关闭该组的可见性。

如果第一个元素不是字符串,它只是使用数组中的前一个元素作为父元素,并包含文件夹图标和可见性“眼睛”以供单击,但单击时“眼睛将关闭父层/” OCG,它不会关闭底层嵌套层/OCG。

如果我知道如何正确创建数据,这个问题可能会得到解决。或者也许如何设置父 OCG。

有什么想法吗?


通过放置以下内容来安装此脚本: c:\Program Files (x86)\Adobe\Acrobat 10.0\Acrobat\Javascripts

它将在“编辑”或“文档”->“编辑”下创建一个菜单项

示例 PDF 为 here 767k 下载本地以查看图层。


/********************************
RSCivilTools by Andrew Binning
Version 01, 2-15-2012
********************************/
//Some code by:
// InDesign Fixups by Dave Merchant  - Creative Commons Share-alike license
// version 02, November 2010
// http://www.uvsar.com/go/indesignfixups

//create new submenu for the Acrobat 8/9 or X menus
//Determine version, assign menu location
var menuParent = (app.viewerVersion<10)? "DocumentProcessing":"Edit";
//Add the menu
app.addSubMenu({ cName:"RSCivilTools", cUser:"RSCivil Tools", cParent:menuParent, nPos:((app.viewerVersion<10)? 0:7) });
//Create a nested layer (tailored code for my specific Document.
app.addMenuItem({ cName:"RSCcreateNest", cUser:"Create Nest", cParent:"RSCivilTools", 
          cExec:"createNest();",
          cEnable:"event.rc = (event.target != null);", nPos:0 });
//Promote sub layers - Unravel the nests
app.addMenuItem({ cName:"RSCpromote", cUser:"Undo Nest", cParent:"RSCivilTools",
          cExec:"promoteOCG_handler(event.target);",
          cEnable:"event.rc = (event.target != null);", nPos:1 });
//Unlist Guides and Grids layer (from Adobe IN-Design)
app.addMenuItem({ cName:"RSCremGAG", cUser:"Unlist 'Guides and Grids'", cParent:"RSCivilTools",
          cExec:"removeGAG(event.target);",
          cEnable:"event.rc = (event.target != null);", nPos:2 });
//Set up layers ( this is tailored code for my specific Document)
app.addMenuItem({ cName:"RSCsetStates", cUser:"Set Layers", cParent:"RSCivilTools",
          cExec:"setStates();",
          cEnable:"event.rc = (event.target != null);", nPos:3 });
//Toggle this list of layers on and off (tailored code for my specific Document.
app.addMenuItem({ cName:"RSCtoggleCityLimits", cUser:"Toggle City Limits", cParent:"RSCivilTools",
          cExec:"toggleCityLimits();",
          cEnable:"event.rc = (event.target != null);", nPos:4 });
//Link to the company website         
app.addMenuItem({ cName:"RSCsite", cUser:"Website", cParent:"RSCivilTools", 
          cExec:"app.launchURL('http://rscivil.com');", nPos:5 });

//Add a button for this function - Add from Quick Tools 3rd party addons
app.addToolButton({
        cName: "RSCcreateNestButton",
        cExec: "createNest();",
        cTooltext: "Create Nest",
        cEnable: true,
        nPos: 0,
        cLabel: "Create Nest"
        })
//Add a button for this function - Add from Quick Tools 3rd party addons
app.addToolButton({
        cName: "promoteLayers",
        cExec: "promoteOCG_handler(event.target);",
        cTooltext: "Undo Nest",
        cEnable: true,
        nPos: 1,
        cLabel: "Undo Nest"

        })

//Creates a nested layer from a predetermined list
function createNest(){
    var layers = this.getOCGs();
    var newOrder = new Array();
    var cityLimits = new Array();
    var comps = new Array();

    /*******************************************************
    This is where I need help.
    By not setting the first element to a String it does not name the group. Instead it seems to attach it as a child to the previous element in the array.
    This is fine, except that when you turn off said parent it does not turn off the sub layers/OCGs.
    If I could figure out how to create an object and set it up as an element before my inserted array it might help.
    *******************************************************/
    //Commented for testing - Set first element of the array to a descriptive string (this will be the name of the nested group) 
    //cityLimits[0] = "City Limits";
    //Set first element of the array to a descriptive string (this will be the name of the nested group)
    comps[0] = "Comps";

    //Separate all layers/OCGs containing "CityLimits|" or "COMP" from the original list of layers/OCGs
    for (var i=0,j=0,k=0,l=1; i<layers.length; i++){
        if(layers[i].name.substr(0,11)==="CityLimits|"){
            cityLimits[j] = layers[i];  //separate CityLimits OCG
            j++;
        }
        else if(layers[i].name.substr(0,4)==="COMP"){
            comps[l] = layers[i];   //separate COMP OCG
            l++;
        }
        else{
            newOrder[k] = layers[i];    //cram everything else into a new array
            k++;
        }
    }
    //Insert the cityLimits array into the newOrder array at position 5, do not remove any elements (the element before this arbitrarily becomes the parent, but does not work correctly)
    newOrder.splice(5,0,cityLimits);
    //Append the comps array to the end of the newOrder array
    newOrder[newOrder.length] = comps;
    //set the newOrder array as the OCGOrder.
    this.setOCGOrder(newOrder);
}
//Code by Dave Merchant
//Handler for promoting OCGs out of nested layers
function promoteOCG_handler(oDoc) {

  var ocgOrder = oDoc.getOCGOrder();
  var hasNest = false;

  if (ocgOrder==null) {
    app.alert( "No layers in current file", 0, 0, "Cannot proceed");
  } else {
    for (var i=0; i<ocgOrder.length; i++) {
       if ((typeof(ocgOrder[i]) == "object") && (ocgOrder[i].length > 0)) hasNest = true;
    }
    if (hasNest)  {
      promoteOCGs(oDoc,ocgOrder);
    } else app.alert( "No nested layers in current file", 0, 0, "Cannot proceed");
  }
}
//Code by Dave Merchant
//Promote/unravel layers/OCG out of nests
function promoteOCGs(oDoc,ocgOrder) {

  // Removes the top-level OCG nest structure from a PDF, promoting all sub-OCGs to the top level.
  // Used to remove the nesting created when a PDF is exported from InDesign with "Create Acrobat Layers" checked.


  var oChk = { cMsg:"Unlist the 'Guides and Grids' layer?", bInitialValue:true, bAfterValue:false};

  //var cMesg = "This action will ungroup all nested layers. IT CANNOT BE UNDONE.\n\nDo you want to continue?";
  //var nRtn = app.alert({ cMsg:cMesg, nIcon:2, nType:2, cTitle:"Promote nested layers", oCheckbox:oChk});
  //if (nRtn == 4) {

    var newOrder = new Array();

    for (var i=0; i<ocgOrder.length; i++) {

     var oType = typeof(ocgOrder[i]);
     var oLeng = ocgOrder[i].length
     if ((oType == "object") && (oLeng > 0)) {      // it's a nest, do the promotions

        for (var j=0; j<oLeng; j++) {
           if ((typeof(ocgOrder[i][j]) == "object") && 
              (!oChk.bAfterValue || (ocgOrder[i][j].name != "Guides and Grids"))) newOrder.push(ocgOrder[i][j]);
        }

     } else if (!oChk.bAfterValue || (ocgOrder[i].name != "Guides and Grids")) newOrder.push(ocgOrder[i]);
    }
    oDoc.setOCGOrder( newOrder );
  //}
}


//Code by Dave Merchant
// Removes the listing for (sub)OCG named "Guides and Grids".
// Does NOT delete the layer, simply hides it from the sidebar display.
function removeGAG(oDoc) {
  var cMesg = "This action will unlist the 'Guides and Grids' layer from the sidebar but will NOT delete the ";
  cMesg += "layer itself. IT CANNOT BE UNDONE.\n\nDo you want to continue?";
  var nRtn = app.alert(cMesg, 2, 2, "Unlist 'Guides and Grids'");
  if (nRtn == 4) {

    var ocgOrder = oDoc.getOCGOrder();
    var newOrder = new Array();

    for (var i=0; i<ocgOrder.length; i++) {

     var oType = typeof(ocgOrder[i]);
     var oLeng = ocgOrder[i].length
     if ((oType == "object") && (oLeng > 0)) {      // it's a nest

        var subObj = new Array();
        for (var j=0; j<oLeng; j++) {
           if ((typeof(ocgOrder[i][j]) == "string") || (ocgOrder[i][j].name != "Guides and Grids")) subObj.push(ocgOrder[i][j]);
        }
        newOrder.push(subObj);

     } else if (ocgOrder[i].name != "Guides and Grids") newOrder.push(ocgOrder[i]);
    }
    oDoc.setOCGOrder( newOrder );
  }
}

//Just a list of layers I want to toggle on or off (document specific)
function togList(name){
    if(name.substr(0,11)==="CityLimits|")
        return true;
    return false;
}
//Just a list of layers I want to set an initial state to off (document specific)
function offList(name){
    var lOff =  new Array();
    lOff[0] = "ADT";
    lOff[1] = "CityLimits|1900";
    lOff[2] = "CityLimits|1910";
    lOff[3] = "CityLimits|1920";
    lOff[4] = "CityLimits|1930";
    lOff[5] = "CityLimits|1940";
    lOff[6] = "CityLimits|1950";
    lOff[7] = "CityLimits|1960";
    lOff[8] = "CityLimits|1970";
    lOff[9] = "CityLimits|1975";
    lOff[10] = "CityLimits|1980";
    lOff[11] = "CityLimits|1985";
    lOff[12] = "CityLimits|1990";
    lOff[13] = "CityLimits|1995";
    lOff[14] = "CityLimits|2000";
    lOff[15] = "CityLimits|2005";
    lOff[16] = "CityLimits|2006";
    lOff[17] = "CityLimits|2007";
    lOff[18] = "CityLimits|2008";
    lOff[19] = "CityLimits|2009";
    lOff[20] = "CityLimits|2010";
    lOff[21] = "CityLimits|2011";
    lOff[29] = "Distance Circles 1";
    lOff[30] = "Distance Circles 2";
    lOff[31] = "landuse|Agriculture";
    lOff[32] = "landuse|Industrial";
    lOff[33] = "Landmark Labels Locations";
    lOff[34] = "landmarks|Locations";

    for (var i=0; i<lOff.length; i++){
        if(lOff[i] === name)
            return true;
    }
    return false;
}

//Checks all layers against a list and toggles them off or on (document specific)
function toggleCityLimits(){
   var layers = this.getOCGs();
    for (var i=0; i<layers.length; i++){
        var tog = true;
        if(togList(layers[i].name)){
            if(layers[i].state)
                tog = false;
            layers[i].state = tog; //toggle layer
        }
    }
}

//Checks all layers against a list and sets the initial state and current state to off (state=visibility) (document specific)
function setStates(){
   var layers = this.getOCGs();
    for (var i=0; i<layers.length; i++){
        var tog = true;
        if(offList(layers[i].name))
            tog = false;
        layers[i].state = tog;      //turn off layer
        layers[i].initState = tog;  //set initial visibilty to off
    }
}

最佳答案

Acrobat 中显示的图层树(上面的代码构建的内容)不一定与 PDF 页面中定义的图层内容树相匹配。
页面内容内的 PDF 图层定义如下:

/OC /layerid /BDC
...
/EMC

在页面内容中,您可以并排放置 2 层:

/OC /layer1id /BDC
...
/EMC
/OC /layer2id /BDC
...
/EMC

但在 Acrobat 的图层 Pane 中,您可以将 Layer2 作为 Layer1 的子级,因为定义此层次结构的/Order 数组独立于页面内容。
为了在隐藏 Layer1(其父级)时自动隐藏 Layer2,必须在页面内容中这样定义它们:

/OC /layer1id /BDC
...
/OC /layer2id /BDC
...
/EMC
/EMC

layer2的内容必须物理包含在layer1中。
出现您的问题是因为页面内容中的所有图层都是并排构建的,而不是子父级的,并且更改/Order 数组不会影响页面内容。
我看到的解决方案,虽然我对 Adob​​e Acrobat JavaScript 不是很熟悉,而且我不知道是否可行,但它是将一个 JavaScript 函数附加到每个父层,该函数在层可见性发生变化时执行,并且也改变了所有子层的可见性。

关于javascript - 如何在 acrobat PDF 中使用 javascript 创建嵌套 OCG/图层并将其附加到父级?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9299757/

相关文章:

javascript - 如何在网站上放置透明 Flash 并保持底层网站可用(焦点、点击、表单提交等)

javascript - 在特定属性值上使用 jQuery 切换(隐藏/显示)<td>

javascript - 在一个有序的标量数组中,给定一个数字,找到前面较小的和后面较大的。

javascript - 如何在浏览器中使用 HTML 查看 pdf 的特定页面?

flash - 如何在 Apple iPad 上运行 Adob​​e AIR 应用程序?

javascript - 在输入字段发生任何变化时调用 jQuery 函数

java - 仅在一页上显示内容

go - golang 中的类型不一致,不能使用 <Type> 作为 *Type

php - 在 php 或 javascript 上自动打印 PDF 脚本

flash - RTMFP 和防火墙/路由器