LWJGL / STB: Inconsistency when running in IntelliJ vs. running over Console - java

I have a problem when using LWJGL and STB TrueType in IntelliJ.
When I now try to create a bitmap and put everything in Main ('Code 1' below), everything works fine.
As soon as I try to split this up and create an OpenGL context (If I split it up without creating an OpenGL context it works fine as well), the loaded font gets corrupted somehow and either the program crashes with an ACCESS_VIOLATION or runs without generating the bitmap. You can see the broken code as 'Code 2' below.
The wrong behaviour though only occurs when running with the java run arguments, that IntelliJ uses - either via Intellij Run or via Console.
It doesnt occur dont happen when building into a JAR and running this.
The problematic argument is the following. If this one is missing in the console, it runs.
-javaagent:<INTELLIJ_HOME>\lib\idea_rt.jar=52850:<INTELLIJ_HOME>\bin
I have read here that the idea_rt.jar file "is needed to provide graceful shutdown/exit/stacktrace features" and therefore I do not want to disable it in IntelliJ.
NOTE: In the broken code ('Code 2' below) you will notice an 'unnecessary' line
ByteBuffer data2 = loadByteBufferFromResource("/fonts/arial.ttf"); which simulates loading multiple fonts. If I only load one font, everything works fine.
You will also notice the OpenGL context creation in code 2, which also seems to be a cause of the problem (as I described above)
Code 1 (works)
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL;
import org.lwjgl.stb.STBTTFontinfo;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.stb.STBTruetype.stbtt_GetCodepointBitmap;
import static org.lwjgl.stb.STBTruetype.stbtt_InitFont;
public class STBTTExampleOnlyMain {
private static ByteBuffer loadByteBufferFromResource(String resource) throws IOException {
try(InputStream stream = STBTTExampleOnlyMain .class.getResourceAsStream(resource)) {
byte[] bytes = stream.readAllBytes();
ByteBuffer buffer = BufferUtils.createByteBuffer(bytes.length);
buffer.put(bytes);
buffer.flip();
return buffer;
}
}
public static void main(String[] args) throws IOException {
ByteBuffer data = loadByteBufferFromResource("/fonts/arial.ttf");
ByteBuffer data2 = loadByteBufferFromResource("/fonts/arial.ttf");
STBTTFontinfo font = STBTTFontinfo.create();
stbtt_InitFont(font, data);
IntBuffer bufWidth = BufferUtils.createIntBuffer(1);
IntBuffer bufHeight = BufferUtils.createIntBuffer(1);
ByteBuffer bitmap = stbtt_GetCodepointBitmap(font, 0, 1, 'a', bufWidth, bufHeight, null, null);
System.out.println(bitmap);
}
}
Code 2 (broken)
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL;
import org.lwjgl.stb.STBTTFontinfo;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.stb.STBTruetype.stbtt_GetCodepointBitmap;
import static org.lwjgl.stb.STBTruetype.stbtt_InitFont;
public class STBTTExample {
private static final Map<Integer, STBTTFontinfo> fontMap = new HashMap<>();
private static ByteBuffer loadByteBufferFromResource(String resource) throws IOException {
try(InputStream stream = STBTTExample.class.getResourceAsStream(resource)) {
byte[] bytes = stream.readAllBytes();
ByteBuffer buffer = BufferUtils.createByteBuffer(bytes.length);
buffer.put(bytes);
buffer.flip();
return buffer;
}
}
private static void initFont() throws IOException {
ByteBuffer data = loadByteBufferFromResource("/fonts/arial.ttf");
ByteBuffer data2 = loadByteBufferFromResource("/fonts/arial.ttf");
STBTTFontinfo font = STBTTFontinfo.create();
stbtt_InitFont(font, data);
fontMap.put(0, font);
}
public static void main(String[] args) throws IOException {
initFont();
glfwInit();
glfwDefaultWindowHints();
long windowHandle = glfwCreateWindow(800, 600, "Test", 0, 0);
glfwMakeContextCurrent(windowHandle);
GL.createCapabilities();
IntBuffer bufWidth = BufferUtils.createIntBuffer(1);
IntBuffer bufHeight = BufferUtils.createIntBuffer(1);
ByteBuffer bitmap = stbtt_GetCodepointBitmap(fontMap.get(0), 0, 1, 'a', bufWidth, bufHeight, null, null);
System.out.println(bitmap);
}
}
How can fix the problem of not being able to run the program out of IntelliJ when working with text rendering?
Am I maybe misunderstanding the STBTT library and actually can't work with fonts this way?
Any help would be appreciated to understand what is wrong and fix this.

I have asked the question in the LWJGL forum and got it solved.
The STBTTFontinfo object contains metadata only. The actual font data is NOT copied from the ByteBuffer you pass to stbtt_InitFont. Only its memory address is copied and the font data is accessed via that pointer when necessary. The segfault you're seeing happens because you don't store a reference to the ByteBuffer anywhere, it is GCed/deallocated by the time you try to use the font. An easy fix would be to change your Font class to also store the ByteBuffer.
You can look at the post here.

Related

How to convert image to qr code using java?

If we search image to qr code, there are many websites which converts image to qr code online.
But how can I do this in java?
I am using the following code for converting text to qr code:-
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class MyQr {
public static void createQR(String data, String path,
String charset, Map hashMap,
int height, int width)
throws WriterException, IOException
{
BitMatrix matrix = new MultiFormatWriter().encode(
new String(data.getBytes(charset), charset),
BarcodeFormat.QR_CODE, width, height);
MatrixToImageWriter.writeToFile(
matrix,
path.substring(path.lastIndexOf('.') + 1),
new File(path));
}
public static void main(String[] args)
throws WriterException, IOException,
NotFoundException
{
String data = "TEXT IN QR CODE";
String path = "image.png";
String charset = "UTF-8";
Map<EncodeHintType, ErrorCorrectionLevel> hashMap
= new HashMap<EncodeHintType,
ErrorCorrectionLevel>();
hashMap.put(EncodeHintType.ERROR_CORRECTION,
ErrorCorrectionLevel.L);
createQR(data, path, charset, hashMap, 200, 200);
}
}
But how to encode a image in qr code?
Images are too big to be embedded into QR codes (with the exception of tiny icons). So instead, the image is put on a publicly accessible server and the URL of the image is embedded in the QR code.
Thus you need access to a server that can fulfill this. That's probably the bigger part of what you are about to implement.
Otherwise, it's straight-forward:
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class MyQr {
/**
* Uploads the image to a server and returns to image URL.
* #param imagePath path to the image
* #return image URL
*/
public static URL uploadImage(String imagePath)
{
// implement a solution to put an image on a public server
try {
return new URL("https://yourserver/some_path/image.jpg");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public static void createQR(String payloadImagePath, String qrCodeImagePath,
Map<EncodeHintType, ?> hints, int height, int width)
throws WriterException, IOException
{
URL imageURL = uploadImage(payloadImagePath);
BitMatrix matrix = new MultiFormatWriter().encode(
imageURL.toString(), BarcodeFormat.QR_CODE, width, height, hints);
String imageFormat = qrCodeImagePath.substring(qrCodeImagePath.lastIndexOf('.') + 1);
MatrixToImageWriter.writeToPath(matrix, imageFormat, Path.of(qrCodeImagePath));
}
public static void main(String[] args)
throws WriterException, IOException
{
String payloadImagePath = "embed_this.jpg";
String qrCodeImagePath = "qrcode.png";
Map<EncodeHintType, ErrorCorrectionLevel> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
createQR(payloadImagePath, qrCodeImagePath, hints, 200, 200);
}
}
BTW: The below code (from your code sample) is non-sense. At best, it creates a copy of the string, which is unnecessary. At worst, it corrupts all characters not supported by charset. I don't think you intended either one.
new String(data.getBytes(charset), charset)
I assume that you mean that you want to add an image (e.g. logo) to the QR Code.
This is generally done by overlaying a small image on top of the QR Code, usually in the center. QR Codes are still readable when a small portion is obscured, especially in the center.
You can use MatrixToImageWriter.toBufferedImage(matrix) to get a BufferedImage containing the QR Code image, and then use Java image methods to overlay the image. See, for example, overlay images in java

BufferUnderflowException while trying to read an Int from a binary file in Java

I am trying to read 4 bytes which represent an int, located at byte position 64 in a binary file.
This is what I have tried:
package testbinaryfile2;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class TestBinaryFile2 {
public static void main(String[] args) throws IOException {
FileChannel fc;
ByteBuffer indexField = ByteBuffer.allocate(4);
fc = (FileChannel.open(Paths.get("myBinaryFile.bin"), StandardOpenOption.READ));
fc.position(64);
fc.read(indexField);
System.out.println(indexField.getInt());
}
}
This is the error I get:
run:
Exception in thread "main" java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Buffer.java:509)
at java.nio.HeapByteBuffer.getInt(HeapByteBuffer.java:373)
at testbinaryfile2.TestBinaryFile2.main(TestBinaryFile2.java:30)
/home/user/.cache/netbeans/11.3/executor-snippets/run.xml:111: The following error occurred while executing this line:
/home/user/.cache/netbeans/11.3/executor-snippets/run.xml:94: Java returned: 1
BUILD FAILED (total time: 0 seconds)
After read indexField is pointing to its end, so it is necessary to use .rewind() method before getting the int.
This code works:
package testbinaryfile2;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class TestBinaryFile2 {
public static void main(String[] args) throws IOException {
FileChannel fc;
ByteBuffer indexField = ByteBuffer.allocate(4);
fc = (FileChannel.open(Paths.get("myBinaryFile.bin"), StandardOpenOption.READ));
fc.position(64);
fc.read(indexField);
indexField.rewind(); // <-- ADD THIS
System.out.println(indexField.getInt());
}
}
Additionally I got a suggestion to use mapped buffer:
public static void main(String[] args) throws Exception {
FileChannel fc = (FileChannel.open(Paths.get("myBinaryFile.bin"), StandardOpenOption.READ));
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
buffer.position(64);
System.out.println(buffer.getInt());
}
But I am wondering if fc.map reads the whole file at once and uses as much memory as the size of the file.

How do I use iText7 to OCR a multi page PDF?

I have used iText PdfRender, which converts a non-OCR PDF to an image, after which I used iText PdfOcr to convert that image to an OCR'd PDF. Is there a tool that lets me perform this process in one step?
It would also be helpful if there was some documentation on how I can process multi-page PDFs using PdfRender, which I can't seem to find. The following is the code I used to convert 1 image to an OCR PDF document.
import com.itextpdf.pdfocr.OcrPdfCreator;
import com.itextpdf.pdfocr.tesseract4.Tesseract4LibOcrEngine;
import com.itextpdf.pdfocr.tesseract4.Tesseract4OcrEngineProperties;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class img2pdfocr {
static final Tesseract4OcrEngineProperties tesseract4OcrEngineProperties = new Tesseract4OcrEngineProperties();
private static List LIST_IMAGES_OCR = Arrays.asList(new File("image1.jpg"));
private static String OUTPUT_PDF = "F:\\ITEXT_workspace\\jumpstart\\bizdoc.pdf";
public static void main(String[] args) throws IOException {
final Tesseract4LibOcrEngine tesseractReader = new Tesseract4LibOcrEngine(tesseract4OcrEngineProperties);
tesseract4OcrEngineProperties.setPathToTessData(new File("F:\\ITEXT_workspace\\jumpstart\\TESS_DATA_FOLDER"));
OcrPdfCreator ocrPdfCreator = new OcrPdfCreator(tesseractReader);
try (PdfWriter writer = new PdfWriter(OUTPUT_PDF)) {
ocrPdfCreator.createPdf(LIST_IMAGES_OCR, writer).close();
}
}
}
EDIT
As pointed out in the comments, I need not use pdfRender, iText core itself can be used to extract images from a PDF. Use this for the code. You can check on this documentation

From byte array to image java

I need to read a image in java ad convert to byte array for postgreSQL.
I have tried the following code, is it ok?
import java.nio.file.Files;
import java.nio.file.Path;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;
public class ConvertImage {
public static void main(String[] args) throws IOException {
Path filepath = Paths.get("image.jpg");
byte[] byteContent = Files.readAllBytes(filepath);
System.out.println(Arrays.toString(byteContent));
}
}
And how to do the way back, form byte array to image?
You can create a ByteArrayInputStream from the byte array and supply it to ImageIO as follows:
ByteArrayInputStream is = new ByteArrayInputStream( byteContent );
BufferedImage image = ImageIO.read( is );

Pyjnius custom java method returning 'JavaException: Unable to find a None Method' works after Public Static

So I needed to read a ByteArray from the InputStream in Android. Therefore I used this custom method in java in a kivy App using pyjnius for the same reason as stated in the link.
I placed the ReadInput.java file in this directory:
~/Build_Environ/.buildozer/android/platform/build/dists/JniusPrintBluetoothAppie/src/main/java/org/kivy/android
I initialised the java class with pyjnius:
Reading = autoclass('org.kivy.android.ReadInput')
The java code:
package org.kivy.android;
import java.io.InputStream;
import java.lang.Byte;
import java.lang.Integer;
import java.io.IOException;
public class ReadInput {
public byte[] inputread(InputStream stream, int count) throws IOException {
byte[] by = new byte[count];
stream.read(by);
return by;
}
}
I read from the buffer in python using the following code:
Reading.inputread(self.recv_stream, 4) #recv_stream is an Android BluetoothAdapter createInsecureRfcommSocketToServiceRecord getInputStream object
But for some reason this above code constantly gave me the following error:
JavaException: Unable to find a None Method
After many, many days of struggle I finally got the method to work by simply declaring the method as:
public static
The new java method looked as follows and I called it in the same way as above:
package org.kivy.android;
import java.io.InputStream;
import java.lang.Byte;
import java.lang.Integer;
import java.io.IOException;
public class ReadInput {
public static byte[] inputread(InputStream stream, int count) throws IOException {
byte[] by = new byte[count];
stream.read(by);
return by;
}
}
What I want to know is why would the word 'static' make the java method suddenly work?
The reason is that in Python code you access the method in a static way:
Reading.inputread(...)
This will work only if you define the method inputread in Java as static.
But it was not necessary. It could better to keep the method as non-static in Java and to use it in Python in a normal non-static way:
Reading = autoclass('org.kivy.android.ReadInput')
reading = Reading()
reading.inputread(...)

Categories

Resources