returning base64 string from Java - java

Very Basically I have an image I have converted into a Base64 string. The following code is how it is turned into a base64string and how im trying to return it. It is a modification of a phonegap plugin so please excuse the naming of certain things.
package org.apache.cordova;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.os.Environment;
import android.util.Base64;
import android.view.View;
public class Screenshot extends Plugin {
#Override
public PluginResult execute(String action, JSONArray args, String callbackId) {
// starting on ICS, some WebView methods
// can only be called on UI threads
final Plugin that = this;
final String id = callbackId;
super.cordova.getActivity().runOnUiThread(new Runnable() {
//#Override
#TargetApi(8)
public void run() {
View view = webView.getRootView();
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
File folder = new File(Environment.getExternalStorageDirectory(), "Pictures");
if (!folder.exists()) {
folder.mkdirs();
}
File f = new File(folder, "screenshot_" + System.currentTimeMillis() + ".png");
System.out.println(folder);
System.out.println("screenshot_" + System.currentTimeMillis() + ".png");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
String base64String = Base64.encodeToString(b, Base64.DEFAULT);
String mytextstring = "data:image/png;base64,"+base64String;
System.out.println(mytextstring);
that.success(new PluginResult(PluginResult.Status.OK), mytextstring);
}
});
PluginResult imageData = new PluginResult(PluginResult.Status.NO_RESULT);
imageData.setKeepCallback(true);
System.out.println("imageData:==================================================================================>>>>>"+imageData);
return imageData;
}
}
This line:
System.out.println(mytextstring);
outputs the base64 string, however this line:
System.out.println("imageData:==================================================================================>>>>>"+imageData);
doesn't. I'm trying to get imageData to contain the base64string to I can return that and use it in some Javascript. i have played about with the code for a while now with no success, I am new to Java so really don't know how close I am. Can anyone guide me please?
EDIT Simply all I want to do is return the Base64String, nothing else.

Your code that calls this.success is incorrect. It should be:
that.success(new PluginResult(PluginResult.Status.OK, mytextstring), id);
The way you have it:
that.success(new PluginResult(PluginResult.Status.OK), mytextstring);
Tells the callback server to call the success callback at "mytextstring". Obviously there is no callback stored at "mytextstring" as that is your result.
In addition the default .js file for the screen shot plugin does not provide a way for you to call it with success/failure callbacks. So you will need to modify the .js code in order to get a success callback invoked with your base64 data. Add something like this to Screenshot.js:
Screenshot.prototype.getBase64Screenshot = function(successCallback, errorCallback) {
exec(successCallback, errorCallback, "Screenshot", "saveScreenshot", []);
};
Then you can call it by doing this:
window.plugins.screenshot.getBase64Screenshot(function(data) {
console.log("Data = " + data);
}, function() {
console.log("We got an error");
});
Obviously you'd provide your own success and failure callbacks.

I think its a mistake in your code. I'll try to provide a couple of ways from the point of view of pure java
When you create your 'PluginResult' object you don't connect it in any manner to the string you've created (base64string variable).
If you want to return the base64-encoded string you should do something like:
PluginResult imageData = new PluginResult(..., ..., base64string, ..., ...)
or if you don't have a constructor try to use setter like this (for example):
PlugingResult imageData = new PlugingResult(...)
imageData.setEncodedString(imageData)
Without an exposed API its hard to understand how to use object of type PluginResult properly (I've never used it by myself)
If you see that nothing suits your needs but you absolutely have to use the PluginResult object, than you may consider to create a class that contains both PluginResult and your encoded String and use it as a return type of your method. Like this:
class MyPluginResult {
private PluginResult pluginResult;
private String encodedString;
/*
....
getters/setters/constructors go here
*/
}
Than make your method returning MyPluginResult, change the code that creates a PluginResult and returns it and you'll be fine.
Hope this helps

I dont know much about Cordova and PhoneGap, but looking through the API you have the constructor public PluginResult(Status status, String message). I guess you can pass the base64String to the second parameter of that constructor. The message is converted to a JSON string format, but you can handle that format in java / javascript easily.
Hope this helps.
Regards

Related

How to fix "Error: Invalid GCS Path Specified" when using Java with Google's Vision API?

I am currently following this example on the Vision API docs:found here
import com.google.cloud.vision.v1.*;
import com.google.cloud.vision.v1.Feature.Type;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class VisionApiTest {
public static void main(String... args) throws Exception {
PrintStream stream = new PrintStream(new File("src/test.txt"));
detectTextGcs("https://www.w3.org/TR/SVGTiny12/examples/textArea01.png", stream);
}
public static void detectTextGcs(String gcsPath, PrintStream out) throws Exception, IOException {
List<AnnotateImageRequest> requests = new ArrayList<>();
ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build();
Image img = Image.newBuilder().setSource(imgSource).build();
Feature feat = Feature.newBuilder().setType(Type.TEXT_DETECTION).build();
AnnotateImageRequest request =
AnnotateImageRequest.newBuilder().addFeatures(feat).setImage(img).build();
requests.add(request);
try (ImageAnnotatorClient client = ImageAnnotatorClient.create()) {
BatchAnnotateImagesResponse response = client.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = response.getResponsesList();
for (AnnotateImageResponse res : responses) {
if (res.hasError()) {
out.printf("Error: %s\n", res.getError().getMessage());
return;
}
// For full list of available annotations, see http://g.co/cloud/vision/docs
for (EntityAnnotation annotation : res.getTextAnnotationsList()) {
out.printf("Text: %s\n", annotation.getDescription());
out.printf("Position : %s\n", annotation.getBoundingPoly());
}
}
}
}
}
After passing in the gcsPath String into the detectTextGcs method in the example, I am given the error: "Error: Invalid GCS path specified: https://www.w3.org/TR/SVGTiny12/examples/textArea01.png"
I am expecting for the PrintStream object to write to the file the text that is held within the picture which will be "Tomorrow, and\ntomorrow, and\ntomorrow; blah blah blah...". After trying the API on Vision API doc page mentioned above, it works fine, but not within IntelliJ.
Any help is greatly appreciated. Thank you. (Also forgive me if this isn't a well worded question, it's my first time posting)
I actually figured out the problem. The problem lies within the in line 3 of the detectGcsText() method.
ImageSource imgSource = imageSource.newBuilder().setGcsImageUri(gcsPath).build();
If you would like to use a regular HTTP URI, you must use setImageUri(path) instead of setGcsImageUri(gcsPath).
Thank you for everyone's help!
Google Cloud Storage (GCS) is a storage system where you can persistently save data as blob storage. In GCS, we have the concept of buckets which are "named" containers of data and objects which are named instances of data. To specify a Blob, we Google has invented the notion of a GCS URL of the form:
gs://[BUCKET_NAME]/[OBJECT_NAME]
In your story, you have specified an HTTP URL where a GCS Url was expected. You must not specify an HTTP URL where a GCS URL is required.

Java, seemingly randomly, started crashing on FileHandle.class.getResourceAsStream(path);

So, I'm working on a program that allows you to import animations in the form of JSON files into Minecraft, and, when working on a completely different part of the program, my import code stopped working.
I'm using eclipse, and this is how my import code looks:
package com.github.sam54123.mc_animation.utils;
import java.io.InputStream;
public class FileHandle
{
public static InputStream inputStreamFromFile(String path)
{
try
{
InputStream inputStream = FileHandle.class.getResourceAsStream(path);
return inputStream;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
new file
package com.github.sam54123.mc_animation.utils;
import java.io.File;
import java.io.InputStream;
import java.util.Scanner;
import org.json.JSONObject;
public class JSONUtils
{
public static String getJSONStringFromFile(String path)
{
// Open file
Scanner scanner;
try
{
InputStream in = FileHandle.inputStreamFromFile(path);
scanner = new Scanner(in);
// Get JSON as string without spaces or newlines
String json = scanner.useDelimiter("\\Z").next();
// Close file
scanner.close();
return json;
}
catch(Exception e)
{
System.out.println(e.getStackTrace());
return null;
}
}
public static JSONObject getJSONObjectFromFile(String path)
{
File file = new File(path);
if (!file.exists())
{
System.out.println("Invalid Path");
return null;
}
String string = getJSONStringFromFile(path);
return new JSONObject(string);
}
}
And I proceed to do some more fancy pampering of the file later on. This used to work reliably, until I made this in a completely different and un-related class:
String command = getCommand(object);
if (command != null && command.length() > 0)
{
commands.add(new AnimCommand(command, i));
}
And then it started throwing this error:
[Ljava.lang.StackTraceElement;#7852e922
Exception in thread "main" java.lang.NullPointerException
at java.io.StringReader.<init>(Unknown Source)
at org.json.JSONTokener.<init>(JSONTokener.java:94)
at org.json.JSONObject.<init>(JSONObject.java:406)
at com.github.sam54123.mc_animation.utils.JSONUtils.getJSONObjectFromFile(JSONUtils.java:47)
at com.github.sam54123.mc_animation.system.Animation.<init>(Animation.java:20)
at com.github.sam54123.mc_animation.testing.Tester.main(Tester.java:13)
I've double checked that the file hasn't changed, and I tried deleting that section of code, restarting Eclipse, the whole deal, and nothing seems to fix it. The code is even able to recognize that the file is valid using the File class, but nothing seems to change. Does anyone have some insight on how this might be fixed? Here is the rest of my code: https://github.com/Sam54123/mc-animation/
EDIT
Okay, I've just done some more debugging, and it looks like it's the
return new JSONObject(string);
on line 47 of the second file that's crashing. No idea why, as the risky stuff of reading a file off disk is okay.
EDIT 2
It looks looks like it's failing because
InputStream in = FileHandle.inputStreamFromFile(path);
is returning null, which makes sense because of the try catch statement
InputStream inputStream = FileHandle.class.getResourceAsStream(path);
is in. Why that's failing beats me though, because the validity of the file is verified elsewhere in the code. It also used to work, and I haven't changed anything about the layout of the files.
EDIT 3
Interesting, a couple System.out.printlns reveal the catch is not actually getting activated, and therefore getResourceAsStream() must actually be returning null. I've confirmed this by printing it out before I return it.

How can I send a PNG of a QR-code in a HTTP response body (with Spark)?

I want to generate a QR-code image, convert it to PNG and return it as a HTTP response to my client.
To generate the QR-code I use ZXing. I already tested the conversion part by writing using a FileOutputStream with MatrixToImageWriter.writeToStream(...). That works like a charm.
The web framework I am currently using is Spark (Version 1.1.1). The return of the handle(...)-method is set as the response body. What am I doing wrong here?
With the current solution I get The image "http://localhost:4567/qrcode" cannot be displayed because it contains errors when performing the GET-request with Firefox.
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import static spark.Spark.get;
import spark.Request;
import spark.Response;
import spark.Route;
import com.google.gson.Gson;
import com.google.common.io.BaseEncoding;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
public class App {
public static void main(String[] args) {
get(new Route("/qrcode") {
#Override
public Object handle(Request request, Response response) {
// Test data
QrData data = new QrData("test");
// Data is wrapped in JSON
String json = new Gson().toJson(data);
// Transform JSON to QR-code PNG byte string
String qrString = "";
try {
qrString = generatePngQrCode(json);
} catch (Exception e) {
e.printStackTrace();
}
// Set response parameters
response.type("image/png");
response.status(200);
// Return response body
return qrString;
}
});
}
public String generatePngQrCode(String content) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// ZXing QR-code encoding
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, 400, 400);
// Convert to PNG image and write to stream
MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream);
// Encode to Base 64
return BaseEncoding.base64().encode(outputStream.toByteArray());
}
}
Just went through this. You can write any file/binary data/output stream using the following code:
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
HttpServletResponse raw = res.raw();
raw.getOutputStream().write(bytes);
raw.getOutputStream().flush();
raw.getOutputStream().close();
return res.raw();
Use response.getRaw to obtain an OutputStream that should be used to write the PNG to (using MatrixToImageWriter).

How to handle a webrequest POST server side

I'm new to webserver work. I am trying to make a webrequest POST from a C# client to my Java webservice. I believe the POST is being done successfully but I do not know how to tell the server to retrieve and use the POST data.
This is my code in Java right now:
//import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.iharder.encoders.Base64;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
#Service("FCBarcodeRecognitionService")
public class DecodeBarcodeFromImageActivity extends Activity {
private static final Log LOG = LogFactory
.getLog(DecodeBarcodeFromImageActivity.class);
#Operation("DecodeBarcodeFromImage")
#Documentation("Attempt to decode a barcode from POST image data.\n Returns a String of the decoded barcode and the type\n of barcode detected if successful.")
public DecodeFromImageOutput enact(DecodeFromImageInput input)
throws DependencyException {
DecodeFromImageOutput output = new DecodeFromImageOutput();
LOG.debug("Received DecodeFromBarcodeImage request...");
// Decode the images from the String arguments. They could
// potentially be in any encoding format. (e.g. Base64)
//How do I retrieve the POST data to use inside this operation??
//I have something like this now
ImageEncoder imageEncoder = new ImageEncoder();
//the current input is just something I'm manually giving it. I want it to be the encoded image from the POST data
List<BufferedImage> bufferedImgs = imageEncoder.decodeImageData(input);
LOG.debug("Received " + bufferedImgs.size() + " images from decoder.");
// Attempt to read a barcode (this will just pass the POST data, once I get it to my decode method)
try {
DecodedBarcode barcode = recognizeBarcodeFromImages(input, bufferedImgs);
output.setDecodedBarcode(barcode);
This is my code in C# right now:
//I am trying to POST an encoded (base64) image
WebRequest serverReq = WebRequest.Create("http://saxtonl.desktop.amazon.com:8000/explorer");
serverReq.Method = "POST";
serverReq.ContentType = "application/x-www-form-urlencoded";
serverReq.ContentLength = base64String.Length;
Stream dataStream = serverReq.GetRequestStream();
dataStream.Write(imageBytes, 0, imageBytes.Length);
dataStream.Close();
WebResponse serverRsp = serverReq.GetResponse();
Console.WriteLine(((HttpWebResponse)serverRsp).StatusDescription);
dataStream = serverRsp.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
reader.Close();
dataStream.Close();
serverRsp.Close();

ImageIO.read sometimes retun null even though I am 100% sure the Image is 100% valid

I know the image is valid because I can convert the IplImage to an Image and even draw it on a JPanel. But when I convert a byte array to an Image most of the time I get null reference to an Image. Look at this code below to get a picture what I am facing with and comments, questions, answers are all welcome and even tips are all welcome.
Image i = Convert.getImage(image);
byte[] buffer = Convert.getBytes(image);
Image i2 = Convert.getImage(buffer);
//i2 is a null reference and i is a valid image. i can be drawn but i2 is useless.
Convert class:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package Security;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
/**
*
* #author danny
*/
public final class Convert
{
public static Image getImage(IplImage image)
{
return image.getBufferedImage();
}
public static byte[] getBytes(IplImage image)
{
byte[] buffer;
BufferedImage bI = image.getBufferedImage();
buffer = ((DataBufferByte) (bI).getRaster().getDataBuffer()).getData();
return buffer;
}
public static String getString(byte[] buffer)
{
return new String(buffer);
}
public static Image getImage(byte[] buffer)
{
try
{
Image i = ImageIO.read(new ByteArrayInputStream(buffer));
return i;
}
catch (Exception e)
{
System.out.printf("Exception Message:\n%s", e.getMessage() );
return null;
}
}
}
Now some of you may ask why do I need as a byte array. Well because I need to send across a network.
Extra Things To Be Aware Of:
No exception is being thrown
IplImage is a valid object
Update:
I have tried using the ToolKit class to create an image from a byte array. But it fails probably because it is not a JPEG or GIF. Although it does return a valid Image object the Image object is pointing to an image that is blank. Here is the code I was trying to use but failed to do so.
public static Image getImage(byte[] buffer)
{
try
{
Toolkit toolkit = Toolkit.getDefaultToolkit();
Image i = toolkit.createImage(buffer);
return i;
}
catch (Exception e)
{
System.out.printf("Exception Message:\n%s", e.getMessage() );
return null;
}
}
DataBufferByte.getData will: "Returns the default (first) byte data array." The first bank that is. That seems an uncertain, incomplete way to get the bytes; especially on the way back. Besides there is the implementation dependent cast from DataBuffer to DataBufferByte.
ImageIO can write to an OutputStream, for instance to a ByteArrayOutputStream, of which you can take the bytes. And on the other side ImageIO can read it in again. That is not the pure only-pixel-data you had in mind, but fool-proof.

Categories

Resources