I'am trying to verify signatures in pdf file. There are three of them. I have signed that file with the code i've found in internet and adopted to my needs, so it might be encorrect too. Here is that signed file pdf file
Verifier code here:
package com.mycompany.verifysignature;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.bouncycastle.crypto.digests.GOST3411Digest;
import ru.CryptoPro.CAdES.CAdESSignature;
import ru.CryptoPro.CAdES.CAdESType;
public class Main {
public static void main(String args[]) {
try {
ArrayList<Map<String, String>> resList = new ArrayList<Map<String, String>>();
InputStream pdfIs = new FileInputStream("/home/user1/Desktop/321-17.pdf");
com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(pdfIs);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
com.itextpdf.text.pdf.PdfStamper stamper = com.itextpdf.text.pdf.PdfStamper.createSignature(reader, baos, '\0');
com.itextpdf.text.pdf.PdfSignatureAppearance sap = stamper.getSignatureAppearance();
com.itextpdf.text.pdf.AcroFields fields = reader.getAcroFields();
for (String signame : fields.getSignatureNames()) {
HashMap<String, String> m = new HashMap();
m.put("name", signame.toString());
System.out.println("name:"+signame);
com.itextpdf.text.pdf.PdfDictionary sig = fields.getSignatureDictionary(signame);
if (sig != null && sig.getAsString(com.itextpdf.text.pdf.PdfName.REASON) != null) {
m.put("reason", sig.getAsString(com.itextpdf.text.pdf.PdfName.REASON).toString()
.replaceAll("\"", "\\\""));
System.out.println("reason:"+sig.getAsString(com.itextpdf.text.pdf.PdfName.REASON).toString()
.replaceAll("\"", "\\\""));
} else {
m.put("reason", "undefined");
System.out.println("reason:undefined");
}
byte signature[] = null;
if (sig != null && sig.getBytes() != null) {
signature = sig.getBytes();
}
byte hash[] = calcHash(sap.getRangeStream());
if (hash != null) {
CAdESSignature cadesSignature = new CAdESSignature(signature, hash, CAdESType.CAdES_X_Long_Type_1);
try {
cadesSignature.verify(null);
m.put("valid", "true");
System.out.println("valid:true");
} catch(Exception ex) {
m.put("valid", "false");
System.out.println("valid:false");
}
} else {
m.put("valid", "\"undefined\"");
System.out.println("valid:undefined");
}
// com.itextpdf.text.pdf.security.PdfPKCS7 pk = fields.verifySignature(signame);
//
// m.put("valid", new Boolean(pk.verify()).toString());
// System.out.println("valid:"+new Boolean(pk.verify()).toString());
resList.add(m);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static byte[] calcHash(InputStream is) {
if (is == null) return null;
try {
GOST3411Digest digest = new GOST3411Digest();
byte node[] = readBytesFromStream(is);
digest.update(node, 0, node.length);
byte[] resBuf = new byte[digest.getDigestSize()];
digest.doFinal(resBuf, 0);
return resBuf;
} catch (Throwable e) {
e.printStackTrace();
//throw new Exception(e);
}
return null;
}
private static byte[] readBytesFromStream(InputStream is) throws Exception {
ArrayList<Object[]> c = new ArrayList();
int n, size = 0;
byte b[] = null;
if (is == null) throw new Exception("input stream is null");
try {
while ((n = is.read(b = new byte[1024])) > 0) {
c.add(new Object[] { n, b });
size += n;
}
} catch (IOException e) {
e.printStackTrace();
}
byte rv[] = new byte[size];
int pos = 0;
for (Object[] bb : c) {
for (int i = 0; i < (Integer) bb[0]; i++) {
rv[pos++] = ((byte[]) bb[1])[i];
}
}
return rv;
}
}
I have signed file's digest, made with GOST3411, with test certificate, that is generated on cryptopro site.
When I open this file with pdf reader, it says there are 3 signatures. I have realy signed it three times. But the code above takes out from the pdf signature names that are not equal to the names I wrote. They are look like Signature1, Signature2 etc. There should be written "CN" in all three cases. Please help. What I have made wrong?
The file provided by the OP, 321-174.pdf, is signed using exactly one signature, not three, and the prime error is that the Contents of the signature dictionary content are not the CMS signature but instead something textually, probably base64 encoded. Thus, some decoding in-between in your code seems necessary.
That been said I cannot find GOST3410 in the Table 257 – SubFilter value algorithm support - of the specification ISO 32000-1- Thus its use in this context most likely wont be accepted.
Related
I have a directory with sub-directories which contains text or binary files ( like pictures ). I need to find duplicate files which can be in different sub-directories and with different names. So, I need to use some algorithm which would look inside the files and NOT rely on file name, or length of file.
I could come up with a quick solution. I know this code can be written much better but functionality wise its working perfect. I even tested it on jpeg, gif files.
public static Map<String, List<File>> mapFilesHash = new HashMap<String, List<File>>();
public static MessageDigest md ;
static {
try {
md = MessageDigest.getInstance("MD5");
} catch (Exception ex) {}
}
private static String checksum(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
byte[] byteArray = new byte[1024];
int bytesCount = 0;
while ((bytesCount = fis.read(byteArray)) != -1) {
md.update(byteArray, 0, bytesCount);
}
fis.close();
byte[] bytes = md.digest();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
public static void findDuplicateFiles(File rootDir) throws Exception {
iterateOverDirectory(rootDir);
System.out.println("based on hash "+mapFilesHash.size());
for (List<File> files: mapFilesHash.values()) {
if (files.size() > 1 ) {
System.out.println(files);
}
}
}
private static void iterateOverDirectory (File rootDir) throws Exception {
for (File file : rootDir.listFiles()) {
if (file.isDirectory()) {
iterateOverDirectory(file);
} else {
if (mapFilesSize.get(file.length()) == null) {
mapFilesSize.put(file.length(), new ArrayList<>());
}
mapFilesSize.get(file.length()).add(file);
String md5hash = checksum(file);
if (mapFilesHash.get(md5hash) == null) {
mapFilesHash.put(md5hash, new ArrayList<>());
}
mapFilesHash.get(md5hash).add(file);
}
}
}
Without mapFilesSize your method iterateOverDirectory can became:
private static void iterateOverDirectory(File rootDir) throws Exception {
for (File file : rootDir.listFiles()) {
if (file.isDirectory()) {
iterateOverDirectory(file);
}
else {
mapFilesHash.computeIfAbsent(checksum(file), k -> new ArrayList<>()).add(file);
}
}
}
I have a C# project to verify a file's MD5. I use System.Security.Cryptography.MD5 to calculate the MD5 in C#.
But it is different from the MD5 in Java.
EDIT: I have found the c# code is correct one. Thanks to Andy. May I know how to correct the Java code?
C# code:
public static String ComputeMD5(String fileName)
{
String hashMD5 = String.Empty;
if (System.IO.File.Exists(fileName))
{
using (System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
System.Security.Cryptography.MD5 calculator = System.Security.Cryptography.MD5.Create();
Byte[] buffer = calculator.ComputeHash(fs);
calculator.Clear();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < buffer.Length; i++){
stringBuilder.Append(buffer[i].ToString("x2"));
}
hashMD5 = stringBuilder.ToString();
}
}
return hashMD5;
}
Java Code:
public static String ComputeMD5(File file) {
if (!file.isFile()) {
return null;
}
MessageDigest digest = null;
FileInputStream in = null;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
in = new FileInputStream(file);
while ((len = in.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return bytesToHexString(digest.digest());
}
Your bytesToHexString function is wrong. After using the function from here, in this complete example, I get the same result as the Linux md5sum command and`onlinemd5.com as Andy suggested. The best way to handle this is to use a library, such as Apache Commons, that has a function to convert from bytes to a hex string. That way, you offload the work to get it right to a reputable library.
import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;
public class Md5{
public static String computeMd5(File file) {
if (!file.isFile()) {
return null;
}
MessageDigest digest = null;
FileInputStream in = null;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance("MD5");
in = new FileInputStream(file);
while ((len = in.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return byteArrayToHex(digest.digest());
}
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b));
return sb.toString();
}
public static void main(String[] args){
System.out.println(computeMd5(new File("./text.txt")));
}
}
I am basing my code from this
https://github.com/Betel-Flowers/BetelFlowers/blob/master/BetelFlowers-ejb/src/main/java/com/betel/flowers/pdf/util/RemoveBlankPageFromPDF.java
or this
http://www.rgagnon.com/javadetails/java-detect-and-remove-blank-page-in-pdf.html
I am trying to use a byte array as input a byte array as output.
This is my code
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfDictionary;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfName;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.RandomAccessFileOrArray;
public class RemoveBlankPageFromPDF {
// value where we can consider that this is a blank image
// can be much higher or lower depending of what is considered as a blank page
public static final int BLANK_THRESHOLD = 160;
public static byte[] removeBlankPdfPages(byte[] fuente) throws IOException, DocumentException{
PdfReader r = null;
RandomAccessFileOrArray raf = null;
Document document = null;
PdfCopy writer = null;
ByteArrayOutputStream archivoFinal = new ByteArrayOutputStream();
try {
r = new PdfReader(fuente);
raf = new RandomAccessFileOrArray(fuente);
document = new Document(r.getPageSizeWithRotation(1));
writer = new PdfCopy(document,archivoFinal);
document.open();
PdfImportedPage page = null;
for (int i = 1; i <= r.getNumberOfPages(); i++) {
PdfDictionary pageDict = r.getPageN(i);
PdfDictionary resDict = (PdfDictionary) pageDict.get(PdfName.RESOURCES);
boolean noFontsOrImages = true;
if (resDict != null) {
noFontsOrImages = resDict.get(PdfName.FONT) == null
&& resDict.get(PdfName.XOBJECT) == null;
}
if (!noFontsOrImages) {
byte bContent[] = r.getPageContent(i, raf);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
bs.write(bContent);
System.out.println("bs size: " + bs.size());
if (bs.size() > BLANK_THRESHOLD) {
page = writer.getImportedPage(r, i);
writer.addPage(page);
}
}
}
System.out.println("Original: " + fuente.length+ " new: " + archivoFinal.toByteArray().length);
return archivoFinal.toByteArray();
} finally {
if (document != null) {
document.close();
}
if (writer != null) {
writer.close();
}
if (raf != null) {
raf.close();
}
if (r != null) {
r.close();
}
}
}
}
my pdf gets corrupted i cannot open it after.
Even with a pdf without spaces I get different sizes, it should be the same
Original: 95089 New: 88129
That is my output from my las sysout.
I am using itext 2.1.5 and java 1.5 by the way. I cannot upgrade.
Anyways I found an answer. Just in case somebody needs for an older version of itext
public static void removeBlankPdfPages(PdfReader r) throws IOException{
PdfTextExtractor extractor = new PdfTextExtractor(r);
List<Integer> paginas = new ArrayList<Integer>();
for (int i = 1; i <= r.getNumberOfPages(); i++) {
PdfDictionary pageDict = r.getPageN(i);
PdfDictionary resDict = (PdfDictionary) pageDict.get(PdfName.RESOURCES);
boolean noFontsOrImages = true;
if (resDict != null) {
noFontsOrImages = resDict.get(PdfName.FONT) == null
&& resDict.get(PdfName.XOBJECT) == null;
}
if (!noFontsOrImages) {
String textFromPage = extractor.getTextFromPage(i);
if(textFromPage.length() >50 ){
paginas.add(i);
}
}
}
r.selectPages(paginas);
}
I'm trying to repeat in .NET the algorithm that was originally written in Java and I'm having troubles with the GZIP decompression.
At the bottom of the post I inserted the hex string that is converted to byte array in both .NET and Java. The resulting byte array is then decompressed in Java with the following method:
public static Object readObjectFromByte(byte[] bytes)
{
ObjectInputStream oos = null;
try {
ByteArrayInputStream baos = new ByteArrayInputStream(bytes);
zis = new GZIPInputStream(baos);
oos = new ObjectInputStream(zis);
return oos.readObject();
} catch (Throwable t) { GZIPInputStream zis;
return null;
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
After decompression the resulting byte array has a length of 3952 which is probably correct. At the same time I tried different .NET classes/libs to decompress, but it always gives a byte array of 3979 bytes which is probably incorrect.
I tried:
GZipStream
DotNetZip
SevenZipLib
SharpZipLib
I read a lot of articles about GZIP issues in .NET trying to fix this. I use .NET 4.5, and for example my last decompression version is this:
Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes)
It's weird but even if I try:
Ionic.Zlib.GZipStream.CompressBuffer(Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes)).SequenceEquals(compressedBytes)
It gives me FALSE.
The hex string:
EDIT:
Java Code:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class JavaFiddle
{
public static void main(String[] args)
{
String hex = "PLEASE_UPDATE"; //update this from the hex constant at the end of the post
byte[] compressedBytes = hexStringToByteArray(hex);
byte[] decompressedBytes = (byte[])readObjectFromByte(compressedBytes);
System.out.println(decompressedBytes.length); //THIS GIVES 3952
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static Object readObjectFromByte(byte[] bytes)
{
ObjectInputStream oos = null;
try {
ByteArrayInputStream baos = new ByteArrayInputStream(bytes);
GZIPInputStream zis = new GZIPInputStream(baos);
oos = new ObjectInputStream(zis);
return oos.readObject();
} catch (Throwable t) { GZIPInputStream zis;
return null;
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
.NET Code
private byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
...
var hex = "PLEASE_UPDATE"; //update this from the hex constant at the end of the post
var compressedBytes = StringToByteArray(hex);
var decompressedBytes = Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes);
//decompressedBytes.Length is 3979, Note that this is using one of the external libraries, the same result is for built-in GZipStream in .NET
1F8B0800000000000000ADCEF923130A0000E0596C8A1CB90AA1D0E428916C4AE6889C61071E1D2A77B42C67D1731BF2DE6C662C5744C6DE7BC8DC4791DCB79E35315EC2C62437E1FDBE9FF7FD055FC53240282418007437AB5893DB060923594000201C030088639882D19C31C860FB7838A60DBBF039C3B41821FF606044C89D24EB4C1D6A627FBF8E978D3616796C2ACDD165ABB32B81A0C493A35F163889E74665A9341C7C36F06FA0F991201BEAAB6A47842C43A50DA6B8C000AD794840CF03E29A527D0C921FAE6D607C71AEF7C01DB34037A7F8CDD8CB1F61DB9C15A87DBBDD1F933FDF58312B054D7B5AF72FE75A0AA101714EEA6980BF405A15A1F13A0979FB5BBE1636A367CB4C943FB7F87A3245573BB6857DA6AA0B412CCB553B39E06973EB2A3864E98915E46C16E4EE06E9DA63DB642915AF6E86811FD2C8F3A1F325C82677EA701D1E3574885696DEB3B8A0C29AE1FDD41DA26C55C6381506A3CF77DD15BD37783F545F76E8DCF9FB6A8B0776E2427FBFF431B73748CE96786EA569E307B5DC8990A68A52838D9DC1BA19291F283BF2C7EE43D3E4516D77A07FDE04934BB7C254057BDFC3AD153A0A711E7EFDDDED31AED367FAAEA6F494A55E029BF6AECA9433CA7D45B52EC24BCF9074315BFE5F5494F4F0DDDE8D73F56397A0667992950E62AD4020A4102DBE7C4D6B85E457F184DC5AA51D2D536313E1E16636928BD6500207571B83C8830DB9E7CF2C92AE4DDB12B8DF3C6AAF83B09CAACB78AA78CDB0DB393D71A599F185B413BFDB907FC99598D2E56ADE701EE72DB71C9650E820DB452F7DD4904E4679FFD0CB6FEEDF7527AF21BE5A5404B8BAE4E9951AE5C88BF9B5D5FFC6447989445C7A2DB80B3E4A2DBCB51978BA1729F97BDCAD174D345417B96941BF2CC5C10539C952B2526770BA4637A5820DCF150E16AED3159AD9724A8DFCFEA8BADA2A08BD1A0C9B05B019CE61E01EDECF7F028B466E4B53A5F1FAE56CB137EF269E1946896D1A3DDCDB756364A96D8E47F3FB33E9B70BBED37FA8719F2D2EA89BBFB0CAFB71CC56947F7907439E9FE97C61D2A326F830592509674860BA7CC7E713EFD69D2724DED740A2959846CFE801B313BB1DAB45594D70E888F2A3063C67085BFDB345D64D116372F5BE42BB08ABBC6D65D90E1E50C849EDD9A6F977751C4DB5A454C66B997D6A0CA148827E03AEE30F1697392124A8C44C6A914C3C69C21447F9C5660665C5D0D3F758D57086D0938608E9BECE9BA95D359C41E255B0524C55EDC97816A76E32B29BF55BAE0EC1F71DBF3FF548DC2C181755D85ABCAFEDF23C248EF7D3C1580AB88D28CDCF9935F1DA797145A7F0B18603C1DA39EA8E969A2279F20F077E7F62BD5C1F7C095BF1B21D36561A254836F37EBC0AEB8C8EAE8EC725044EE47F107DE413DE804EED41473E4D3BEC93E9234255F9FDD1FD91F00B32BF13B2629C4373888813E5FD08F66AB7295D281E180ACE99A77952DE6DCD675B20E021A71E91F78B899A1FC2F8FD913C0E4D980B1D6CF13F7A76E823BDF75FDE8FC513C3C491F51305F1A483B81A11884254CB2DB396F864B08DDEDD005A90EF457E7F8EDFB64FF7C7443C6E2135183619ED69F27E1464BF862FB14A66509C379818517F6B2423D0D1BE794E4D9C7130D9F54AB19DDF9FC825CF8B3B5EBD8090811D372C0315CEFBB926701AC2B84CB4820D25DD2D71F2F6630FB3FA88A3EAAF9E44C709EFACC05FF2FBD342E844AB8A22F433B7C2161FEDE70BF07EF29A6B6355DAF2D33E7A2679C8A38511939EEE73DABDE98B021A9F0E21A5CFFEE6F7A7C44CE2358158F5B15F837CE96B75622FEFE702653D87222B9319D46D321EEDA628713D1B355A30E0D07A655F12A55B6397CFEFCFA3DB3B76DB80347FDCA613FD1F3F6022EF276A1666DDA3BE518CB634F67B185BD2016DB2DC20E56C1C9B58CD411710E802FCFED0E3E1E182C37A9684A007EF0DEBBBCB783F37A0D39E2B6FAB147A3BCD75B1C24FA5939BDD9501D5E0365A60E58BE429C821BF3F774DC4603D43CE355412CC3DBF47639DF7B33CFEF4138133255770F2659E44F2FC9EE285FCDCEC414B473CCB31BA39BA798CDF1FF28A3EBD7549341C8E809E8AABF836C7FB59DB4025ED1DC5BF1874EDF4511ECCC397050C8C3F404FB04BF52DF4F35411EBFCFEFCB70C2AF6EE8AFC32A539F624F0E30D47DE8F9138B0C9B24F03F5CD53E05CA77D63CAA8800CA567E4D60D8D4ECBA9F9FE3C75FADED32267AB07ED635AD14CB6A87B1F8D5B5BD43F7C04E14DB30935A6B6CA780F2FBD10CD2EAE8DD13D6C9FA89334A8ADEAC40D63C54B6E881F9F382D3056BF7DACFFC6914A6DF60F64E7C5FE8EB222FD71632318CDC5E3CF8EC48602D238E95FC06C9BDBBD3D85535DED236D1FFA4EB1F3939B334A222BBF7FE034EB1599A7E20DFF89F92E9B3EE0D45FA7103A9B8BE6F727EC6D338C464AAA1B6B8AF426BA2153793FF7C43EEE7A43E6038296B83E130BAA9D467DB7A9B8E29E18B8F4E4493DB3E1BE4CDC1ABA3074A8D69058420FB2F56BCCD3CAB0806FA9C1E825D6F18644CD9137AB9195DD63A8BD3BA9F5C9BF0AEC9F5B6E605B2C02CAA93FB10A5F03ADD7370A981F3A99F0F3CC2DA93C298292E9859C01BBB088FE6CD979FC5A02127305D63C72B319EDD48A0EE6BE431C17B3F8E4FFDAC1F5D9A9F4EB7443EE2D3CAD6A3508A918C48DBB7F89081B7087C94A60F9FD297839305DA999BE163F234E3ED7D8D8CDFBA16AE5327F3E9D5925DF533EF5FEA2F26D3784CFB578877E15799DB73DAEC8D767F9FD81597235251D2DC413C2E1F58887AF75783F8248EC923F57F93D81A88D9E3E1E045997FD3C40B1BF83CEFC9CC2CCC079197928232333623BE67DA6A70B4818095DEEC23ABEC73E4DC9E1A74E04AEC1D420EB533CF3C06C242E1612F85A560A2861A0E54C218AC1834FCCDBD2F61FBC3B32983F25B29F5967A7219C74A10C769002C1869E9DC926A99C9D1AC92CC8BC3A5D151D405693BA0DBE292D94F40B918AFCEE6851DFC215B3738975F1EFAA32923037D96656C2D2B94B015CD1DA5F43D0A8FFA063099BA0BFB246724C8E61150FB2126EDE245963F4454EBCFF5105BDA267D598E2D1E9985136AF4348D8FCF96F355B27AE6E6F5378415D8A8D1CAD3EC3426969BF5790DBA0C01EF9B7E86095D9313F74309E01C7BA00B9B0E85DA89900D6F89DEA5BCA9273C017B56139F9CF13E7DB74724240262CBDFCEC05FB5DDAA64CB98257C9AAF7AA48AAD36577B3D6F11CD0A074D5B15860B2791E8E8B87AB2A5B2419F61561E6ECF56746E2185EBFFF0F96F821B38B0F0000
Thanks,
Now we've got more of the Java code, we can see the problem: you've got an extra layer of serialization around your real data. That has nothing to do with compression really.
Here's an example to show what I mean:
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(output)) {
oos.writeObject(new byte[5]);
}
byte[] data = output.toByteArray();
System.out.println(data.length);
}
}
}
That's writing a byte array that's 10 bytes long - but the result is 32 bytes long, because of the extra "wrapper" information. Note that the extra 27 bytes is the same as the discrepancy you've seen.
Fundamentally, it's odd to wrap a byte array in this way, and if you can possibly change the original code, that would be for the best. If you absolutely can't do that, it may be safe to just ignore the first 27 bytes of the resulting data.
After compile and run it shows "no pdf printer available", How to solve this?
I have created a file in c:\print.pdf (using PHP TCPDF). And i am
trying to read that file in byte array, so that i can silently print
it without showing any popup of print etc.
I cant make it working, can anyone please show guide how to read a
file in Byte array? To do the following:
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
public class print
{
private static Object pdfBytes;
// Byte array reader
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
long length = file.length();
if (length > Integer.MAX_VALUE) {}
byte[] bytes = new byte[(int)length];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
is.close();
return bytes;
}
// Convert Byte array to Object
public static Object toObject(byte[] bytes)
{
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream (bis);
obj = ois.readObject();
} catch (IOException ex) {
} catch (ClassNotFoundException ex) {
}
return obj;
}
private static File fl = new File("c:\\print.pdf");
public static void main(String argc[])
{
DocFlavor flavor = DocFlavor.BYTE_ARRAY.PDF;
PrintService[] services =
PrintServiceLookup.lookupPrintServices(flavor,
null);
//Object pdfBytes = null;
try {
byte[] abc = getBytesFromFile(fl);
pdfBytes =toObject(abc);
} catch (IOException ex) {
Logger.getLogger(print.class.getName()).log(Level.SEVERE, null, ex);
}
if (services.length>0)
{
DocPrintJob printJob = services[0].createPrintJob();
Doc document = new SimpleDoc(pdfBytes,flavor,null);
try {
printJob.print(document, null);
} catch (PrintException ex) {
Logger.getLogger(print.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
System.out.println("no pdf printer available");
}
}
}
I tried this and it solves my silent printing: https://gist.github.com/1094612
Here's an example on how to read a file into a byte[]:
// Returns the contents of the file in a byte array.
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// You cannot create an array using a long type.
// It needs to be an int type.
// Before converting to an int type, check
// to ensure that file is not larger than Integer.MAX_VALUE.
if (length > Integer.MAX_VALUE) {
// File is too large
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
import java.io.*;
import java.util.*;
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
public class ReadPDFFile {
public static void main(String[] args) throws IOException {
try {
Document document = new Document();
document.open();
PdfReader reader = new PdfReader("file.pdf");
PdfDictionary dictionary = reader.getPageN(1);
PRIndirectReference reference = (PRIndirectReference) dictionary
.get(PdfName.CONTENTS);
PRStream stream = (PRStream) PdfReader.getPdfObject(reference);
byte[] bytes = PdfReader.getStreamBytes(stream);
PRTokeniser tokenizer = new PRTokeniser(bytes);
StringBuffer buffer = new StringBuffer();
while (tokenizer.nextToken()) {
if (tokenizer.getTokenType() == PRTokeniser.TK_STRING) {
buffer.append(tokenizer.getStringValue());
}
}
String test = buffer.toString();
System.out.println(test);
} catch (Exception e) {
}
}
}
After compile and run it shows "no pdf printer available"
From my reading of the documentation here and here, the problem is you haven't configured print service provider that understands how to print documents with that DocFlavour.
One solution is to find a JAR file that implements the PrinterService SPI for PDF documents and add it to your classpath. A Google search will show examples. (I can't recommend any particular SP because I've never had to use one. You'll need to do some investigation / testing to find one that works for you.)