I need to transport several files inside the source code. Horrible, I know, but I don't have any other option. So far I'm only storing images, so I do this:
Encoding the image:
Bitmap bm = BitmapFactory.decodeFile(imagePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
String encodedimage = Base64.encodeToString(b, Base64.DEFAULT);
Decoding the image:
public static Bitmap decodeBitmap(imageString) {
return BitmapFactory.decodeStream(new ByteArrayInputStream(Base64.decode(imageString, Base64.DEFAULT)));
}
I use base64 so that putting a new image in the program is easier because it's just a simple string.
Now I'm trying to expand the functionality to any file format so I seek guidance as to find out if there is less bad way of storing files inside code.
for images you should be using the resources folder. It's built into the system for that.
For general final you should use the asset folder and access just like shown on this stackoverflow question: How to get URI from an asset File?
If you want to keep some data files, you can keep them in Assets folders and you can use AssetManager to get the files.
Related
I got a strange issue with a GIF image in Java. The image is provided by an XML API as Base64 encoded string. To decode the Base64, I use the commons-codec library in version 1.13.
When I just decode the Base64 string and write the bytes out to a file, the image shows properly in browsers and MS Paint (nothing else to test here).
final String base64Gif = "[Base64 as provided by API]";
final byte[] sigImg = Base64.decodeBase64(base64Gif);
File sigGif = new File("C:/Temp/pod_1Z12345E5991872040.org.gif");
try (FileOutputStream fos = new FileOutputStream()) {
fos.write(sigImg);
fos.flush();
}
The resulting file opened in MS Paint:
But when I now start consuming this file using Java (for example creating a PDF document from HTML using the openhtmltopdf library), it is corrupted and does not show properly.
final String htmlLetterStr = "[HTML as provided by API]";
final Document doc = Jsoup.parse(htmlLetterStr);
try (FileOutputStream fos = new FileOutputStream(new File("C:/Temp/letter_1Z12345E5991872040.pdf"))) {
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.useFastMode();
builder.withW3cDocument(new W3CDom().fromJsoup(doc), "file:///C:/Temp/");
builder.toStream(fos);
builder.useDefaultPageSize(210, 297, BaseRendererBuilder.PageSizeUnits.MM);
builder.run();
fos.flush();
}
When I now open the resulting PDF, the image created above looks like this. It seems that only the first pixel lines are printed, some layer is missing, or something like that.
The same happens, if I read the image again with ImageIO and try to convert it into PNG. The resulting PNG looks exactly the same as the image printed in the PDF document.
How can I get the image to display properly in the PDF document?
Edit:
Link to original GIF Base64 as provided by API: https://pastebin.com/sYJv6j0h
As #haraldK pointed out in the comments, the GIF file provided via the XML API does not conform to the GIF standard and thus cannot be parsed by Java's ImageIO API.
Since there does not seem to exist a pure Java tool to repair the file, the workaround I came up with now is to use ImageMagick via Java's Process API. Calling the convert command with the -coalesce option will parse the broken GIF and create a new one that does conform to the GIF standard.
// Decode broken GIF image and write to disk
final String base64Gif = "[Base64 as provided by API]";
final byte[] sigImg = Base64.decodeBase64(base64Gif);
Path gifPath = Paths.get("C:/Temp/pod_1Z12345E5991872040.tmp.gif");
if (!Files.exists(gifPath)) {
Files.createFile(gifPath);
}
Files.write(gifPath, sigImg, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
// Use the Java Process API to call ImageMagick (on Linux you would use the 'convert' binary)
ProcessBuilder procBuild = new ProcessBuilder();
procBuild.command("C:\\Program Files\\ImageMagick-7.0.9-Q16\\magick.exe", "C:\\Temp\\pod_1Z12345E5991872040.tmp.gif", "-coalesce", "C:\\Temp\\pod_1Z12345E5991872040.gif");
Process proc = procBuild.start();
// Wait for ImageMagick to complete its work
proc.waitFor();
The newly created file can be read by Java's ImageIO API and be used as expected.
I need to be able to modify the contents of a jpeg or png files and am able to successfully break the image down into bytes and vice versa. The only problem is that i do not know how many bytes make up a jpeg file header or a png file header. The information on most websites is pretty vague and/or way too informative for a beginner like me.
Id really appreciate if someone can provide a simple answer telling me how many bytes i need to skip to get past the header and how to identify if the image is a jpeg image or a png image as well as any other important information that i may not have mentioned.
Ive added the code below which im using to extract the bytes from an image and to convert the image into bytes.
Note: This code works on android OS
Code used to convert image to bytes:
public byte[] imgtobytes(File f)
{
FileInputStream fis=null;
try
{
fis = new FileInputStream(f);
}
catch(Exception e) {}
Bitmap bm = BitmapFactory.decodeStream(fis);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100 , baos);
byte[] b = baos.toByteArray();
return b;
}
Code used to convert bytes to image and display it on an imageview:
public void bytestoimg(byte[] bytearray, ImageView imgv)
{
Bitmap bmp = BitmapFactory.decodeByteArray(bytearray, 0, bytearray.length);
imgv.setImageBitmap(Bitmap.createScaledBitmap(bmp, imgv.getWidth(),
imgv.getHeight(), false));
}
I've done some similar work in python a while ago playing with encryption. I believe that what you are looking for can be found in this wikipedia article under "Examples" section.
Also you can check out this answer
When I convert a picture into bytes and back, the quality deteriorates a lot. How to do it without reducing quality?
I need to save the photo in the database or send it to the server. I can consider other options to do this.
public static byte[] fromBitmap(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
return stream.toByteArray();
}
public static Bitmap toBitmap(byte[] bytes) {
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
How to do it without reducing quality?
Use a lossless image format, such as PNG.
It's not a good way to save the picture in the database directly. The best way is to upload pictures to the server in a directory and save the picture path in the database. Here you can find out a complete tutorial to upload the picture on the server and save its path in the MYSQL database.
The typical way (based on research) for saving bitmap images from a remote url is:
Bitmap bmImage = null;
InputStream in = new java.net.URL(imageUrl).openStream();
bmImage = BitmapFactory.decodeStream(in);
File file = new File(myPath);
FileOutputStream outputStream;
outputStream = new FileOutputStream(file);
bmImage.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.close();
I cannot save bitmap unless it is compressed (Bitmap is always uncompressed).
The remote image size is 32KB, after compression it gets 110KB.
I know I have to lower compression parameter to get smaller size, but the remote image is optimize and much more efficient.
Is there a way I can save the remote image on mobile storage without compressing it?
===== ANSWER TO MY PROBLEM =====
First I apologize for misleading content; all I wanted is to save images that could be png|jpeg|gif|etc.. Probably I mislead you guys that the image I am trying to save is in BMP format, but it is not.
Nevertheless, for those who want to save images WITHOUT compressing, have a look to this answer
Use AndroidBmpUtil as shown in the code below:
new AndroidBmpUtil().save(bmImage, file);
I have a jpeg, and on the end of it I wrote a zip file.
Inside this zip file is a single txt file called hidden.txt. I can change the extension to zip and read the file just fine on my laptop (debian) but when I try to read it using either a ZipInputStream or using ZipFile I get an error telling me it's not a zip file.
I tried separating the jpg part out first by reading the whole thing to a Bitmap then writing that to a byte[], however the byte[] encompassed more than just the image.
My method to combine the bitmap and the zipFile (a byte[])
private byte[] combineFiles(Bitmap drawn, byte[] zip) throws
IOException {
InputStream in;
ByteArrayOutputStream out = new ByteArrayOutputStream();
/*write the first file*/
byte[] img;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
drawn.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
img = byteArrayOutputStream.toByteArray();
in = new ByteArrayInputStream(img);
IOUtils.copy(in, out);
in.close();
/*add the second (hidden) file*/
in = new ByteArrayInputStream(zip);
IOUtils.copy(in, out);
out.flush();
in.close();
return out.toByteArray();
}
So really I have two questions,
How do I separate the jpg and zip portions of the file?
How do I unzip hidden.txt (preferably into a byte[])
fairly certain I know this one, but what I am doing currently does not work, probably because I am doing #1 wrong
Ok, well here's how I would do this. Although it's very hacky.
The problem is that it's hard to tell the index of the boundary between the image data and the zip data. Assuming that you can write arbitrary data after the image data and still have a working image file, here is something you could try:
write out the image data.
write out a magical string like "BEGIN_ZIP"
write out the zip data.
Now, when you are trying to read things back in:
byte[] data = readAllTheBytes();
int index = searchFor("BEGIN_ZIP", data) + "BEGIN_ZIP".length();
// now you know that the zip data begins at index and goes to the end of the byte array
// so just use a regular zipinputstream to read in the zip data.
In JPEG file 0xFF, 0xD8 sequence of bytes indicates start of image and 0xFF, 0xD9 sequence of bytes indicates end of image JPEG Structure Wikipedia. So simply search for the latter sequence in file and you will be able to separate image and zip parts. Then use ZipInputStream to read (decompress) the data from zip file.