The following snippet generates a pdf with text but the image is distorted like this
Seems the required image should be a .jpg
. When I used a .png
, not even a distorted image was showing in the pdf.
public static void createPdf() {
try {
//Image image = Image.createImage("/icon.png");
Image image = Image.createImage("/Logo.jpg");
EncodedImage encodedImage = EncodedImage.createFromImage(image, true);
byte[] imageData = encodedImage.getImageData();
StringBuilder content = new StringBuilder();
content.append("%PDF-1.4\n");
content.append("1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n");
content.append("2 0 obj<</Type/Pages/Kids [3 0 R]/Count 1>>endobj\n");
content.append("3 0 obj<</Type/Page/Parent 2 0 R/Resources 4 0 R/MediaBox [0 0 520 800]/Contents 6 0 R>>endobj\n");
content.append("4 0 obj<</Font<</F1 5 0 R>>/XObject<</Im0 7 0 R>>>>endobj\n");
content.append("5 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>endobj\n");
content.append("6 0 obj<</Length 219>>stream\n");
content.append("BT /F1 24 Tf 175 720 Td (Codename One)Tj ET\n");
content.append("BT /F1 20 Tf 100 700 Td (Using one codebase, build)Tj ET\n");
content.append("BT /F1 20 Tf 0 660 Td (Android apps)Tj ET\n");
content.append("BT /F1 20 Tf 0 640 Td (iOS apps)Tj ET\n");
content.append("BT /F1 20 Tf 0 600 Td (UWP apps)Tj ET\n");
content.append("512 0 0 512 4 50 cm\n");
content.append("/Im0 Do\n");
content.append("endstream\n");
content.append("endobj\n");
content.append("7 0 obj<</Type/XObject/Subtype/Image/Width 512/Height 512/ColorSpace/DeviceRGB/BitsPerComponent 8/Filter/DCTDecode/Length 132959>>stream\n");
content.append(new String(imageData));
content.append("endstream\n");
content.append("endobj\n");
content.append("\n");
content.append("xref\n");
content.append("0 8\n");
content.append("0000000000 65535 f \n");
content.append("0000000009 00000 n \n");
content.append("0000000052 00000 n \n");
content.append("0000000102 00000 n \n");
content.append("0000000197 00000 n \n");
content.append("0000000255 00000 n \n");
content.append("0000000316 00000 n \n");
content.append("0000000609 00000 n \n");
content.append("trailer\n");
content.append("<</Size 8/Root 1 0 R>>\n");
content.append("startxref\n");
content.append("133724\n");
content.append("%%EOF\n");
FileSystemStorage fss = FileSystemStorage.getInstance();
String pdfPath = fss.getAppHomePath() + "Test2.pdf";
try (Writer w = new OutputStreamWriter(fss.openOutputStream(pdfPath))) {
w.write(content.toString());
} catch (Exception e) {
Log.p("Error " + e);
}
} catch (Exception e) {
Log.p("Error " + e);
}
}
The generated pdf is saved in app storage directory home/.cn1
How can the required raw image data be extracted from the image so that image can show without distortion?
Edit: This question is a bit different from this since I need the image binary data to be generated/created and inserted to the pdf programmatically not manually
EDIT
Writing pdf content directly without appending to a StringBuilder
results to this Test7.pdf. That is
private void createPdf7() {
try {
FileSystemStorage fss = FileSystemStorage.getInstance();
String pdfPath = fss.getAppHomePath() + "Test7.pdf";
try (Writer w = new OutputStreamWriter(fss.openOutputStream(pdfPath))) {
w.write("%PDF-1.4\n");
w.write("1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n");
w.write("2 0 obj<</Type/Pages/Kids [3 0 R]/Count 1>>endobj\n");
w.write("3 0 obj<</Type/Page/Parent 2 0 R/Resources 4 0 R/MediaBox [0 0 520 800]/Contents 6 0 R>>endobj\n");
w.write("4 0 obj<</Font<</F1 5 0 R>>/XObject<</Im0 7 0 R>>>>endobj\n");
w.write("5 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>endobj\n");
w.write("6 0 obj<</Length 219>>stream\n");
w.write("BT /F1 24 Tf 175 720 Td (Codename One)Tj ET\n");
w.write("BT /F1 20 Tf 100 700 Td (Using one codebase, build)Tj ET\n");
w.write("BT /F1 20 Tf 0 660 Td (Android apps)Tj ET\n");
w.write("BT /F1 20 Tf 0 640 Td (iOS apps)Tj ET\n");
w.write("BT /F1 20 Tf 0 600 Td (UWP apps)Tj ET\n");
w.write("512 0 0 512 4 50 cm\n");
w.write("/Im0 Do\n");
w.write("endstream\n");
w.write("endobj\n");
w.write("7 0 obj<</Type/XObject/Subtype/Image/Width 50/Height 50/ColorSpace/DeviceRGB/BitsPerComponent 8/Length 132959>>stream\n");
InputStream is = Display.getInstance().getResourceAsStream(this.getClass(), "/Logo.jpg");
//InputStream is = Display.getInstance().getResourceAsStream(this.getClass(), "/icon.jpeg");
//InputStream is = Display.getInstance().getResourceAsStream(this.getClass(), "/icon.png");
int nextChar = is.read();
if (nextChar == -1) {
//return null;
}
while (nextChar > -1) {
//Log.p("Char " + (char) nextChar);
char[] charArray = {(char) nextChar};
w.write(charArray);
nextChar = is.read();
}
w.write("\nendstream\n");
w.write("endobj\n");
w.write("\n");
w.write("xref\n");
w.write("0 8\n");
w.write("0000000000 65535 f \n");
w.write("0000000009 00000 n \n");
w.write("0000000052 00000 n \n");
w.write("0000000102 00000 n \n");
w.write("0000000197 00000 n \n");
w.write("0000000255 00000 n \n");
w.write("0000000316 00000 n \n");
w.write("0000000609 00000 n \n");
w.write("trailer\n");
w.write("<</Size 8/Root 1 0 R>>\n");
w.write("startxref\n");
w.write("133724\n");
w.write("%%EOF\n");
} catch (Exception e) {
Log.p("Error " + e);
}
} catch (Exception e) {
Log.p("Error " + e);
}
}
What I am still missing for the image to show correctly?
EDIT
Opening this JSjpegSample-with image.pdf with Linux Text Editor shows the following image data stream encoding. Note some readable text like JFIF
Photoshop 7.0
In Codename One simulator, this encoding is close to how SQLite database file is encoded. SQLite database open with Linux Text Editor shows the following. Note some readable text like SQLite format 3
CREATE TABLE
How can a .jpeg
to be added to a pdf be encoded same way as SQLite database file?
The following successfully adds image to the pdf document. The requirements include:
Create a jpeg
image using
EncodedImage.createFromImage(image, true);
This is useful since png
images can be converted to jpeg
Create a ByteArrayInputStream
from image bytes. Using ByteArrayInputStream
, image bytes are directly written as characters to the pdf.
Set ISO-8859-1
encoding in OutputStreamWriter
. This encoding ensured all characters in the image bytes are read as expected by Filter/DCTDecode
.
Windows-1252
encoding also tries but some hexadecimal are read as ?
.
private void createPdf11() {
try {
//Image image = Image.createImage("/Logo.jpg");
Image image = Image.createImage("/android_logo.png");
//Image image = Image.createImage("/ios_logo.png");
//create a jpeg encoded image
EncodedImage encodedImage = EncodedImage.createFromImage(image, true);
byte[] imageData = encodedImage.getImageData();
//get image width, height & length
int imageWidth = encodedImage.getWidth();
int imageHeight = encodedImage.getHeight();
int imageLength = imageData.length;
//create ByteArrayInputStream from image byte array
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imageData);
FileSystemStorage fss = FileSystemStorage.getInstance();
String pdfPath = fss.getAppHomePath() + "Test12.pdf";
try (Writer w = new OutputStreamWriter(fss.openOutputStream(pdfPath), "ISO-8859-1")) {
w.write("%PDF-1.7\n");
w.write("1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n");
w.write("2 0 obj<</Type/Pages/Kids [3 0 R]/Count 1>>endobj\n");
w.write("3 0 obj<</Type/Page/Parent 2 0 R/Resources 4 0 R/MediaBox [0 0 520 800]/Contents 6 0 R>>endobj\n");
w.write("4 0 obj<</Font<</F1 5 0 R>>/XObject<</Im0 7 0 R>>>>endobj\n");
w.write("5 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>endobj\n");
w.write("6 0 obj<</Length 219>>stream\n");
w.write("BT /F1 24 Tf 175 720 Td (Codename One)Tj ET\n");
w.write("BT /F1 20 Tf 100 700 Td (Using one codebase, build)Tj ET\n");
w.write("BT /F1 20 Tf 0 660 Td (Android apps)Tj ET\n");
w.write("BT /F1 20 Tf 0 640 Td (iOS apps)Tj ET\n");
w.write("BT /F1 20 Tf 0 600 Td (UWP apps)Tj ET\n");
w.write("50 0 0 50 4 540 cm\n");
w.write("/Im0 Do\n");
w.write("endstream\n");
w.write("endobj\n");
w.write("7 0 obj<</Type/XObject/Subtype/Image/Width " + imageWidth + "/Height " + imageHeight + "/ColorSpace/DeviceRGB/BitsPerComponent 8/Filter/DCTDecode/Length " + imageLength + ">>stream\n");
//read the next byte of data from ByteArrayInputStream in int range 0 - 255
int nextChar = byteArrayInputStream.read();
while (nextChar > -1) {
//convert int to char and add it to char array
char[] charArray = {(char) nextChar};
//write char array
w.write(charArray);
nextChar = byteArrayInputStream.read();
}
w.write("\nendstream\n");
w.write("endobj\n");
w.write("\n");
w.write("xref\n");
w.write("0 8\n");
w.write("0000000000 65535 f \n");
w.write("0000000009 00000 n \n");
w.write("0000000052 00000 n \n");
w.write("0000000102 00000 n \n");
w.write("0000000197 00000 n \n");
w.write("0000000255 00000 n \n");
w.write("0000000316 00000 n \n");
w.write("0000000609 00000 n \n");
w.write("trailer\n");
w.write("<</Size 8/Root 1 0 R>>\n");
w.write("startxref\n");
w.write("133724\n");
w.write("%%EOF\n");
} catch (Exception e) {
Log.p("Error " + e);
}
} catch (Exception e) {
Log.p("Error " + e);
}
}
This creates Test11.pdf with text and image in the app home path directory home/.cn1
To add a 2nd image, another object to contain it eg 8 0 obj
is needed. This object number is then added to 4 0 obj
as /Im1 8 0 R
. Finally the position of 2nd image is also set in 6 0 obj
as w.write("q 50 0 0 50 4 460 cm /Im1 Do Q\n");
. That is,
private void createPdf13() {
try {
Image image = Image.createImage("/Logo.jpg");
//create a jpeg encoded image
EncodedImage encodedImage = EncodedImage.createFromImage(image, true);
byte[] imageData = encodedImage.getImageData();
int imageWidth = encodedImage.getWidth();
int imageHeight = encodedImage.getHeight();
int imageLength = imageData.length;
//create ByteArrayInputStream from image byte array
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imageData);
Image image2 = Image.createImage("/android_logo.png");
//create a jpeg encoded image
EncodedImage encodedImage2 = EncodedImage.createFromImage(image2, true);
byte[] imageData2 = encodedImage2.getImageData();
int imageWidth2 = encodedImage2.getWidth();
int imageHeight2 = encodedImage2.getHeight();
int imageLength2 = imageData2.length;
//create ByteArrayInputStream from image byte array
ByteArrayInputStream byteArrayInputStream2 = new ByteArrayInputStream(imageData2);
FileSystemStorage fss = FileSystemStorage.getInstance();
String pdfPath = fss.getAppHomePath() + "Test13.pdf";
try (Writer w = new OutputStreamWriter(fss.openOutputStream(pdfPath), "ISO-8859-1")) {
w.write("%PDF-1.7\n");
w.write("1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n");
w.write("2 0 obj<</Type/Pages/Kids [3 0 R]/Count 1>>endobj\n");
w.write("3 0 obj<</Type/Page/Parent 2 0 R/Resources 4 0 R/MediaBox [0 0 520 800]/Contents 6 0 R>>endobj\n");
w.write("4 0 obj<</Font<</F1 5 0 R>>/XObject<</Im0 7 0 R/Im1 8 0 R>>>>endobj\n");
w.write("5 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>endobj\n");
w.write("6 0 obj<</Length 219>>stream\n");
w.write("q\n");
w.write("BT /F1 24 Tf 175 720 Td (Codename One)Tj ET\n");
w.write("BT /F1 20 Tf 100 700 Td (Using one codebase, build)Tj ET\n");
w.write("BT /F1 20 Tf 0 660 Td (Android apps)Tj ET\n");
w.write("BT /F1 20 Tf 0 640 Td (iOS apps)Tj ET\n");
w.write("BT /F1 20 Tf 0 600 Td (UWP apps)Tj ET\n");
w.write("q 50 0 0 50 4 540 cm /Im0 Do Q\n");
w.write("q 50 0 0 50 4 460 cm /Im1 Do Q\n");
w.write("Q\n");
w.write("endstream\n");
w.write("endobj\n");
w.write("7 0 obj<</Type/XObject/Subtype/Image/Width " + imageWidth + "/Height " + imageHeight + "/ColorSpace/DeviceRGB/BitsPerComponent 8/Filter/DCTDecode/Length " + imageLength + ">>stream\n");
//read the next byte of data from ByteArrayInputStream in int range 0 - 255
int nextChar = byteArrayInputStream.read();
while (nextChar > -1) {
//convert int to char and add it to char array
char[] charArray = {(char) nextChar};
//write char array
w.write(charArray);
nextChar = byteArrayInputStream.read();
}
w.write("\nendstream\n");
w.write("endobj\n");
w.write("8 0 obj<</Type/XObject/Subtype/Image/Width " + imageWidth2 + "/Height " + imageHeight2 + "/ColorSpace/DeviceRGB/BitsPerComponent 8/Filter/DCTDecode/Length " + imageLength2 + ">>stream\n");
//read the next byte of data from ByteArrayInputStream in int range 0 - 255
int nextChar2 = byteArrayInputStream2.read();
while (nextChar2 > -1) {
//convert int to char and add it to char array
char[] charArray2 = {(char) nextChar2};
//write char array
w.write(charArray2);
nextChar2 = byteArrayInputStream2.read();
}
w.write("\nendstream\n");
w.write("endobj\n");
w.write("\n");
w.write("xref\n");
w.write("0 9\n");
w.write("0000000000 65535 f \n");
w.write("0000000009 00000 n \n");
w.write("0000000052 00000 n \n");
w.write("0000000102 00000 n \n");
w.write("0000000197 00000 n \n");
w.write("0000000255 00000 n \n");
w.write("0000000316 00000 n \n");
w.write("0000000609 00000 n \n");
w.write("trailer\n");
w.write("<</Size 9/Root 1 0 R>>\n");
w.write("startxref\n");
w.write("133724\n");
w.write("%%EOF\n");
} catch (Exception e) {
Log.p("Error " + e);
}
} catch (Exception e) {
Log.p("Error " + e);
}
}
Which generates Test13.pdf