I have a question about using Javonet. In the .NET code I have a method that returns a
System.DrawingImage and I have to obtain it on my Java side of code. So
when I issue a "get" of the attribute by Javonet API, it returns an
NObject. Here is the example:
.NET code:
...
namespace ImageTest
{
public class FileReader
{
public byte[] GetByteArray(string filename)
{
return System.IO.File.ReadAllBytes(filename);
}
public System.Drawing.Image GetImage(string filename)
{
byte[] b = GetByteArray(filename);
using (var ms = new System.IO.MemoryStream(b, false))
{
return Image.FromStream(ms);
}
}
}
}
Java code
...
public Image getImage(String fileName) {
NObject res = null;
try {
res = item.get(propName); // Casting NObject to Image is not allowed!
} catch (JavonetException jex) {
jex.printStackTrace();
}
return res; // Wrong: an Image object must be returned!
}
I have to cast 'res' to Image or ImageIcon or something similar in
Java. Any suggestion? Have I to get it as byte array or something else
or there is another mechanism on Javonet?
Any complex object (like class) will always be returned in form of "NObject" so in fact it is the handle to that object on .NET side. If you want to move the concrete image from .NET to Java you need to do it using the value-types so in form of byte[] or string base64 as there is no direct counterpart of "System.Drawing.Image" class in Java.
Therefore you just need to extract the value-type form of your image from System.Drawing.Image class.
You can do it like this:
NObject ms = Javonet.New("MemoryStream");
yourImageNObject.Save(ms,Javonet.getType("System.Drawing.Imaging.ImageFormat").getRef("Jpeg"));
Byte[] imageBytes = ms.invoke("ToArray");
//you can also unbox the bytes to regular byte[]
byte[] unboxed = new byte[fileBytes.length];
for(int i=0; i<imageBytes.length;i++)
unboxed[i]=imageBytes[i].byteValue();
Related
I am rewriting java code in python. The code works with different files through Spring. It opens such formats as JSON, DBF, RAR, XML and converts the data into String.
There is always a line in every code:
byte[] decodeFile = Base64.getMimeDecoder().decode(fileBase64); #(1)
Or in the block:
public interface FileService {
String convert(String file, String fileName);
#Service
class FileServiceImpl implements FileService {
#Override
public String convert(String fileBase64, String fileName) {
byte[] decodeFile = Base64.getMimeDecoder().decode(fileBase64);
try {
FileOutputStream out = new FileOutputStream(new File(fileName));
out.write(decodeFile);
out.close();
return convertToJson(new File(fileName));
} catch (IOException e) {
return null;
}
}
Basically I do not understand the purpose of line (1).
So, the question is: should I do something like that in Python? If it is necessary, then: how can I do it in Python?
Thank you for any possible advice.
As per the following line
byte[] decodeFile = Base64.getMimeDecoder().decode(fileBase64); #(1)
The MIME encode/decoder generates Base64 encoded output/decoded values in MIME format.
You can use the quopri python module for similar things.
You can refer below the link.
https://docs.python.org/3/library/quopri.html
You have to use the code like this
encodedValue = quopri.decodestring(<your encoded>, True)
There seems to be a problem with serializing BufferedImages in JSON using GSON. I am using Derby to store images. When I query the the database I build a JavaBean that has some text fields and one BufferedImage field. I then use GSON to convert the JavaBean into JSON, and this is where the exception occurs.
The Exception message is below:
java.lang.IllegalArgumentException: class sun.awt.image.ByteInterleavedRaster declares multiple JSON fields named maxX
I did find similar problems here GSON java.lang.IllegalArgumentException: class 'xx' declares multiple JSON fields named 'XX' AND StackOverflowError and here class A declares multiple JSON fields
But the problem is with the awt library included with Java. I could follow the answers provided in those other stackoverflow answers if I could access the AWT source code, but how do I do that?
You have to know that not every class is designed to be (de)serialized, especially if (de)serialization is based on the target class binary structure. Your approach has at least the following weak points:
the sun.awt.image.ByteInterleavedRaster class fields are not necessarily the same on another JVM/JRE, thus you can get be vendor-locked;
persisting binary data in JSON is probably not the best choice (probably huge and terrible memory consumption during (de)serialization, storage consumption, performance) -- maybe a generic blob storage is better for binary data?
reading an images with Java AWT and writing it back does not guarantee the same binary output: for example, my test image, 1.2K, was deserialized as an image of another size, 0.9K;
you must choose the target persisting image format or detect the most efficient one (how?).
Consider the following simple class:
final class ImageHolder {
final RenderedImage image;
ImageHolder(final RenderedImage image) {
this.image = image;
}
}
Now you have to create a type adapter to tell Gson how a particular type instance can be stored and restored:
final class RenderedImageTypeAdapter
extends TypeAdapter<RenderedImage> {
private static final TypeAdapter<RenderedImage> renderedImageTypeAdapter = new RenderedImageTypeAdapter().nullSafe();
private RenderedImageTypeAdapter() {
}
static TypeAdapter<RenderedImage> getRenderedImageTypeAdapter() {
return renderedImageTypeAdapter;
}
#Override
#SuppressWarnings("resource")
public void write(final JsonWriter out, final RenderedImage image)
throws IOException {
// Intermediate buffer
final ByteArrayOutputStream output = new ByteArrayOutputStream();
// By the way, how to pick up the target image format? BMP takes more space, PNG takes more time, JPEG is lossy...
ImageIO.write(image, "PNG", output);
// Not sure about this, but converting to base64 is more JSON-friendly
final Base64.Encoder encoder = Base64.getEncoder();
// toByteArray() returns a copy, not the original array (x2 more memory)
// + creating a string requires more memory to create the String internal buffer (x3 more memory)
final String imageBase64 = encoder.encodeToString(output.toByteArray());
out.value(imageBase64);
}
#Override
public RenderedImage read(final JsonReader in)
throws IOException {
// The same in reverse order
final String imageBase64 = in.nextString();
final Base64.Decoder decoder = Base64.getDecoder();
final byte[] input = decoder.decode(imageBase64);
return ImageIO.read(new ByteArrayInputStream(input));
}
}
Note that Gson is currently NOT very well designed to support byte transformation, however it might be somewhat better in the future if fixed.
Example use:
private static final Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(RenderedImage.class, getRenderedImageTypeAdapter())
.create();
public static void main(final String... args)
throws IOException {
try ( final InputStream inputStream = getPackageResourceInputStream(Q43301580.class, "sample.png") ) {
final RenderedImage image = ImageIO.read(inputStream);
final ImageHolder before = new ImageHolder(image);
final String json = gson.toJson(before);
System.out.println(json);
final ImageHolder after = gson.fromJson(json, ImageHolder.class);
...
}
}
Example output (with real tiny (32x32) PNG file inside):
{"image":"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADgklEQVR42t2XXUiTYRTHpxj4kSKShhgYGSihZGIXXYhU5J2BhBIhCH5cCF6oiWhG0k1BpHghgRgoJHiloBKEqFQ3frDNuemaOqdu0+n8mFM3Nzf37z1n+JZUEPlOoQdetvd5L87vOed/Ph4ZznnJzsqQz+uFz+M5HwBrezuUFy9CERoKY3U1jtzuwAFY29pgGxgQ350aDVSXLmFfLud9eVAQTHV1gQNYKi+HMiwM9uFhft/o6MBcTg6fWp+XB93duzhyOOA7POSwyAIR64UnTxhi9+tXfhQhIdBlZ2P2wQM2Tmv11StY3rwJjAYIQl9QAGVUFPZGRzF7/z7kwcGw9ffzt80PHzAZE4ODuTnpAQ50OjgmJ3HkcmE+N5chdr98wfzDh5DLZPyo4uOx+/mz9Bqg+B8b0d6+zSecFeJPInSo1XAbjXAKvxR/yUW4Pz7uV/vEBJ9OffUqNNev49BiYeGp4uLg0usDUwdIUNNpaTDV1op7rqUljvNKYyMLb7G4GIdWa2AAbH19LDIy8vNaefmSBRiQUkynMtXUYLGkBO7lZWx2dTEEnVjURFnZL1CSASyWlmL6xg1okpIwdeUK3CYTNjo7WYCGoiLOeU1yMtxmc2AA1NeuscA829uYTk1lEIJYf/eOIcgzP6tdEgAyRicjtatiY8V9EhdDpKTw/7XmZoYgGEkBzEITIQDzs2dsYPX1a/EbuZq8YG5o8GeG8E2dmIgjp/P0AJxGgku1GRnYVyh479jVdFrRE+vrXGqPl3dvTxoPeO12aDMz2aBDqRT315qa/trV/wTgsdmw1d3NJVSMs+BmOqlYhARXL1dUSA/gWljg9FKGh/u72tgYQ1BqEcjvqtqpAHY+fcLOx4/+durzcTOxvH3LXY1qOUFQ/CnVyAszN2+eGK1OBWCur4cyIgIrL174Xb+1hdl79xiERioqOFRSKf3sQ0MclvXWVmk8sN3b6+9UBsMvQwWtb3fuwD4ywpkwlZDAojNWVUk3lhsrK7Hw+PHJ+AudzKnVwrOzwwYP5ud50JhJT5cs9iLAxvv3UFy4wLVdn58P1eXLP4YKIfWor09GR0MZGYm1lhbpLyYUZ/Pz55i5dQu6rCwYnz4FhYXmNjJKKbYmiHG7p+fsb0aGwkIsC2PWuVzNaJ5j1Q8Oni0AVTkKCbmffs/8cuoVlK9/9IjHrP/qdvyn9R0SEM4flWsmCwAAAABJRU5ErkJggg\u003d\u003d"}
I think there are too many flaws, and I would strongly recommend you to redesign your binaries storage if possible and store binary content as-is.
I have a server-side java code that gets a byte array from the client. In order to do some image processing, I need to convert the byte array into a BufferedImage. I have a code that's supposed to do that here:
public void processImage(byte[] data) {
ByteArrayInputStream stream = new ByteArrayInputStream(data);
BufferedImage bufferedImage;
bufferedImage = ImageIO.read(stream);
// bufferedImage is null
//...
}
But this doesn't work; bufferedImage is null. According to the ImageIO documentation:
If no registered ImageReader claims to be able to read the resulting stream, null is returned.
How do I tell the ImageReader what image type it is. For instance, if I know the image to be JPEG (which it is, in my case), what am I supposed to do?
EDIT: Thanks for the suggestion that the file is most likely not in JPEG format. This is the client-side code I have that sends the data as String over to the server:
import org.json.JSONObject;
// Client-side code that sends image to server as String
public void sendImage() {
FileInputStream inputStream = new FileInputStream(new File("myImage.jpg"));
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while ((bytesRead = inputStream.read(b)) != -1) {
byteStream.write(b,0,bytesRead);
}
byte[] byteArray = byteStream.toByteArray();
JSONObject jsonObject = new JSONObject();
jsonObject.put("data",new String(byteArray));
// ... more code here that sends jsonObject in HTTP post body
}
And this is the server-side code that calls the processImage() function:
// Server-side code that calls processImage() function
public void handleRequest(String jsonData) {
JSONObject jsonObject = new JSONObject(jsonData);
processImage(jsonObject.getString("data").getBytes());
}
The most likely explanation is that the byte array doesn't contain a JPEG image. (For instance, if you've just attempted to download it, you may have an HTML document giving an error diagnostic.) If that's the case, you'll need to find what is causing this and fix it.
However, if you "know" that the byte array contains an image with a given format, you could do something like this:
Use ImageIO.getImageReadersByFormatName or ImageIO.getImageReadersByMIMEType to get an Iterator<ImageReader>.
Pull the first ImageReader from the Iterator.
Create an MemoryCacheImageInputStream wrapping a ByteArrayInputStream for the types.
Use ImageReader.setInput to connect the reader to the ImageInputStream.
Use ImageReader.read to get the BufferedImage.
This is an example XML file that would come from the Android Client.
<test>
<to>Mee</to>
<from>Youuu</from>
<img src="http://www.domain.com/path/to/my/image.jpg" />
</test>
I have written a XML parser about this. My problem is while passing it to the Android Client, I need to have the image binary data instead of the image path. How can I accomplish this and how can I update the above said XML with the binary data.
You could use Base64 to encode your image binary data (represented by a byte[]) and include it in the xml as CDATA.
Then on the Android machine, you just decode it to a byte array, and render the image.
You can use Apache Commons to encode/decode.
Edit:
You need to get a byte representation of the image data in order to convert it. See my example. This is using sun.misc.BASE64Decoder and sun.misc.BASE64Encoder, you may need to adapt depending on what you have at your disposal on Android (see Apache Commons).
public class SO11096275 {
public static byte[] readImage(URL url) throws IOException {
final ByteArrayOutputStream bais = new ByteArrayOutputStream();
final InputStream is = url.openStream();
try {
int n;
byte[] b = new byte[4096];
while ((n = is.read(b)) > 0) {
bais.write(b, 0, n);
}
return bais.toByteArray();
} finally {
if (is != null) {
is.close();
}
}
}
public static void main(String[] args) throws Exception {
URL url = new URL("http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png");
byte[] imgData = readImage(url);
String imgBase64 = new BASE64Encoder().encode(imgData);
System.out.println(imgBase64);
byte[] decodedData = new BASE64Decoder().decodeBuffer(imgBase64);
FileUtils.writeByteArrayToFile(new File("/path/to/wikipedia-logo.png"), decodedData); // apache commons
}
}
Then you have your image data as a string in imgBase64, you just have to append a node to your xml using the DOM implementation you want, for example dom4j. There are methods to add CDATA to the XML. Finally, on your Android, you just need to retrieve the node content and you're good to decode it like above and do what you want with the image.
XML-alternatives like JSON, Protocol Buffer could help you.
I'm trying to get an audio data from a AS library, from the documentation the function is like this:
protected function audioData():String
{
var ret:String="";
buffer.position = 0;
while (buffer.bytesAvailable > 0)
{
ret += buffer.readFloat().toString() + ";";
}
return ret;
}
In between my code and this library is another js that have this code:
audioData: function(){
return this.flashInterface().audioData().split(";");
},
From my code I access this like:
function getdata(){
var data = Recorder.audioData();
console.log("audioData: " + data);
}
However, I tried to output the returned value to Firebug, I get a very long comma-separated list of of floating point values, how can I get back the byte[] buffer? What I mean by buffer is similar to Java, since I will be accessing the buffer from Java via JSNI.
Here's the sample log output (actual log is very long):
-0.00030517578125,0.00006103515625,0.00115966796875,0.00146484375,-0.00091552734375,-0.000946044921875,-0.001983642578125,-0.003997802734375,-0.005126953125,-0.00360107421875,-0.0032958984375,-0.004119873046875,-0.00433349609375,-0.0023193359375,-0.0008544921875,-0.003448486328125,-0.00347900390625,-0.0054931640625,-0.0067138671875,-0.005279541015625,-0.006072998046875,
I can't re-compile the AS that creates the output, for now what I can do is to interface to the SWF component in javascript and accept its floating point and convert it back to byte array. There's just too many errors in my AS project in FDT 5 IDE that I already need to do the mockup of my application.
I really want to recompile the AS library to fit the need however right now I just want to use it as it is.
If you want to see the actual byte data in the byte array you can use the following :
protected function audioData():String
{
var ret:String="";
buffer.position = 0;
while (buffer.bytesAvailable > 0)
{
ret += buffer.readByte().toString();
}
return ret;
}
AFAIK the ByteArray class in as3 is already a byte array(as the name suggests :)) you can access it's data using the [] operator, as in byteArray[0] will give you the first byte.
You should be able to send the byte array to a url on your server with a post request with something like this:
var request:URLRequest = new URLRequest ("http://someurl");
var loader: URLLoader = new URLLoader();
request.contentType = "application/octet-stream";
request.method = URLRequestMethod.POST;
request.data = byteArray;
loader.load(_request);