stuck loading image to Oracle and retrieving in servlet - java

I thought this would be a quick fun project, but it's turning into a problem. :(
I want to load some images into an Oracle table and then later retrieve them with hibernate through a servlet.
So here's the portion of the loader that inserts the image.
String imageFileName = row[col++];
String ext = imageFileName.substring(imageFileName.lastIndexOf('.') + 1);
String imageFilePath = imageDir + imageFileName;
String mimeType = "image/" + ext;
image.setImageType(mimeType);
Image found = imageDAO.retrieve(imageId);
if(found==null){
//create a new one
byte[] bytes = loadImage(imageFilePath, mimeType);
image.setImageData(bytes);
image = imageDAO.create(image);
++created;
}
else{
//check if an update is needed
if(updateDate.after(found.getUpdated())){
byte[] bytes = loadImage(imageFilePath, mimeType);
found.setImageData(bytes);
found.setUpdated(updateDate);
image = imageDAO.update(found);
++updated;
}
}
}
and here's the servlet innards:
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
String imageId = request.getParameter(KeyNames.PARM_IMAGE_ID);
if(imageId==null){
throw new NullPointerException("Image ID parameter is required");
}
Image image = getImageDAO().retrieve(imageId);
if(image==null){
throw new IllegalArgumentException(imageId + " is not a valid image ID");
}
response.setContentType(image.getImageType());
response.getOutputStream().write(image.getImageData());
response.getOutputStream().close();
return null;
}
Seems simple to me, but when I hit the URL using my browser, I get:
"The image [url] cannot be displayed because it contains errors"
Since the servlet is wrapping successful, I must guess that either in the loading or in the retrieving, I've corrupted the image data. I'm out of guesses as to what to do next, so any advice is appreciated.

Shame on me! This is what I get for running code off the internet without actually studying it to find out what it does!
So the answer was that I was running the image through a writable raster in order to store in the DB. Well, DUH! when you rasterize the image, it's not a png anymore.
So I simply do a byte copy from the input file and store that in the blob and it works fine.
Shoot me now.
Thanks for the help!

Related

webview.evaluateJavascript apparently just not running for long strings

I have an android app I've programmed where most of the action happens in a html+javascript webView, and I have a couple of scenarios where I pass data and commands back and forth between the Java side and the WebView/JS side.
I've recently programmed a way for the JS side to trigger a registerForActivityResult(new ActivityResultContracts.GetContent(), ... call to allow the user to select an image, and it works, but when I try to send the data back from Java to my javascript, it fails.
public void onActivityResult(Uri uri) {
// this means I've got the URI selected from the gallery
try {
final InputStream imageStream = getContentResolver().openInputStream(uri);
final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
String ecImage = Base64.encodeToString(b, Base64.DEFAULT);
myWebView.evaluateJavascript("onImageSelectTest('" + ecImage + "')", null);
} catch (FileNotFoundException e) {
// e.printStackTrace();
}
}
After a bit of testing, I've found that it's only when the ecImage variable contains the base64 long string that the function doesn't run -- it runs just fine if I set ecImage = "abcd"; for example.
I want the webview to have the image for display purposes and, mainly, for posting the data to a web server, and right now for me the easiest way I can think of doing that is passing the image as a base64 string, but the evaluateJavascript call just isn't working with the long strings right now. I'm open to alternative ways of passing the image data to the webview.

Publishing a post with a picture to the facebook page with restFb

When I publish a picture to my wall by
FacebookType publish = fc.publish("me/photos", FacebookType.class,
BinaryAttachment.with(attachmentName, temporaryStream),
Parameter.with("message", "my myssage"));
the post is created as expected. I can see a message and the published pictute under the message .
but when I want to do the same but on some pages wall instead the user wall by.
FacebookType publish = fc.publish(pageId + "/photos", FacebookType.class,
BinaryAttachment.with(attachmentName, temporaryStream),
Parameter.with("message", "my myssage"));
the post is published, but I can see only text. Not the picture. The picture can be seen only when I click on the date of the post. I can also reach this photo by clicking on the photos on the top of the page and then "name of the page" photos tab.
Is there any way how to see the photo as the part of the post also when I post it on a page?
I finally found a solution. To publish post with a photo to the section with normal "text only" posts you need publish a photo to your wall (your user wall not the wall of the page), then get its link and finally create a feed to the page with the the picture link.
here is the sample code:
FacebookType photo = fc.publish(pageid + "/photos" , FacebookType.class,
BinaryAttachment.with(photoName, photoInputStream));
Link photoLink = fc.fetchObject(photo.getId(), Link.class);
FacebookType post = fc.publish(pageid + "/feed", FacebookType.class,
Parameter.with("message", "your message"),Parameter.with("type", "photo"),
Parameter.with("link", photoLink.getLink()));
edit: I forgot about one thing. When you later delete the post, you do not delete to photo. To do that you have to do that manually.
Your Answer worked a treat and helped me untold amounts however i found with my solution I didn't need
FacebookType post = fc.publish(pageid + "/feed", FacebookType.class,
Parameter.with("message", "your message"),Parameter.with("type", "photo"),
Parameter.with("link", photoLink.getLink()));
as i would recive an error (that i should have copied to show you) but photoLink.getLink() returned null in my case.
so my updated solution ended up being
FacebookType photo = client.publish(groupId + "/photos",
FacebookType.class,
BinaryAttachment.with(imageName),
imageAsBytes,
"image/png"),
Parameter.with("message",
message));
Just my 2 cents, Thanks again for your help!
EDIT
Also while playing around I noticed that in the solution I arrived at I was creating a FacebookType photo object and this object doesn't get used anywhere, your just calling the publish method of the client that's created further up in your program.
my final class is below, (my application is taking an image from the computer and posing to a groups wall)
public void createImagePostInGroup(String message, String groupId, String imageFilePath){
byte[] imageAsBytes = fetchBytesFromImage(imageFilePath);
DefaultFacebookClient client =
new DefaultFacebookClient(accessToken, Version.LATEST);
client.publish(groupId + "/photos",
FacebookType.class,
BinaryAttachment.with(imageFilePath.substring(imageFilePath.length()-34),
imageAsBytes,
"image/png"),
Parameter.with("message",
message));
}
And my image is converted into a byte array in this method
private byte[] fetchBytesFromImage(String imageFile) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte fileContent[] = null;
try{
BufferedImage image = ImageIO.read(new File(imageFile));
ImageIO.write(image, "png", baos);
baos.flush();
fileContent = baos.toByteArray();
}catch (Exception e){
e.printStackTrace();
}
return fileContent;
}
Again thanks for your help.

Issue with reading Tiff image metadata with imageIO

I'm writing a program that is supposed to taking in a bunch of tiff's and put them together. I got it to work for most of the image files I read in but a large batch of them throw out an error when I try to read them in.
Here is a snippet of code I have:
int numPages = 0;
inStream = ImageIO.createImageInputStream(imageFile);
reader.setInput(inStream);
while(true){
bufferedImages.add(reader.readAll(numPages, reader.getDefaultReadParam()));
numPages++;
}
Yes I catch the out of bounds exception so we don't have to worry about that. My problem is that I get the following error:
javax.imageio.IIOException: I/O error reading image metadata!
at com.sun.media.imageioimpl.plugins.tiff.TIFFImageReader.readMetadata(TIFFImageReader.java:340)
at com.sun.media.imageioimpl.plugins.tiff.TIFFImageReader.seekToImage(TIFFImageReader.java:310)
at com.sun.media.imageioimpl.plugins.tiff.TIFFImageReader.prepareRead(TIFFImageReader.java:971)
at com.sun.media.imageioimpl.plugins.tiff.TIFFImageReader.read(TIFFImageReader.java:1153)
at javax.imageio.ImageReader.readAll(ImageReader.java:1067)
at sel.image.appender.ImageAppender.mergeImages(ImageAppender.java:59)
at sel.imagenow.processor.AetnaLTCProcessor.processBatch(AetnaLTCProcessor.java:287)
at sel.imagenow.processor.AetnaLTCProcessor.processImpl(AetnaLTCProcessor.java:81)
at sel.processor.AbstractImageNowProcessor.process(AbstractImageNowProcessor.java:49)
at sel.RunConverter.main(RunConverter.java:37)
Caused by: java.io.EOFException
at javax.imageio.stream.ImageInputStreamImpl.readShort(ImageInputStreamImpl.java:229)
at javax.imageio.stream.ImageInputStreamImpl.readUnsignedShort(ImageInputStreamImpl.java:242)
at com.sun.media.imageioimpl.plugins.tiff.TIFFIFD.initialize(TIFFIFD.java:194)
at com.sun.media.imageioimpl.plugins.tiff.TIFFImageMetadata.initializeFromStream(TIFFImageMetadata.java:110)
at com.sun.media.imageioimpl.plugins.tiff.TIFFImageReader.readMetadata(TIFFImageReader.java:336)
... 9 more
I did make sure to add in the right JAI lib and my reader is using the "TIFF" type so the reader (and writer) is correct but for some reason the metadata is wrong. Now I can open and view all these images normally in windows so they really aren't corrupted or anything. Java just doesn't want to read them in right. Since I'm just using the stream meatadata to write them out later I don't care that much about the metadata I just need it to read in the file to the list so I can append it. I did find a writer.replaceImageMetaData method on the writer but the TIFFwriter version of IOWriter doens't have code for it. I'm stuck, anyone anything? Is there maybe a way to read in parts of the metadata to see what is wrong and fix it?
For anyone that would like to know I ended up fixing my own issue. It seems the the image metadata was a bit screwed up. Since I was just doing a plain merge and since I knew each image was one page I was able to use a buffered image to read in the picture then make it a IIOImage with null metadata. I used the stream metadata (which worked) to merge the images. Here is my complete method I use to merge a list of images:
public static File mergeImages(List<File> files, String argID, String fileType, String compressionType) throws Exception{
//find the temp location of the image
String location = ConfigManager.getInstance().getTempFileDirectory();
logger_.debug("image file type [" + fileType + "]");
ImageReader reader = ImageIO.getImageReadersByFormatName(fileType).next();
ImageWriter writer = ImageIO.getImageWritersByFormatName(fileType).next();
//set up the new image name
String filePath = location + "\\" + argID +"." + fileType;
//keeps track of the images we copied from
StringBuilder builder = new StringBuilder();
List<IIOImage> bufferedImages = new ArrayList<IIOImage>();
IIOMetadata metaData = null;
for (File imageFile:files) {
//get the name for logging later
builder.append(imageFile.getCanonicalPath()).append("\n");
if (metaData == null){
reader.setInput(ImageIO.createImageInputStream(imageFile));
metaData = reader.getStreamMetadata();
}
BufferedImage image = ImageIO.read(imageFile);
bufferedImages.add(new IIOImage(image, null, null));
}
ImageWriteParam params = writer.getDefaultWriteParam();
if (compressionType != null){
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
params.setCompressionType(compressionType);
}
ImageOutputStream outStream = null;
try{
outStream = ImageIO.createImageOutputStream(new File(filePath));
int numPages = 0;
writer.setOutput(outStream);
for(IIOImage image:bufferedImages){
if (numPages == 0){
writer.write(metaData, image, params);
}
else{
writer.writeInsert(numPages, image, params);
}
numPages++;
}
}
finally{
if (outStream != null){
outStream.close();
}
}
//set up the file for us to use later
File mergedFile = new File(filePath);
logger_.info("Merged image into [" + filePath + "]");
logger_.debug("Merged images [\n" + builder.toString() + "] into --> " + filePath);
return mergedFile;
}
I hope this help someone else because I know there isn't much on this issue that I could find.

Update database table without uploading a file while using a MultiPart Form - JavaEE, Servlet

I have a servlet which is responsible for enabling a user to update a reports table and upload a report at the same time. I have written code that enables a user upload a document and also be able to update the table with other details e.g date submitted etc.
However not all the times will a user have to upload a document. in this case it should be possible for a user to still edit a report's details and come back later to upload the file. i.e the user can submit the form without selecting a file and it still updates the table.
This part is what is not working. If a user selects a file and makes some changes. The code works. If a user doesn't select a file and tries to submit the form, it redirects to my servlet but it is blank. no stacktrace. No error is thrown.
Below is part of the code I have in my servlet:
if(param.equals("updateschedule"))
{
String[] allowedextensions = {"pdf","xlsx","xls","doc","docx","jpeg","jpg","msg"};
final String path = request.getParameter("uploadlocation_hidden");
final Part filepart=request.getPart("uploadreport_file");
int repid = Integer.parseInt(request.getParameter("repid_hidden"));
int reptype = Integer.parseInt(request.getParameter("reporttype_select"));
String webdocpath = request.getParameter("doclocation_hidden");
String subperiod = request.getParameter("submitperiod_select");
String duedate = request.getParameter("reportduedate_textfield");
String repname = request.getParameter("reportname_textfield");
String repdesc = request.getParameter("reportdesc_textarea");
String repinstr = request.getParameter("reportinst_textarea");
int repsubmitted = Integer.parseInt(request.getParameter("repsubmitted_select"));
String datesubmitted = request.getParameter("reportsubmitdate_textfield");
final String filename = getFileName(filepart);
OutputStream out = null;
InputStream filecontent=null;
String extension = filename.substring(filename.lastIndexOf(".") + 1, filename.length());
if(Arrays.asList(allowedextensions).contains(extension))
{
try
{
out=new FileOutputStream(new File(path+File.separator+filename));
filecontent = filepart.getInputStream();
int read=0;
final byte[] bytes = new byte[1024];
while((read=filecontent.read(bytes))!=-1)
{
out.write(bytes,0,read);
}
String fulldocpath = webdocpath+"/"+filename;
boolean succ = icreditdao.updatereportschedule(repid, reptype, subperiod, repname, repsubmitted,datesubmitted, duedate,fulldocpath, repdesc, repinstr);
if(succ==true)
{
response.sendRedirect("/webapp/Pages/Secured/ReportingSchedule.jsp?msg=Report Schedule updated successfully");
}
}
catch(Exception ex)
{
throw new ServletException(ex);
}
}
I'm still teaching myself javaee. Any help will be appreciated. Also open to other alternatives. I have thought of using jquery to detect if a file has been selected then use a different set of code. e.g
if(param.equals("updatewithnofileselected"))
{//update code here}
but I think there must be a better solution. Using jdk6, servlet3.0.
try this one.
MultipartParser parser = new MultipartParser(request, 500000000, false, false, "UTF-8");
Part part;
while ((part = parser.readNextPart()) != null) {
if(part.isParam()){
if(part.isFile()){
if(part.getName().equals("updatewithnofileselected")){
//update code here.
} else if(part.getName().equals("updateschedule")) {
//updateschedule
}
}
}
}
I used this one when I am using Multipart-form and it's working fine.

Convert byte[] to Base64 string for data URI

I know this has probably been asked 10000 times, however, I can't seem to find a straight answer to the question.
I have a LOB stored in my db that represents an image; I am getting that image from the DB and I would like to show it on a web page via the HTML IMG tag. This isn't my preferred solution, but it's a stop-gap implementation until I can find a better solution.
I'm trying to convert the byte[] to Base64 using the Apache Commons Codec in the following way:
String base64String = Base64.encodeBase64String({my byte[]});
Then, I am trying to show my image on my page like this:
<img src="data:image/jpg;base64,{base64String from above}"/>
It's displaying the browser's default "I cannot find this image", image.
Does anyone have any ideas?
Thanks.
I used this and it worked fine (contrary to the accepted answer, which uses a format not recommended for this scenario):
StringBuilder sb = new StringBuilder();
sb.append("data:image/png;base64,");
sb.append(StringUtils.newStringUtf8(Base64.encodeBase64(imageByteArray, false)));
contourChart = sb.toString();
According to the official documentation Base64.encodeBase64URLSafeString(byte[] binaryData) should be what you're looking for.
Also mime type for JPG is image/jpeg.
That's the correct syntax. It might be that your web browser does not support the data URI scheme. See Which browsers support data URIs and since which version?
Also, the JPEG MIME type is image/jpeg.
You may also want to consider streaming the images out to the browser rather than encoding them on the page itself.
Here's an example of streaming an image contained in a file out to the browser via a servlet, which could easily be adopted to stream the contents of your BLOB, rather than a file:
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
ServletOutputStream sos = resp.getOutputStream();
try {
final String someImageName = req.getParameter(someKey);
// encode the image path and write the resulting path to the response
File imgFile = new File(someImageName);
writeResponse(resp, sos, imgFile);
}
catch (URISyntaxException e) {
throw new ServletException(e);
}
finally {
sos.close();
}
}
private void writeResponse(HttpServletResponse resp, OutputStream out, File file)
throws URISyntaxException, FileNotFoundException, IOException
{
// Get the MIME type of the file
String mimeType = getServletContext().getMimeType(file.getAbsolutePath());
if (mimeType == null) {
log.warn("Could not get MIME type of file: " + file.getAbsolutePath());
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
resp.setContentType(mimeType);
resp.setContentLength((int)file.length());
writeToFile(out, file);
}
private void writeToFile(OutputStream out, File file)
throws FileNotFoundException, IOException
{
final int BUF_SIZE = 8192;
// write the contents of the file to the output stream
FileInputStream in = new FileInputStream(file);
try {
byte[] buf = new byte[BUF_SIZE];
for (int count = 0; (count = in.read(buf)) >= 0;) {
out.write(buf, 0, count);
}
}
finally {
in.close();
}
}
If you don't want to stream from a servlet, then save the file to a directory in the webroot and then create the src pointing to that location. That way the web server does the work of serving the file. If you are feeling particularly clever, you can check for an existing file by timestamp/inode/crc32 and only write it out if it has changed in the DB which can give you a performance boost. This file method also will automatically support ETag and if-modified-since headers so that the browser can cache the file properly.

Categories