I'm using iText to generate PDF files. I want to disallow editing of the PDF, but allow the reader to extract pages. Here's my code to set encryption:
writer.setEncryption(null, null, 0xffffffff, PdfWriter.STANDARD_ENCRYPTION_128);
The third parameter specifies permissions. I'm using 0xffffffff instead of the individual iText flags ALLOW_PRINTING etc. This will ask iText to enable everything. But this is what I get in the PDF file:
I should think I should be allowed to enable extraction but disable editing, but am not certain. Here are the permissions bits per Adobe:
(From here, but be warned it's 30 meg)
So turn off bits 6 and 11 but leave on the others (especially bits 5 and 10), and that would turn off editing but allow extraction. In any case, by specifying 0xffffffff I would think that everything would be allowed; but instead everything except extraction is allowed.
I've skimmed the iText source code for setting permissions and don't see anything that would cause this. Here is the relevant code from PdfEncryption.setupAllKeys:
permissions |= (revision == STANDARD_ENCRYPTION_128 || revision == AES_128 || revision == AES_256) ? 0xfffff0c0
: 0xffffffc0;
permissions &= 0xfffffffc;
The first line is doing an OR and so wouldn't remove any permissions; the second line is setting the two right-most bites to 0, per the PDF specification.
I'm wondering if it's an iText thing, a PDF thing or if I'm doing something else wrong.
Thanks
A similar issue already has been raised here.
Using encryption actually is counter-productive as it can only be used to remove permissions, not to add them.
According to this, it might be helpful to completely unlock the PDF first:
PdfReader reader = new PdfReader(file.toURI().toURL());
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(
file.getAbsolutePath().replace(".pdf", "_UNLOCKED.pdf")));
stamper.close();
reader.close();
Afterwards you can grab the output and start from scratch (mess around with the permission bits). Hope this helps.
EDIT: If you don't have access to the password, the iText sources can be modified. Simply comment out if (!reader.isOpenedWithFullPermissions()) throw ... (line 121 and 122 in version 5.5.0) in com.itextpdf.text.pdf.PdfStamperImp.
Related
I have to work with a PDF form created by a person unknown to me. Why did the program with which the form was created (Word + PDF export?) split the term "Stunde" into "S", "t" and "unde" in line 6909 of the decoded PDF? There is no visual break between the three parts.
/TT1 1 Tf
11.04 0 0 11.04 59.16 476.1203 Tm
(Datum)Tj
/C2_1 1 Tf
<0003>Tj
/TT1 1 Tf
(der)Tj
0.424 -1.315 Td
(Tätigkeit)Tj
-0.0022 Tc 0 11.04 -11.04 0 261.24 437.7203 Tm
[(Ve)-4.6<7267fc74>-4.2(ungssat)-4.2(z)]TJ
/C2_1 1 Tf
0 Tc <0003>Tj
/TT1 1 Tf
-0.0021 Tc 0.935 -1.315 Td
[<2880>-6.1(/)-7.2(S)0.8(t)-4.1(unde)-4.5(\))]TJ % <<< the important line
0 Tc 11.04 0 0 11.04 340.92 468.8003 Tm
(Anlass/Art)Tj
/C2_1 1 Tf
resulting in
[]
To get the source code above, I decoded the PDF file as described here. I have no know-how concerning the PDF file format.
Background: I had to replace the word "Stunde", it drove me crazy to find the place where "Stunde" was written (in parts) within the source code, since no free PDF editor seems to be able to work with horizontal text without problems.
Academic Bonus questions: Is it possible to set the sum over a column as default value for a form field? (Modifiable; changed every time the column is changed.) Why was I able to replace "Stunde" with "Einsatz" without making the PDF file corrupt due to now irregular offsets?
Why did the program with which the form was created (Word + PDF export?) split the term "Stunde" into "S", "t" and "unde" in line 6909 of the decoded PDF?
As #gettalong mentioned in his answer, in your case this most likely has been done to apply kerning.
If you start looking into the outputs of some other PDF producers, you'll see that this export from Word actually is very unobtrusive in regard to splitting words:
there are PDF producers that draw each character individually after explicitly setting the text matrix for it, and
there also are PDF producers that have the width information for the characters of the used fonts set to zero and use the numbers in TJ instructions to forward the current text matrix between characters accordingly.
And this doesn't cover all the variants to be found, not by far...
Thus,
I had to replace the word "Stunde", it drove me crazy to find the place where "Stunde" was written (in parts) within the source code
in your case replacing actually was a fairly trivial task...
Is it possible to set the sum over a column as default value for a form field? (Modifiable; changed every time the column is changed.)
If all the column values in question are stored in form fields, you can use JavaScript to recalculate sums after form changes. To have it serve as "default" only, you can use some other (hidden) field for a flag whether the field has already been touched. Beware, though: JavaScript is not supported by all PDF viewers. Furthermore, the JavaScript object model for PDF is not specified in an independent (like ISO) specification but in an Adobe one which can make interpretation of the specification biased.
Why was I able to replace "Stunde" with "Einsatz" without making the PDF file corrupt due to now irregular offsets?
As we don't know how exactly you applied the changes, this obviously is hard to tell.
Most likely, though, you did corrupt the PDF and the PDF viewers you opened it in merely repair the corruption under the hood. There is a strong tendency in PDF viewers to do such under-the-hood repairs without informing the user; the result is that a large part of the PDFs in the wild actually being broken.
You don't see a visual break but the standard distance between "S", "t" and "unde" has been changed nonetheless. This is done by PDF writers that support e.g. kerning so that the word appear nicer. This is the reason why it is split that way.
for the purpose of creating a syllabus, I like to know whether it is possible to insert a citation as a full citation. Right now, I have following markdown code:
# Session 1
#zhu2015.
This converts (pandoc "document.md" -o "document.pdf" --from markdown --template "eisvogel" --listings --citeproc) in the pdf as
Session 1
Zhu and Basar (2015).
Bibliography
Zhu, Quanyan, and Tamer Basar. 2015. “Game-Theoretic Methods for Robustness, Security, and Resilience of Cyberphysical Control Systems: Games-in-Games Principle for Optimal Cross-Layer Resilient Control Systems.” Control Systems, IEEE 35 (1): 46–65.
However, would it be possible to insert the reference as a full-citation in text?
Such as:
Session 1
Zhu, Quanyan, and Tamer Basar. 2015. “Game-Theoretic Methods for Robustness, Security, and Resilience of Cyberphysical Control Systems: Games-in-Games Principle for Optimal Cross-Layer Resilient Control Systems.” Control Systems, IEEE 35 (1): 46–65.
Thanks for your help!
Here's how to do this with a Lua filter: First, the filter finds the generated bibliography entry and saves it to a table, indexed by the citation key. Then it looks for the citation and replaces it with the full entry.
local refs = {}
local function store_refs (div)
local ref_id = div.identifier:match 'ref%-(.*)$'
if ref_id then
refs[ref_id] = div.content
end
end
local function replace_cite (cite)
local citation = cite.citations[1]
if citation and refs[citation.id] and #cite.citations == 1 then
return pandoc.utils.blocks_to_inlines(refs[citation.id])
end
end
return {
{Div = store_refs},
{Cite = replace_cite},
}
Save the above to a file and pass that file to pandoc with the --lua-filter command line option. The filter must run after the citeproc processer has done its work, so it should be the last command line argument. Tested with the latest pandoc version 2.12 (which no longer requires pandoc-citeproc, but it should work either way).
When I import product data or I upload image directly to a product I get the following message (was not uploaded. Filename is too long; must be 90 characters or less)
Recently my magento has been updated and I didn't have this problem before.
Does anyone know how I can increase the number of characters slightly?
enter image description here
I was able to solve the problem myself.
The file in question is located in the following folder
vendor\magento\framework\File Uploader.php
search for the following code:
// account for excessively long filenames that cannot be stored completely in database
if (strlen($fileInfo['basename']) > 90) {
throw new \InvalidArgumentException('Filename is too long; must be 90 characters or less');
Adjusting this file is not the best method, I have to add
For anyone finding this question on Google, I wanted to share additional findings, as I've faced the same issue. Perhaps you will find them helpful.
As #Timo already wrote, the limit of 90 characters is hard-coded in the getCorrectFileName() method in vendor\magento\framework\File\Uploader.php (in older versions of Magento).
public static function getCorrectFileName($fileName)
{
(...)
$maxFilenameLength = 90;
if (strlen($fileInfo['basename']) > $maxFilenameLength) {
throw new \LengthException(
__('Filename is too long; must be %1 characters or less', $maxFilenameLength)
);
}
(...)
}
Since this method is static, writing a plugin is not possible and apparently providing a preference won't work as well.
It seems that there was a fix for this already available in Magento, but only in versions 2.4.2 and 2.4.2-p1. Then, for whatever reasons it got removed. See the related Github issue.
Since Magento v2.4.5 the file name length is now limited to 255 characters:
private const MAX_FILE_NAME_LENGTH = 255;
(...)
public static function getCorrectFileName($fileName)
{
(...)
if (strlen($fileInfo['basename'] ?? '') > self::MAX_FILE_NAME_LENGTH) {
throw new \LengthException(
__('Filename is too long; must be %1 characters or less', self::MAX_FILE_NAME_LENGTH)
);
}
(...)
}
So, until you upgrade your Magento version to 2.4.5 or newer, it seems that making a change in the core code is the only option, either manually or using a composer patch.
I'm using iText® 5.2.1 ©2000-2012 1T3XT BVBA and Integration Designer 8.0 to create a PDF file that is exported in an byte array.
I am creating a document with a fair amount of text and want to add a logo at the beginning.
Part of the code that is adding the image is as follows:
BASE64Decoder decoder = new BASE64Decoder();
byte[] decodedBytes = decoder.decodeBuffer(Stringovi.SLIKA1);
Image image1 = Image.getInstance(decodedBytes);
image1.setAbsolutePosition(30f, 770f);
image1.scalePercent(60f);
document.add(image1);
The input image is in byte array format because of the system requirements.
The rest of the document consists of different tables with various content and it's all text.
When I add the image in the before mentioned way the program finishes and i get an byte output that i run trough a Base64 decoder. Resulting PDF can not be opend and the error shown is:
"Error [PDF Structure 40]:Invalid reference table (xref)"
I can't see where my mistake is so if anybody could be so kind and point me in the right direction I would very much appreciate it.
The document you presented as a "broken PDF file" is not a complete PDF file. It doesn't end with %%EOF, it doesn't have a cross-reference table,... It's a PDF document that isn't complete.
This means that you don't have the following line in your code:
document.close();
If you do have this line, it isn't reached. For instance: an exception is thrown causing the code to jump to a catch clause, skipping the close() operation.
The error message saying Invalid reference table (xref) is consistent with that diagnosis. This isn't a problem caused by iText. It's a problem caused by bad coding: not closing the document and/or not dealing with exceptions correctly.
How do i format something for another locale in Windows?
For example, in managed C# code, i would try to render a DateTime using en-US locale with:
String s = DateTime.Now.ToString(CultureInfo.CreateSpecificCulture("en-US"));
TextRenderer.DrawText(
e.Graphics, s, SystemFonts.IconTitleFont,
new Point(16, 16), SystemColors.ControlText);
And that works fine when my computer's locale is en-US:
It even works fine when my computer's locale is de-DE:
But it completely falls apart when my computer's locale is ps-AF:
Note: My sample code is in .NET, but can also be native.
Update: Attempting to set System.Threading.Thread.CurrentThread.CurrentCulture to en-US before calling DrawText:
var oldCulture = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
try
{
// String s = DateTime.Now.ToString(CultureInfo.CreateSpecificCulture("en-US"));
String s = DateTime.Now.ToString();
TextRenderer.DrawText(e.Graphics, s, SystemFonts.IconTitleFont, new Point(16, 16), SystemColors.ControlText);
}
finally
{
System.Threading.Thread.CurrentThread.CurrentCulture = oldCulture;
}
No help.
Nine, no help
Jack, no help
Eight, possible straight
King, possible flush
Ace, no help
Six, possible straight
Dave of love for the dealer
Ace bets.
Update Two:
From Michael Kaplan's blog entry:
Sometimes, GDI respects users (even if no one else does!)
GDI doesn't give a crap about formatting or really anything related to locales, with one single exception:
Digit Substitution
Any time you go to render text it will grab those digit substitution settings in the user locale (including the user override information) and use the info to decide how to display numbers.
And there is no way to override those settings at the level where GDI uses them.
i wonder how Chrome manages it. When i write digits here, in the stackoverflow question, Chrome renders them using latin digits:
0123456789
See:
What you are seeing is due to the digit substitution that occurs when your system's locale is ps-AF.
I believe that's OK -- Users of such a locale are used to seeing digits presented this way.
Normally the way this is done is slightly different, see here for example, but I don't actually think this should make any difference:
String s = DateTime.Now.ToString(new CultureInfo("en-US"));
An alternative is to set Thread.CurrentCulture to your desired locale.
I.e. do this:
Thread.CurrentCulture = new CultureInfo("en-US");
And you can then replace the first line of your code with this:
String s = DateTime.Now.ToString();
I am not quite sure, but I believe that this would solve the digit substitution issue as DrawText would now be based on the en-US culture, rather than ps-AF