I'm making an interactive map in Adobe Acrobat using layers. Imagine a map with property lines and I click a bookmark to see the property highlighted. click a different bookmark, highlight (with a layer) a different property.
I've got about 40 layers, and bookmarks for each property or category of properties so that when you click it, it displays just the associated image layer(s).
The problem is, people keep requesting changes to the map. I can't delete layers in Acrobat (?), and when I add a layer, the new layer appears with every single bookmark already set up.
The only way I've figured out to make this work is to basically redo the entire map every time. I want to access document javascript to show/hide layers based on bookmarks, but I'm not sure that's accessible. I'm open to options, anything that would get around redoing from scratch every time.
Adobe Acrobat does allow you to manipulate layers using JavaScript. The only confusing bit you need to know is that layers aren't called layers, but OCGs.
OCG stands for "Optional Content Group", which is a technically correct and completely bonkers way to name these things. But well.
From the Adobe Acrobat JavaScript SDK (which you can access on the Adobe DevNet pages for Acrobat):
function TurnOnOCGsForPage(doc, nPage) {
var ocgArray = doc.getOCGs(nPage);
for (var i=0; i < ocgArray.length; i++)
ocgArray[i].state = true;
}
Related
I'm working with two PDFs that are not identical, but are to have the same operation applied to them.
The first one is generated by Microsoft Office 365 by downloading a Word document as a PDF
The second one is generated by Google Drive by downloading a Google Docs document as a PDF
I'm working with some preliminary code using Aspose to apply the same image to both PDF files using exactly the same code. I'm not inclined to blame the library right away as it is capable of generating the correct output when operating on the Office 365 document:
// note: Anyone familiar with the PDF format itself should have no
// issues inferring the low-level operations being performed here...
fun Page.writeImage(image: InputStream) {
val imageName = resources.images.add(image.inMemory());
val rectangle = rectangleFromTopLeft(0.0, 0.0, 400.0, 200.0);
val matrix = rectangle.defaultMatrix();
contents.add(listOf(
GSave(),
ConcatenateMatrix(matrix),
Do(imageName),
GRestore()
));
}
Regardless of which file I provide, the coordinates for the rectangle and matrix in both these cases remain the same.
For the Office 365 derived PDF, the image is applied to the page as I specify. Where things get weird is when I open the Google Docs derived PDF, the image is applied flipped vertically and at the bottom of the page!
View the four PDF files in their before and after states.
I would love for any PDF experts to perhaps be able to explain to me what's going on here. My initial suspicion is that some prior state or operation in the Google Docs PDF is in effect prior to my image operation.
That said, I'm not familiar enough (yet!) with the PDF spec to pick it out...
I don't know who you should blame, but there is a straightforward reason for the difference.
The Google Docs document has a page stream that begins with:
1 0 0 -1 0 792 cm
This basically does the vertical flipping of the page, the 792 is to compensate and move things back on the page - it should be the height of the page in points.
It does not encapsulate this in a q ... Q pair to do a "save ... restore", which means this matrix is now set for the remainder of all that follows on the page. As you might already know, the PDF specification does not provide a way to reset the page matrix, you can only append to it.
When you add content to the page at the end, your content now inherits this matrix, which is why you see it flipped and at the bottom.
The Microsoft file does not do this and as a result it's handled properly. In this case the matrix remains the identity matrix and you end up with your content where you expected it.
How to fix this? Well, if your library doesn't provide a way to know what the current page matrix is, that's going to be very difficult. It can of course be solved "just for this document" by applying the inverse matrix to cancel out the stupid thing Google did here, but I can imagine this is not the ultimate way to handle this you'd be looking for.
We need to print a pdf document on the page which has predefined fields on it, a formular basically, which fields needs to be filled.
We are using iTextSharp to create pdfs and we use absoulte positioning for elements based on the formular fields positioning. For instance, if the field starts 20mm from left and 20 mm from top I will put data to start at 21mm from the left and 21 mm from top so it fits inside that field. And it works well on my printer.
But my question is, can different printers mess up positioning because of different margins, font sizes, etc... Maybe it will be the same, I am not aware of what differences can different printers bring.
Is it important that user chooses Actual size option when printing pdf?
I need to know what difficulties I can expect, better to know it now then waiting customers calling when this is in production.
The problem you anticipate, exist. It can be avoided by setting a viewer preference.
See How to prevent the resizing of pages in PDF?
You have to set the print scaling to none:
writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE);
That's the line you'll need if you are using iText 5 (writer is an instance of PdfWriter). If you are using iText 7, you can define the viewer preferences like this:
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
PdfViewerPreferences preferences = new PdfViewerPreferences();
preferences.setPrintScaling(PdfViewerPreferencesConstants.NONE);
pdf.getCatalog().setViewerPreferences(preferences);
See Handling events; setting viewer preferences and printer properties.
Of course, end users can always overrule the print scaling in their PDF viewer, but that's their responsibility, not yours.
I know about Doc.SetOCGOrder() and the likes, but apparently the Acrobat API does not provide means to remove layers (aka optional content groups, ocgs), only to hide them from users while leaving them accessible via scripting.
I'm not forced to use Acrobat, in fact I'd prefer a FOSS-solution (or at least freeware) using e.g. pypdf2 or pdftk. edit There is another post using abcpdf, which is unfortunately not free. Is there any way to port that behaviour to Acrobat's JS or pypdf2? Essentially the answer seems to loop through every page's content, which seems to include the layers.
(Concerning merging, I notice pdftk does remove layers when merging multiple files, so one can simple pdftk A=input.pdf B=input.pdf cat A1-end output output.pdf.)
My approach so far: For the relevant layers obtained via GetOCGs() set locked=true and both initState=false and state=false. Then use SetOCGOrder() to remove the layer from the layers view. Unfortunately this is not perfect, since at least in Acrobat DC I can still select "show all layers" in the layers panel, which still shows the layer. One could merge all layers now, but neither did I find an option to achieve that programmatically nor do I believe that would actually remove the hidden layer's elements.
You can't do it programmatically but you can create an Action that will process a folder full of PDF files using Adobe Acrobat. Set the Action to use the PDF Optimizer to discard hidden layers and flatten visible ones. See the graphic.
I want to create a pdf form for two language (Chinese/English) UI, and there's a button(s) or somethings on the form for language switch, is there anyway can make it? and how to do?
thanks!
Thanks for all reply!
Actually I got a sample like this,
PDF Sample
there're two checkbox on the top-left of the form, one is for English UI, the other is Chinese, I just want to know how to make PDF like that sample? (and I don't see any layers on the sample...)
thx
mkl's comment (which he should turn into a full answer, really) already hinted at the option to use different page templates residing in the same file.
Another option you could explore is this:
put the two language versions into 2 different layers (or 'optional content groups' in PDF parlance)
make the visibility of the two layers toggeable
let the user activate that layer which he/she needs.
Layer activation can be handled through normal Acrobat Reader user interface elements.
The layer switching can be made accessible via a "button" on the PDF page too -- but that requires additional JavaScript to be embedded in the PDF (something many people are not particularly keen about).
As Kurt proposed, I make my comment on Frank's answer an answer in its own right:
Actually there is a pdf feature seldomly used nowerdays, page
templates. Thus, those two forms can reside in the same file in
different page templates, and based on some initially present buttons
("English version", ...) the desired form is spawned.
Unfortunately I don't know how to create page templates using some easy-to-use tool, I only came a cross them in the context of integrated PDF signatures (depending on the signature type, page template instantiation is a document change not breaking the signature) and tested them with low-level tools.
Essentially page templates are PDF objects just like page dictionaries of the normal pages, they are not XFA stuff. They merely are not referenced in the pages tree but instead in the name tree.
There is a JavaScript command which creates a visible page based on such a template --- I don't know which anymore; I may be able to find out when I'm back in office next week. This command would have to be bound to the inital language selection button in the file.
The problem will be in switching the static text - PDF does not allow this.
If I were you, I would split the document into two identical forms in the respective languages. You can use bookmarks and links on the first page to navigate to the right part of the document.
Note that it is possible to assign the same field names to the Enlgish/Chinese versions of your fields. This will make it easier to process the submitted form data because the process path would be independent of the chosen language. It will also simplify any JavaScript (validation, summing, etc.) you plan to add.
Creating all the art for a large website often involves a couple dozen 50+mb photoshop files. Frequently, a given module may appear in more than one file.
Is there a way to reference an oft-used module from another file?
For instance -
"site-section-2.psd" references "common-module-h.psd", and "site-section-6.psd" also references "common-module-h.psd", so that any time updates are made to "common-module-h.psd", the updates appear in both files which reference it.
Possible?
(maybe with photoshop javascript?)
I've checked the JSX Photoshop Object Model, and you can access LayerComps, but there is no magic function to save from one file to another. Something like this could be written to disk, from file1.psd for example, then loaded into file2.psd.
It's a bit of a long shot and I don't know if it's worth the trouble.
For web prototyping I use Fireworks and and I'm pretty happy. You can easily create symbols (much like in Flash and Illustrator) and even save them to a Common Library, which means it will be easy peasy to keep your navigation items for example up to date, for all the files using it. You can even import PSD files into Fireworks, only not all the filters will be supported.
Don't know if you can keep most of the eye-candy in Photoshop and then assemble reamble versions with ease using Fireworks.
You can try converting all the layers into one smart object and then drag the smart object layer into the new .psd file.
Go to the Layers palette: Window > Layers(F7).
LMB SINGLE CLICK the top layer.
Scroll down Layer palette until you get to the bottom.
SHIFT + LMB SINGLE CLICK. At this point all the layers should be hilighted.
RMB SINGLE CLICK any of Layer "Titles".
You should see a menu pop up so use the mouse to scroll until you find "Convert to Smart Object". LMB SINGLE CLICK to convert all the layers into one smart object. The smart object can be edited by double clicking it in the Layers palette. You can also drag a smart object from one .PSD into another .PSD. I usually just open both .PSD files and drag the smart object form one Layers palette to the other Layers palette.