PDFBox PDFMergerUtility unstable on JavaFX application - java

My JavaFX application was downloading PDFs from the server, rotate to portrait if the PDF is landscape, and then merge all the PDF files into one single PDF file to print it out.
Everything went fine except the program will randomly stuck at outputting the merged PDF or adding one of the PDF files to PDFMergerUtility(which I am using PDFBox 2.0.11 and tried 2.0.9 also). Because my application requires a ProgressBar and TextArea to show the current action or status, I used a Task in my controller page. When the program hangs, it didn't enter any exception or print any message but completely stops the background action. I have tried small amount of files (<50 files) and large file tests (>1000), but they all have the same results of absolutely normal or randomly hangs.
Below are the code of my controller program:
public class ReadDataPageController implements Initializable {
public long startTime;
public long stopTime;
#FXML
private Button btnNext, btnCancel, btnPrevious;
#FXML
private Label infoLabel, time, total;
#FXML
private ProgressBar progBar;
#FXML
private TextArea textArea;
public Task<String> dlTask() {
return new Task<String>() {
#Override
protected String call() throws Exception {
DownloadUtil dlutil = new DownloadUtil();
StringBuilder textStr = new StringBuilder();
List<String> dlList = mainApp.DL_LIST;
// Download PDF files from FTP
super.updateValue(textStr.append("Preparing files for download...\n").toString());
for (int count = 0; count < dlList.size(); count++) {
String PDFLink = dlList.get(count).getPDFLink();
super.updateTitle("Downloading file" + PDFLink + " ...");
super.updateValue(textStr.append("Got " + PDFLink + "\n").toString());
try {
dlutil.exec(PDFLink);
// downloaded location will be stored inside List DownloadUtil.pdfList
} catch (IndexOutOfBoundsException ex) {
super.updateValue(textStr.append("Link not found for " + PDFLink + "\n").toString());
} catch (Exception ex) {
super.updateValue(textStr.append("Error while downloading " + PDFLink + " :" + ex.getMessage() + "\n").toString());
}
super.updateProgress(count + 1, dlList.size() * 3);
}
super.updateProgress(dlList.size(), dlList.size() * 3);
super.updateTitle("Download action has finished.");
super.updateValue(textStr.append("Download action has finished.\n").toString());
// Rotate downloaded PDFs
super.updateTitle("Preparing files for PDF rotation...");
super.updateValue(textStr.append("Preparing files for PDF rotation...\n").toString());
for (int i = 0; i < dlutil.pdfList.size(); i++) {
try {
String fileName = dlutil.pdfList.get(i);
rotatePDF(new File(fileName));
super.updateValue(textStr.append("Rotating PDF ("+(i+1)+" of "+dlutil.pdfList.size()+")...\n").toString());
} catch (Exception ex) {
super.updateValue(textStr.append("Error:" + ex.getMessage() + "...\n").toString());
ex.printStackTrace();
}
super.updateProgress(dlutil.pdfList.size() + i + 1, dlutil.pdfList.size() * 3);
}
if (PRINT_OPTION == PrintType.PRINT) {
// Merge downloaded PDFs
super.updateValue(textStr.append("Preparing files for PDF merging action...\n").toString());
PDFMergerUtility pdfutil = new PDFMergerUtility();
for (int i = 0; i < dlutil.pdfList.size(); i++) {
try {
String fileName = dlutil.pdfList.get(i);
pdfutil.addSource(fileName);
super.updateTitle("Adding files (" + (i + 1) + "/" + dlutil.pdfList.size() + ")");
} catch (Exception ex) {
super.updateValue(textStr.append("Error:" + ex.getMessage() + "...\n").toString());
ex.printStackTrace();
}
super.updateProgress(dlutil.pdfList.size()*2 + i + 1, dlutil.pdfList.size() * 3);
}
// Output merged pdf
try {
pdfutil.setDestinationFileName("../odt/merge.pdf");
pdfutil.mergeDocuments();
} catch (Exception ex) {
ex.printStackTrace();
}
super.updateTitle("Merged all PDFs.");
}
super.updateProgress(100, 100);
super.updateTitle("All action has been finished.");
super.updateValue(textStr.append("All action has been finished, press Next to choose your printing option.\n").toString());
return textStr.toString();
}
};
}
/**
* Rotates PDF images 90 degree if the PDF is portrait
* #param resource the PDF file path
* #throws InvalidPasswordException
* #throws IOException
*/
public void rotatePDF(File resource) throws InvalidPasswordException, IOException {
try {
PDDocument document = PDDocument.load(resource);
int pageCount = document.getNumberOfPages();
System.out.println("Reading file: "+resource+", total page="+pageCount);
for (int i = 0; i < pageCount; i++) {
PDPage page = document.getDocumentCatalog().getPages().get(i);
PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND,
false, false);
Matrix matrix = Matrix.getRotateInstance(Math.toRadians(90), 0, 0);
cs.transform(matrix);
cs.close();
PDRectangle cropBox = page.getCropBox();
if (cropBox.getWidth() > cropBox.getHeight()) {
System.out.println("ROTATE "+i+"th");
Rectangle rectangle = cropBox.transform(matrix).getBounds();
PDRectangle newBox = new PDRectangle((float) rectangle.getX(), (float) rectangle.getY(),
(float) rectangle.getWidth(), (float) rectangle.getHeight());
page.setCropBox(newBox);
page.setMediaBox(newBox);
document.save(resource);
}
}
document.close();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
}
}
Is there any reason that may cause the PDFMergerUtility unstable, maybe because I used a Task outside or because I missed something crucial?

Bingo! The exception was OutOfMemoryError, and Task from JavaFX made it silence.
I added the following code while initiating the task and it will handle the exceptions:
task.setOnFailed(new EventHandler<WorkerStateEvent>(){
#Override
public void handle(WorkerStateEvent event) {
Throwable th = task.getException();
System.out.println("Error on Task:"+th.getMessage());
th.printStackTrace();
}
});
To avoid OutOfMemoryError, I split the merging job into 100 pages per merging job, and save as multiple merged PDF files.

Related

JFileChooser not working when converted to .jar

So I'm pretty new to coding and I just started taking comp sci in school this year. In one of my programs I'm trying to use a JFileChooser and JButton so I just copied some code I found online and modified it since I don't know how to use try/catch yet:
JButton button = new JButton("Select File");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String path;
try {
path = new File(".").getCanonicalPath();
path = path.substring(0, path.length() - 7);
JFileChooser jf = new JFileChooser();
jf.setFileSelectionMode(JFileChooser.FILES_ONLY);
jf.setMultiSelectionEnabled(false);
int returnValue = jf.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION)
{
int n = ptoj.convert(jf.getSelectedFile().getAbsolutePath(), path);
for (int i = 0; i < n; i++)
{
if (i < 10)
{
PictureTester.split(path + "yourFile-0" + i + ".jpg", i);
}
else
{
PictureTester.split(path + "yourFile-" + i + ".jpg", i);
}
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
j.add(button);
The problem is when I run it in Eclipse, it works perfectly, but when I export it into a .jar file the program opens and it seems like its going to work, but when I try to press the button, nothing happens. It doesn't crash or anything, its just that nothing happens no matter how many times I press the button.
Here is the code to the class that the previous code was getting the method "convert" from:
public class ptoj {
public static int convert(String n, String path) throws Exception{
try (final PDDocument document = PDDocument.load(new File(n))){
PDFRenderer pdfRenderer = new PDFRenderer(document);
for (int page = 0; page < document.getNumberOfPages(); ++page)
{
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
String fileName;
if (page < 10)
{
fileName = path + "yourFile-0" + page + ".jpg";
}
else
{
fileName = path + "yourFile-" + page + ".jpg";
}
ImageIOUtil.writeImage(bim, fileName, 300);
}
document.close();
return document.getNumberOfPages();
} catch (IOException e){
System.err.println("Exception while trying to create pdf document - " + e);
}
return 0;
}
}

Running a JAVA Program with a Button (GUI)

I've been stumped on this all day, despite hours of research. Below is a basic idea of my program. It extracts data from links and puts it into a spreadsheet, and it can run for hours at a time. My intent is to connect this to a GUI with a progress bar. I'm trying to have an "upload" button, then a "Run" button.
For the "Run" button, I cannot figure out how to connect the button to running an instance of the below program.
I have attempted putting
App obj= new App();
obj.main(null);
under actionPerformed with no luck. I receive the following error:
Error:(31, 25) java: unreported exception java.lang.Exception;
must be caught or declared to be thrown
I understand now that we can't exactly call main functions. But in that case, how can I make my program work with a GUI? The main reason behind this is to be able to create a webapp for it in the future so that I can access it anywhere.
public class App {
private static final int[] URL_COLUMNS = { 0, 4, 9 }; // Columns A, E, J
public static void main(final String[] args) throws Exception {
Workbook originalWorkbook = Workbook.getWorkbook(new File("C:/Users/Shadow/Desktop/original.xls"));
WritableWorkbook workbook = Workbook.createWorkbook(new File("C:/Users/Shadow/Desktop/updated.xls"), originalWorkbook);
originalWorkbook.close();
WritableSheet sheet = workbook.getSheet(0);
Cell cell;
for (int i = 0; i < URL_COLUMNS.length; i++) {
int currentRow = 1;
while (!(cell = sheet.getCell(URL_COLUMNS[i], currentRow)).getType().equals(CellType.EMPTY)) {
String url = cell.getContents();
System.out.println("Checking URL: " + url);
if (url.contains("scrapingsite1.com")) {
String Price = ScrapingSite1(url);
System.out.println("Scraping Site1's Price: " + Price);
// save price into the next column
Label cellWithPrice = new Label(URL_COLUMNS[i] + 1, currentRow, Price);
sheet.addCell(cellWithPrice);
}
currentRow++;
}
}
workbook.write();
workbook.close();
}
private static String ScrapingSite1 (String url) throws IOException {
Document doc = null;
for (int i=1; i <= 6; i++) {
try {
doc = Jsoup.connect(url).userAgent("Mozilla/5.0").timeout(6000).validateTLSCertificates(false).get();
break;
} catch (IOException e) {
System.out.println("Jsoup issue occurred " + i + " time(s).");
}
}
if (doc == null){
return null;
}
else{
return doc.select("p.price").text();
}
}
}
At a crude guess I would say that the compiler is prompting you to change:
App obj= new App();
obj.main(null);
To one of several possibilities, this one based on 'must be caught' (try / catch):
try {
App obj= new App();
obj.main(null);
} catch(Exception e) {
e.printStackTrace(); // good fall back if logging not implemented
}
Edit: For more information, see the Exceptions lesson of the Java Tutorial.

Reuse threads to download next segment of file

I am looking for possible methods that can increase download speed and improve cpu, memory performance. Currently I am downloading file in segments and transferring data using java nio transferFrom function.
public void startDownload() {
threadService.execute(() -> {
double currentBytes = bytesDone.doubleValue();
//Download each segment independently.
for (int i = 0; i < segments; i++) {
if (intialState[i] != -1) {
threadService.execute(new Segment((i * sizeOfEachSegment)
+ intialState[i], (i + 1) * sizeOfEachSegment, i));
}
}
if (intialState[segments] != -1) {
threadService.execute(new Segment((segments * sizeOfEachSegment)
+ intialState[segments], sizeofFile, segments));
}
// Keep saving states of threads. And updating speed.
while (bytesDone.get() < sizeofFile) {
for (int i = 0; i < 1; i++) {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
System.out.println("thread interupted while sleeping");
}
System.out.println(speed
= (int) ((bytesDone.doubleValue() - currentBytes) / 5120));
currentBytes = bytesDone.doubleValue();
avgSpeed[0] += speed;
avgSpeed[1]++;
}
states.saveState(stateArray, currentState);
}
// Download Complete.
try {
fileChannel.close();
file.close();
} catch (IOException ex) {
System.out.println("failed to close file");
}
currentState.set(2);
states.saveState(stateArray, currentState);
System.out.println("Alhamdullilah Done :)");
System.out.println("Average Speed : " + avgSpeed[0] / avgSpeed[1]);
});
}
public class Segment implements Runnable {
long start;
long end;
long delta;
int name;
public Segment(long start, long end, int name) {
this.start = start;
this.end = end;
this.name = name;
}
#Override
public void run() {
try {
HttpGet get = new HttpGet(uri);
// Range header for defining which segment of file we want to receive.
String byteRange = start + "-" + end;
get.setHeader("Range", "bytes=" + byteRange);
try (CloseableHttpResponse response = client.execute(get)) {
ReadableByteChannel inputChannel = Channels.newChannel(
response.getEntity().getContent());
while (start < end && currentState.get() == 1) {
delta = fileChannel.transferFrom(inputChannel, start, 8192);
start += delta;
bytesDone.addAndGet(delta);
stateArray.set(name, start);
}
stateArray.set(name, -1);
}
System.out.println("Thread done: " + name);
} catch (IOException ex) {
System.out.println("thread " + name + " failed to download");
}
}
}
This implementation gives 400+ kb/s but Internet Download Manager downloads same file at 500+ kb/s.
Are there any resources I can reuse(I noticed every connection initially takes time to reach its maximum speed so is there any way i can reuse the same thread to download the next portion of file as soon as it complete downloading previous)?

How to record video from webcam in a lossless format?

I'm trying to write an application which can record video in a lossless format. For this purpose I use Webcam-Capture and Xuggler libraries. Everything works but the outout video has the following artifacts:
And this is observed not at all frames, nearly 1 of 5 ones. My code:
#FXML
public void record() {
File file = new File("output.wmv");
IMediaWriter writer = ToolFactory.makeWriter(file.getName());
Dimension size = WebcamResolution.VGA.getSize();
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_RAWVIDEO, size.width, size.height);
Webcam webcam = Webcam.getDefault();
webcam.setViewSize(size);
webcam.open(true);
long start = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
System.out.println("Capture frame " + i);
BufferedImage image = ConverterFactory.convertToType(webcam.getImage(), BufferedImage.TYPE_3BYTE_BGR);
IConverter converter = ConverterFactory.createConverter(image, IPixelFormat.Type.YUV420P);
IVideoPicture frame = converter.toPicture(image, (System.currentTimeMillis() - start) * 1000);
frame.setKeyFrame(i == 0);
frame.setQuality(100);
writer.encodeVideo(0, frame);
// 10 FPS
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
writer.close();
System.out.println("Video recorded in file: " + file.getAbsolutePath());
}
What am I doing wrong?
Needs more information on your dependencies. Links maybe?

Fonts do not display correctly - Java

I have some words in English that have been translated into Tamil. The task requires me to display them. An example line is given below. The first and second lines are in Tamil while the last is in Bengali.
> unpopular ஜனங்கலால் வெறுக்கப்பட்ட ¤µ£»ªÀ»õu
inactive ஜடமான ö\¯»ØÓ
doctor வைத்தியர் ©¸zxÁº
apart வேறாக uµ
If you notice above, the text in some lines does not render correctly because it is written in custom fonts. The custom font can be downloaded from here. My problem:
1. All Tamil fonts (custom and pre-loaded) have been installed. None of the text displays correctly. Why?
2. Is there a problem with the way that I am loading custom fonts?
3. In the above lines, the second column is pre-loaded font while the third column is written in custom fonts. The third column does not seem like it is Unicode, which is why application of any font also fails. What is going on?
import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
/* This is the imageMaker class.
* It loads a plain white image, writes text taken from another file
* and creates a new image from it.
*
* Steps:
* 1. A plain white image is loaded.
* 2. Text is taken from a file.
* 3. Text is written to the image.
* 4. New image is created and saved.
*/
public class imgMaker_so {
/**
* #param args
*/
private static String tgtDir = "YOUR_tgt directory to store images goes here";
private static String csvFile = "csv file goes here";
private static int fontSize = 22; //default to a 22 pt font.
private static Font f;
private static String fontName = "WTAM001";
public static void main(String[] args) {
// TODO Auto-generated method stub
//Step 0. Read the image.
//readPlainImage(plainImg);
//Step 0.a: Check if the directory exists. If not, create it.
File tgtDir_file = new File(tgtDir);
if(!tgtDir_file.exists()) { //this directory does not exist.
tgtDir_file.mkdir();
}
Font nf = null;
try {
nf = Font.createFont(Font.TRUETYPE_FONT, new File("C:\\Windows\\Fonts\\" + fontName + ".ttf"));
} catch (FontFormatException | IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
if(nf != null) {
f = nf.deriveFont(Font.BOLD, fontSize);
}
if(f == null) {
System.out.println("Font is still null.");
}
//Step 1. Read csv file and get the string.
FileInputStream fis = null;
BufferedReader br = null;
try {
fis = new FileInputStream(new File(csvFile));
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String temp = "\u0b85";
System.out.println(temp.length());
for(int i = 0; i < temp.length(); i++) {
System.out.print(temp.charAt(i));
}
//SAMPLE CODE ONLY. CHECK IF IT CAN PRINT A SINGLE CHARACTER IN FONT.
BufferedImage img = new BufferedImage(410, 200, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 410, 200);
System.out.println("String being printed = " + temp.codePointAt(0));
g.setColor(Color.BLACK);
g.setFont(f);
if(f.canDisplay('\u0b85')) {
System.out.println("Can display code = \u0b85");
} else {
System.out.println("Cannot display code = \u0b85");
}
g.drawString(temp, 10, 35);
//g.drawString(translation, 10, fontWidth); //a 22pt font is approx. 35 pixels long.
g.dispose();
try {
ImageIO.write(img, "jpeg", new File(tgtDir + "\\" + "a.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("File written successfully to a");
//System.out.println("Cat,,बिल्ली,,,");
if(fis != null) {
try {
br = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
} catch (UnsupportedEncodingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
System.out.print("Unsupported encoding");
}
String line = null;
if(br != null) {
try {
while((line = br.readLine()) != null) {
if(line != null) {
System.out.println("Line = " + line);
List<String> word_translation = new ArrayList<String>();
parseLine(line, word_translation); //function to parse the line.
//printImages(word_translation);
if(word_translation.size() > 0) {
printImages_temp(word_translation);
}
//now that images have been read, read the plain image afresh.
//readPlainImage(plainImg);
word_translation.clear();
}
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
public static void printImages_temp(List<String> list) {
/* Function to print translations contained in list to images.
* Steps:
* 1. Take plain white image.
* 2. Write English word on top.
* 3. Take each translation and print one to each line.
*/
String dest = tgtDir + "\\" + list.get(0) + ".jpg"; //destination file image.
//compute height and width of image.
int img_height = list.size() * 35 + 20;
int img_width = 0;
int max_length = 0;
for(int i = 0; i < list.size(); i++) {
if(list.get(i).length() > max_length) {
max_length = list.get(i).length();
}
}
img_width = max_length * 20;
System.out.println("New dimensions of image = " + img_width + " " + img_height);
BufferedImage img = new BufferedImage(img_width, img_height, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, img_width, img_height);
//image has to be written to another file. Do not write English word, which is why list starts iteration from 1.
for(int i = 1; i < list.size(); i++) {
System.out.println("String being printed = " + list.get(i).codePointAt(0));
g.setColor(Color.BLACK);
g.setFont(f);
g.drawString(list.get(i), 10, (i + 1) * 35);
}
//g.drawString(translation, 10, fontWidth); //a 22pt font is approx. 35 pixels long.
g.dispose();
try {
ImageIO.write(img, "jpeg", new File(dest));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("File written successfully to " + dest);
}
public static void purge(String line) {
//This removes any inverted commas and tabs from the line apart from trimming it.
System.out.println("Line for purging = " + line);
int fromIndex = line.indexOf("\"");
//System.out.println("from index = " + fromIndex);
if(fromIndex != -1) {
line = line.substring((fromIndex + 1));
int toIndex = line.lastIndexOf("\"", line.length() - 1);
if(toIndex != -1) {
line = line.substring(0, (toIndex));
}
}
line.replaceAll("\t", " ");
line.trim();
System.out.println("Line after purging = " + line);
}
public static void parseLine(String line, List<String> result) {
/*
* This function parses the string and gets the different hindi meanings.
*/
//int index = line.indexOf(",");
//int prev_index = 0;
String[] arr = line.split(",");
List<String> l = new ArrayList<String>(Arrays.asList(arr));
for(int i = 0; i < l.size(); i++) {
if(l.get(i).isEmpty()) { //if the string at position i is empty.
l.remove(i);
}
}
for(int i = 0; i < l.size(); i++) { //inefficient copy but should be short.
String ith = l.get(i).trim();
if(!(ith.isEmpty())) { //add a string to result only if it is non-empty.
//in some entries, there are commas. they have been replaced with !?. find them and replace them.
if(ith.contains("!?")) {
//System.out.println(r + " contains !?");
String r = ith.replace("!?", ",");
result.add(r);
} else if(ith.contains("\n")) {
String r = ith.replace("\n", " ");
System.out.println("found new line in " + ith);
result.add(r);
} else {
result.add(ith);
}
}
}
for(int i = 0; i < result.size(); i++) {
System.out.println("Result[" + i + "] = " + result.get(i));
}
//System.out.println("Line being printed = " + line);
}
}
The above text was written by professional translators. So, is there something here that I am missing?
to test the concrete Font with methods in API Font.canDisplay
required to test in Unicode form (for mixing chars from a few languages (Tamil & Bengali))
please can you post and SSCCE, with used Font and can be based on

Categories