How to create uninitialised static final variables in Java - java

The code below produces the compiler error Variable HEIGHT might not have been initialized (same goes for WIDTH).
How can I declare an uninitialized static final variable like what I'm trying to do below?
public static final int HEIGHT, WIDTH;
static{
try {
currentImage = new Image("res/images/asteroid_blue.png");
WIDTH = currentImage.getWidth();
HEIGHT = currentImage.getHeight();
}catch (SlickException e){
e.printStackTrace();
}
}

static {
Image currentImage = null;
try {
currentImage = new Image("res/images/asteroid_blue.png");
} catch (Exception e) {
// catch exception - do other stuff
} finally {
if (currentImage != null) {
WIDTH = currentImage.getWidth();
HEIGHT = currentImage.getHeight();
} else {
// initialise default values
WIDTH = 0;
HEIGHT = 0;
}
}
}
Whatever happens (try/catch), you have to assign values to the static variables - therefor, finally should be used.

The right way would be to set the values to null (in case its an object), but since it's final you'll have to do this roundabout:
public static final int HEIGHT, WIDTH;
static{
int w = 0, h = 0;
try {
currentImage = new Image("res/images/asteroid_blue.png");
w = currentImage.getWidth();
h = currentImage.getHeight();
}catch (SlickException e){
e.printStackTrace();
}
WIDTH = w;
HEIGHT = h;
}

You can do this but you need to exit the static block by throwing an exception
public static final int HEIGHT, WIDTH;
static{
try {
currentImage = new Image("res/images/asteroid_blue.png");
WIDTH = currentImage.getWidth();
HEIGHT = currentImage.getHeight();
}catch (SlickException e){
e.printStackTrace();
throw new RuntimeException("Could not init class.", e);
}
}

You can't. final variables can only be assigned values during initialization, hence why you're receiving compiler error (the variables will stay null). It's used to ensure consistency.
You can either drop the final keyword or make HEIGHT and WIDTH local variables.
currentImage = new Image("res/images/asteroid_blue.png");
final int width= currentImage.getWidth();
final int height = currentImage.getHeight();

Related

Find dynamic image on sikuliX created problems with buffer

I'm trying to find an image that I create previously inside an empty template with this function that insert text on it receiving color, content and font and return the path of generate image:
the template
public String insertTextOnBlanck(String colorLetter,String text,Font font) {
//path is a private varibable initialized with the constructor
File blankFile = new File("images/dinamic/"+path);
BufferedImage image = null;
String exit_path = null;
try {
image = ImageIO.read(blankFile);
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
Graphics2D g2 = image.createGraphics();
FontMetrics metrics = g2.getFontMetrics(font);
BufferedImage resizeImage = resizeImage(image,type, text,metrics);
image.flush();
int w = resizeImage.getWidth();
int h = resizeImage.getHeight();
g2 = resizeImage.createGraphics();
g2.setColor(Color.decode(colorLetter));
g2.setFont(font);
// Get the FontMetrics
int x = (w - metrics.stringWidth(text)) / 2;
int y = (metrics.getAscent() + (h - (metrics.getAscent() + metrics.getDescent())) / 2);
g2.setBackground(Color.decode("#d1e8f8"));
g2.drawString(text, x, y);
g2.dispose();
//create image with text
exit_path = "images/dinamic/changed_"+path;
File file = new File(exit_path);
ImageIO.write(resizeImage, "png", file);
resizeImage.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return exit_path;
}
and this works the fist time when i call this other function
public void dinamicClick(String path,String input,String fontLetter,String colorLetter, int fontType,int size) throws FindFailed {
DinamicImg DimImg = new DinamicImg();
DimImg.setPath(path);
String modPath = DimImg.insertTextOnBlanck(
colorLetter,
input,//Inventario de recurso
new Font(fontLetter,fontType, size)
);
Iterator<Match> myIt = s.findAll(modPath);
while (myIt.hasNext()) {
Location loc = myIt.next().getTarget();
s.click(loc);
}
myIt.remove();
removeFile(modPath);
}
the removeFile function is:
private void removeFile(String toRemove) {
File file = new File(toRemove);
if(file.delete()){
System.out.println(file.getName() + " is deleted!");
}else{
System.out.println("Delete operation is failed.");
}
}
The result:
but next calls dont work at all, just when i change the name of exit path, so i thought was a cache problem but adding ImageIO.setUseCache(false); at start of "insertTextOnBlanck" function still doesn`t work. Im out of ideas please help, thanks.
I resolve it , with the libary org.sikuli.script.ImagePath you ve to reset the paths of the internal cache of SikuliX with ImagePath.reset().

Write text to image in multiple fonts with wrapping in java

I am trying to create an image with a given text and style. eg;
" textStyle(Offer ends 25/12/2016. Exclusions Apply., disclaimer) textStyle(See Details,underline) "
In above line i am splitting and creating a map that stores the first parameter of textStyle block as key and second parameter as value where second param defines the style to be applied on first param. Hence an entry of map will look like .
Now when i iterate over this map to write the text to image i check if the text is overflowing the width. If yes then it breaks the text and adds it to next line in the horizontal center. So for example lets say i am trying to write "Offer ends 25/12/2016. Exclusions Apply." with Arial and font size 12. While writing i find that i can write till "Offer ends 23/12/2016. " only and "Exclusions apply" has to go in next line. But it writes the text in horizontal center neglecting that as there is space left horizontally i can write "See Details" too in the same line.
Please help. Below is the code what i have tried. I have also tried creating a JTextPane and then converting it to image but this cannot be an option as it first creates the frame, makes it visible, writes it and then disposes it. And most of the times i was getting Nullpointer exception on SwingUtilities.invokeAndWait.
Actual : http://imgur.com/7aIlcEQ
Expected http://imgur.com/038zQTZ
public static BufferedImage getTextImage(String textWithoutStyle, Map<String, String> textToThemeMap, Properties prop, int height, int width) {
BufferedImage img = new BufferedImage(width,height,BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = img.createGraphics();
g2d.setPaint(Color.WHITE);
FontMetrics fm = g2d.getFontMetrics();
Map<String, Font> textToFontMap = new LinkedHashMap<String, Font>();
for(Map.Entry<String, String> entry : textToThemeMap.entrySet()) {
if(StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())) {
Font font = getFont(prop, entry.getValue().trim());
g2d.setFont(font);
fm = g2d.getFontMetrics();
String string = entry.getKey();
char[] chars = null;
int i = 0, pixelWidth = 0;
List<String> newTextList = new ArrayList<String>();
if(fm.stringWidth(string) > (width - 10)) {
chars = string.toCharArray();
for (i = 0; i < chars.length; i++) {
pixelWidth = pixelWidth + fm.charWidth(chars[i]);
if(pixelWidth >= (width - 10)) {
break;
}
}
String newString = WordUtils.wrap(string, i, "\n",false);
String[] splitString = newString.split("\n");
for(String str : splitString) {
newTextList.add(str);
textToFontMap.put(string, font);
}
} else {
newTextList.add(string);
textToFontMap.put(string, font);
}
}
}
Font font = new Font("Arial", Font.BOLD, 14);
int spaceOfLineHeight = (textToFontMap.size() - 1) * 7;
int spaceOfText = textToFontMap.size() * font.getSize();
int totalSpace = spaceOfLineHeight + spaceOfText ;
int marginRemaining = height - totalSpace;
int tempHt = marginRemaining / 2 + 10;
String txt = null;
for(Map.Entry<String, Font> entry : textToFontMap.entrySet()) {
txt = entry.getKey();
font = entry.getValue();
g2d.setFont(font);
fm = g2d.getFontMetrics();
int x = (width - fm.stringWidth(txt)) / 2;
int y = tempHt;
g2d.drawString(txt, x, y);
tempHt = tempHt + fm.getHeight();
}
// g2d.drawString(text.getIterator(), 0, (int)lm.getAscent() + lm.getHeight());
// g2d.dispose();
return img;
}
// Code with JTextPane ------------------------------------------
public static BufferedImage getTextImage(final Map < String, String > textToThemeMap, final Properties prop, final int height, final int width) throws Exception {
JFrame f = new JFrame();
f.setSize(width, height);
final StyleContext sc = new StyleContext();
DefaultStyledDocument doc = new DefaultStyledDocument(sc);
final JTextPane pane = new JTextPane(doc);
pane.setSize(width, height);
// Build the styles
final Paragraph[] content = new Paragraph[1];
Run[] runArray = new Run[textToThemeMap.size()];
int i = 0;
for (Map.Entry < String, String > entry: textToThemeMap.entrySet()) {
if (StringUtils.isNotBlank(entry.getValue().trim()) && StringUtils.isNotBlank(entry.getKey().trim())) {
Run run = new Run(entry.getValue().trim(), entry.getKey());
runArray[i++] = run;
}
}
content[0] = new Paragraph(null, runArray);
/*createDocumentStyles(sc, prop,textToThemeMap.values());
addText(pane, sc, sc.getStyle("default"), content);
pane.setEditable(false);*/
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
createDocumentStyles(sc, prop, textToThemeMap.values());
} catch (MalformedURLException e) {
//e.printStackTrace();
}
addText(pane, sc, sc.getStyle("default"), content);
pane.setEditable(false);
}
});
} catch (Exception e) {
System.out.println("Exception when constructing document: " + e);
}
f.getContentPane().add(pane);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D gd = img.createGraphics();
f.paint(gd);
f.dispose();
/*ImageIO.write(img, "png", new File("C:\\Users\\spande0\\Desktop\\a.png"));
System.out.println("done");*/
return img;
}
I suspect the issue is in your 'Y' computation.
int spaceOfLineHeight = (newTextList.size() - 1) * 7;
int spaceOfText = newTextList.size() * font.getSize();
int totalSpace = spaceOfLineHeight + spaceOfText;
int marginRemaining = height - totalSpace;
int tempHt = marginRemaining / 2 + 10;
You have to keep the height occupied by the previous lines, and add it to the current 'Y'.
At the moment, for all the lines, the 'Y' values is same.
Declare prevHeight outside the for loop. and then do the following.
int tempHt = marginRemaining / 2 + 10;
tempHT += prevHeight;
prevHeight = tempHeight
Based on the comments, I will suggest you to break down your function into two smaller functions.
// Loop through the strings and find out how lines are split and calculate the X, Y
// This function will give the expected lines
splitLinesAndComputeResult
// Just render the lines
renderLines

Printing a text document using Java

Alright, I have made a program that makes a text file. The text file is a different size every time the program is ran. I simply just want to add a print button that allows the user to print out the text file to a printer. I made a button with an action listener that brings up my print class. It is almost working except it only prints one page with my text displayed in horizontal columns extremely small. I think my problem has something to do with my printJob setup. Any help would be greatly appreciated.
public class PrintingClass implements Printable {
// Global variables
int[] pageBreaks;
String [] textLines;
static String fileName;
public static void print(String filename){
fileName = filename;
PrintingClass object = new PrintingClass();
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(object);
Boolean ok = job.printDialog();
if (ok) {
try {
job.print();
} catch (PrinterException ex) {
/* The job did not successfully complete */
}
}
}
public int print(Graphics g, PageFormat pf, int pageIndex)
throws PrinterException {
Font font = new Font("Monospaced", Font.PLAIN, 12);
FontMetrics metrics = g.getFontMetrics(font);
int lineHeight = metrics.getHeight();
if (pageBreaks == null) {
initTextLines();
int linesPerPage = (int)(pf.getImageableHeight()/lineHeight);
System.out.println("Lines per page = " + linesPerPage);
int numBreaks = (textLines.length-1)/linesPerPage;
System.out.println("number of pages = " + numBreaks);
pageBreaks = new int[numBreaks];
for (int b=0; b<numBreaks; b++) {
pageBreaks[b] = (b+1)*linesPerPage;
}
}
if (pageIndex > pageBreaks.length) {
return NO_SUCH_PAGE;
}
/* User (0,0) is typically outside the imageable area, so we must
* translate by the X and Y values in the PageFormat to avoid clipping
* Since we are drawing text we
*/
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
/* Draw each line that is on this page.
* Increment 'y' position by lineHeight for each line.
*/
int y = 0;
int start = (pageIndex == 0) ? 0 : pageBreaks[pageIndex-1];
int end = (pageIndex == pageBreaks.length)
? textLines.length : pageBreaks[pageIndex];
for (int line=start; line<end; line++) {
y += lineHeight;
g.drawString(textLines[line], 0, y);
}
/* tell the caller that this page is part of the printed document */
return PAGE_EXISTS;
}
/**
* This will initialize the textLines[] variable
* and read in my file
* #param fileName
*/
public void initTextLines(){
// Get file size
int fileSize = counter();
// Initialize textLine
textLines = new String[fileSize];
// Read text to set lines
BufferedReader file;
try {
file = new BufferedReader(new FileReader(fileName));
String line = null;
int x = 0;
while((line = file.readLine()) != null){
textLines[x] = line;
x++;
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* This will simply count the size of the file
* and return it
* #return
*/
public int counter(){
int count = 0;
try {
BufferedReader file = new BufferedReader(new FileReader(fileName));
while(file.readLine() != null){
count++;
}
file.close();
} catch (IOException e) {
e.printStackTrace();
}
return count;
}
}
Most of this code comes straight from Javas own tutorial page. Thank you.

java.io.IOException: RandomAccessBuffer already closed, when reading a PDPage

I've created a program to convert a PDF to Excel. The conversion takes a long time (100 page=10 minutes). It runs fine for about 15-20 minutes, after that an error occurs when reading the PDPage.
Is it possible the Java GC "clean" the variable before the programs end?
the code:
private class Search_Text implements Runnable {
private int x, y, width, height;
private PDPage pdPage;
private Object lock;
private ArrayList<Object[]> result;
private PDFTextStripperByArea strip;
public Search_Text(int x, int y, int width, int height, PDPage pdPage, Object lock) throws IOException {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.pdPage = pdPage;
this.lock = lock;
this.result = new ArrayList<>();
this.strip = new PDFTextStripperByArea();
}
#Override
public void run() {
if (height < 10) {
int upper = y;
int bottom = 1;
ArrayList<Object[]> st = new ArrayList<>();
String str = "";
while (upper + bottom <= y + height) {
strip.addRegion("cell", new Rectangle(x, upper, width, bottom));
//System.out.println("prova.Pdf2Excell.log_extract()BEFORE LOCK" + init);
synchronized (lock) {
try {
strip.extractRegions(pdPage);
} catch (IOException ex) {
Logger.getLogger(Pdf2Excell.class.getName()).log(Level.SEVERE, null, ex);
}
}
str = strip.getTextForRegion("cell");
if (!emptyString(str)) {
st.add(new Object[]{str, upper + bottom, upper});
upper += bottom;
bottom = 1;
while (upper + bottom < height + y && !emptyString(str)) {
strip.addRegion("cell", new Rectangle(x, upper, width, bottom));
synchronized (lock) {
try {
strip.extractRegions(pdPage);
} catch (IOException ex) {
Logger.getLogger(Pdf2Excell.class.getName()).log(Level.SEVERE, null, ex);
}
}
str = strip.getTextForRegion("cell");
upper++;
//System.out.println("prova.Pdf2Excell.pdf2EX()DENTRO");
}
} else {
bottom += 1;
//System.out.println("prova.Pdf2Excell.pdf2EX()UPPER;;"+upper+";;BOTTOM;;" + bottom);
}
if (upper == y) {
st.add(new Object[]{"", y + height, upper});
}
result = st;
}
} else {
try {
int half_rec = height / 2;
Rectangle first_rec = new Rectangle(x, y, width, half_rec);
Rectangle last_rec = new Rectangle(x, y + half_rec, width, height - half_rec);
Search_Text first_search = new Search_Text(x, y, width, half_rec, pdPage, lock);
Search_Text last_search = new Search_Text(x, y + half_rec, width, height - half_rec, pdPage, lock);
Thread first = new Thread(first_search);
Thread last = new Thread(last_search);
strip.addRegion("cell", first_rec);
synchronized (lock) {
strip.extractRegions(pdPage);
}
String temp = strip.getTextForRegion("cell");
if (!emptyString(temp)) {
first.start();
}
strip.addRegion("cell", last_rec);
synchronized (lock) {
strip.extractRegions(pdPage);
}
temp = strip.getTextForRegion("cell");
if (!emptyString(temp)) {
last.start();
}
first.join();
last.join();
result = first_search.getResult();
ArrayList<Object[]> temp_res = last_search.getResult();
for (int i = 0; i < temp_res.size(); i++) {
result.add(temp_res.get(i));
}
} catch (InterruptedException | IOException ex) {
Logger.getLogger(Pdf2Excell.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
This is the error message:
Exception in thread "Thread-214418" java.lang.RuntimeException: java.io.IOException: RandomAccessBuffer already closed
at org.apache.pdfbox.pdfparser.PDFStreamParser$1.tryNext(PDFStreamParser.java:198)
at org.apache.pdfbox.pdfparser.PDFStreamParser$1.hasNext(PDFStreamParser.java:205)
at org.apache.pdfbox.util.PDFStreamEngine.processSubStream(PDFStreamEngine.java:255)
at org.apache.pdfbox.util.PDFStreamEngine.processSubStream(PDFStreamEngine.java:235)
at org.apache.pdfbox.util.PDFStreamEngine.processStream(PDFStreamEngine.java:215)
at org.apache.pdfbox.util.PDFTextStripper.processPage(PDFTextStripper.java:458)
at org.apache.pdfbox.util.PDFTextStripperByArea.extractRegions(PDFTextStripperByArea.java:153)
at prova.Pdf2Excell$Search_Text.run(Pdf2Excell.java:954)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: RandomAccessBuffer already closed
at org.apache.pdfbox.io.RandomAccessBuffer.checkClosed(RandomAccessBuffer.java:325)
at org.apache.pdfbox.io.RandomAccessBuffer.seek(RandomAccessBuffer.java:105)
at org.apache.pdfbox.io.RandomAccessFileInputStream.read(RandomAccessFileInputStream.java:96)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at java.io.PushbackInputStream.read(PushbackInputStream.java:139)
at org.apache.pdfbox.io.PushBackInputStream.read(PushBackInputStream.java:90)
at org.apache.pdfbox.io.PushBackInputStream.peek(PushBackInputStream.java:68)
at org.apache.pdfbox.pdfparser.PDFStreamParser.hasNextSpaceOrReturn(PDFStreamParser.java:560)
at org.apache.pdfbox.pdfparser.PDFStreamParser.parseNextToken(PDFStreamParser.java:408)
at org.apache.pdfbox.pdfparser.PDFStreamParser.parseNextToken(PDFStreamParser.java:374)
at org.apache.pdfbox.pdfparser.PDFStreamParser.access$000(PDFStreamParser.java:49)
at org.apache.pdfbox.pdfparser.PDFStreamParser$1.tryNext(PDFStreamParser.java:193)
... 8 more
PDFBox has been developed for single-threaded use per document while the OP accesses the same document using multiple threads. While this may still work (because it is a read-only use case), proper synchronization is necessary.
This synchronization most likely would have slowed down everything still more. Thus, the solution was to use a different architecture altogether, namely to
take PDFTextStripper, override writeString(String text, List<TextPosition> textPositions), and collect the required information from that List<TextPosition> textPositions. TextPosition contains information on a small piece of text (usually a single letter, I think), including its position.
The result turned out to be
like 4 times faster.

First line and last line in jtextarea viewport

i am looking for a function which gives the viewport starting line and viewport ending line from jtextarea. The below code works fine. But when the number of lines in the jtextarea is too big, say 10,000 lines, response of the cursor becoming very slow. I narrowed down the line which is causing it, it is,
startLine = getRow(topLeft, editorTextArea) - 1; //editorTextArea is jtextarea name
endLine = getRow(bottomRight, editorTextArea);
I am calling the startAndEndLine() on every keyPressEvent
Can someone suggest me a better code, which is efficient?
private void startAndEndLine() {
Rectangle r = editorTextArea.getVisibleRect();
Point topLeft = new Point(r.x, r.y);
Point bottomRight = new Point(r.x + r.width, r.y + r.height);
try {
startLine = getRow(topLeft, editorTextArea) - 1;
endLine = getRow(bottomRight, editorTextArea);
} catch (Exception ex) {
// System.out.println(ex);
}
}
public int getViewToModelPos(Point p, JTextComponent editor) {
int pos = 0;
try {
pos = editor.viewToModel(p);
} catch (Exception ex) {
}
return pos;
}
public int getRow(Point point, JTextComponent editor) {
int pos = getViewToModelPos(point, editor);
int rn = (pos == 0) ? 1 : 0;
try {
int offs = pos;
while (offs > 0) {
offs = Utilities.getRowStart(editor, offs) - 1;
rn++;
}
} catch (BadLocationException e) {
System.out.println(e);
}
return rn;
}
This is based on a solution by JigarJoshi from this question Java: column number and line number of cursor's current position ... You gotta love this site ;)
protected int getLineNumber(int modelPos) throws BadLocationException {
return textArea.getLineOfOffset(modelPos) + 1;
}
Rectangle viewRect = scrollPane.getViewport().getViewRect();
Point startPoint = viewRect.getLocation();
int pos = textArea.viewToModel(startPoint);
try {
int startLine = getLineNumber(pos);
Point endPoint = startPoint;
endPoint.y += viewRect.height;
pos = textArea.viewToModel(endPoint);
int endLine = getLineNumber(pos);
System.out.println(startLine + " - " + endLine);
} catch (BadLocationException exp) {
}
This is not entirely accurate, but gives you a starting point.

Categories