image compression using s3 and lambda in java - java

I am trying to fetch image from s3 bucket of aws in lambda fuction and i want to compress this image and upload back to destination bucket of aws s3. I tried to fetch file from s3 and compress it.but facing problem in uploading the compressed file

Finally this worked
public class TempComp implements RequestHandler<S3Event, String> {
private static final float MAX_WIDTH = 100;
private static final float MAX_HEIGHT = 100;
private final String JPG_TYPE = (String) "jpg";
private final String JPG_MIME = (String) "image/jpeg";
private final String PNG_TYPE = (String) "png";
private final String PNG_MIME = (String) "image/png";
public String handleRequest(S3Event s3event, Context context) {
try {
S3EventNotificationRecord record = s3event.getRecords().get(0);
String srcBucket = record.getS3().getBucket().getName();
// Object key may have spaces or unicode non-ASCII characters.
String srcKey = record.getS3().getObject().getKey()
.replace('+', ' ');
srcKey = URLDecoder.decode(srcKey, "UTF-8");
String dstBucket = srcBucket + "resized";
String dstKey = "resized-" + srcKey;
// Sanity check: validate that source and destination are different
// buckets.
if (srcBucket.equals(dstBucket)) {
System.out
.println("Destination bucket must not match source bucket.");
return "";
}
// Infer the image type.
Matcher matcher = Pattern.compile(".*\\.([^\\.]*)").matcher(srcKey);
if (!matcher.matches()) {
System.out.println("Unable to infer image type for key "
+ srcKey);
return "";
}
String imageType = matcher.group(1);
if (!(JPG_TYPE.equals(imageType)) && !(PNG_TYPE.equals(imageType))) {
System.out.println("Skipping non-image " + srcKey);
return "";
}
// Download the image from S3 into a stream
AmazonS3 s3Client = new AmazonS3Client();
S3Object s3Object = s3Client.getObject(new GetObjectRequest(
srcBucket, srcKey));
InputStream objectData = s3Object.getObjectContent();
// int b=objectData.read();
// Read the source image
BufferedImage srcImage = ImageIO.read(objectData);
// BufferedImage destImage = srcImage;
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
if (!writers.hasNext())
throw new IllegalStateException("No writers found");
ImageWriter writer = (ImageWriter) writers.next();
ByteArrayOutputStream os=new ByteArrayOutputStream() ;
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
// compress to a given quality
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.5f);
// appends a complete image stream containing a single image and
//associated stream and image metadata and thumbnails to the output
writer.write(null, new IIOImage(srcImage, null, null), param);
System.out.print("file is compressed");
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
//InputStream is = new ByteArrayInputStream(retValue);
BufferedImage destImage = ImageIO.read(is);
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
ImageIO.write(destImage, imageType, os1);
InputStream is1 = new ByteArrayInputStream(os1.toByteArray());
// Set Content-Length and Content-Type
ObjectMetadata meta = new ObjectMetadata();
meta.setContentLength(os1.size());
System.out.println(os1.size());
if (JPG_TYPE.equals(imageType)) {
meta.setContentType(JPG_MIME);
}
if (PNG_TYPE.equals(imageType)) {
meta.setContentType(PNG_MIME);
}
// Uploading to S3 destination bucket
System.out.println("Writing to: " + dstBucket + "/" + dstKey);
s3Client.putObject(dstBucket, dstKey, is1, meta);
System.out.println("Successfully resized " + srcBucket + "/"
+ srcKey + " and uploaded to " + dstBucket + "/" + dstKey);
return "Ok";
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

Related

S3 Multipart Upload Error Code: MalformedXML

I am using the following code to for multipart upload to s3.
public boolean uploadFileToS3(List<InputStream> filePartitions ) throws FileException, IOException{
AWSCredentials credentials = new BasicAWSCredentials("access_key","secret_key");
String existingBucketName = "bucketName";
String keyName = "file.log";
AmazonS3 s3Client = new AmazonS3Client(credentials);
// Create a list of UploadPartResponse objects. You get one of these for
// each part upload.
List<PartETag> partETags = new ArrayList<PartETag>();
// Step 1: Initialize.
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(existingBucketName, keyName);
InitiateMultipartUploadResult initResponse = s3Client.initiateMultipartUpload(initRequest);
try {
// Step 2: Upload parts.
Iterator its = filePartitions.iterator();
int i=0;
while(its.hasNext()){
UploadPartRequest uploadRequest = new UploadPartRequest()
.withBucketName(existingBucketName)
.withKey(keyName)
.withUploadId(initResponse.getUploadId()).withPartNumber(i)
.withInputStream((InputStream)its.next());
i++;
System.out.println("Part " + i + "is uploaded");
}
// Step 3: Complete.
CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(existingBucketName,
keyName,
initResponse.getUploadId(),
partETags);
s3Client.completeMultipartUpload(compRequest);
} catch (Exception e) {
System.out.println("******************************");
System.out.println(e.getMessage());
System.out.println(e.getCause());
System.out.println("************************");
s3Client.abortMultipartUpload(new AbortMultipartUploadRequest(
existingBucketName, keyName, initResponse.getUploadId()));
}
return true;
}
I am facing the following exception when I run this code.
The XML you provided was not well-formed or did not validate against our published schema (Service: Amazon S3; Status Code: 400; Error Code: MalformedXML; Request ID: C0538A21C25A2DD4)
In the above code List filePartitions is created from a large file.
each chunk is of 20000 bytes.
I have used the following code to split the file into partitions as I have InputStream data directly not a file. It is a REST API.
List<InputStream> filePartitions = new ArrayList<InputStream>();
InputStream inStream = new BufferedInputStream(a_fileInputStream);
int totalBytesRead = 0;
int FILE_SIZE = a_fileInputStream.available();
int chunkSize = 20000;
while (totalBytesRead < FILE_SIZE) {
int bytesRemaining = FILE_SIZE - totalBytesRead;
if (bytesRemaining < chunkSize) {
chunkSize = bytesRemaining;
}
byte[] buffer=new byte[chunkSize];
//Temporary Byte Array
int read = inStream.read(buffer,0,chunkSize);
int bytesRead = inStream.read(buffer, 0, chunkSize);
if (bytesRead > 0) // If bytes read is not empty
{
totalBytesRead += bytesRead;
//create InputStream from temporary byte array
InputStream partition = new ByteArrayInputStream(buffer);
filePartitions.add(partition);
}
}
return filePartitions;

Java - Cannot view modified metadata

I have been trying to access modified metadata of images in Java for the past few hours. I know I am one or two steps away from getting the correct output. Would really appreciate if someone can help me with this.
I want to add an extra field in the metadata, which is like an text similar to:
Writing image metadata in Java, preferably PNG
My issue is that when i add the custom data to my image and when i read the image, i do not see the change in the modified metadata when i call the method readAndDisplay. I think the reason is that i am not saving the image properly into a new file with the modified metadata. Can someone have a look at what i am missing from my code:
public class Metadata {
public static void main(String[] args) throws Exception {
String imageFile = "134.png";
BufferedImage img = null;
try {
img = ImageIO.read(new File(imageFile));
} catch (IOException e) {
System.out.println(e.getMessage());
}
Metadata meta = new Metadata();
byte[] result = meta.writeCustomData(img, "decimalID", "211");
BufferedImage output = ImageIO.read(new ByteArrayInputStream(result));
ImageIO.write(output, "png", new File("output.png"));
meta.readAndDisplayMetadata("output.png");
}
void readAndDisplayMetadata( String fileName ) {
try {
File file = new File( fileName );
ImageInputStream iis = ImageIO.createImageInputStream(file);
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
if (readers.hasNext()) {
// pick the first available ImageReader
ImageReader reader = readers.next();
// attach source to the reader
reader.setInput(iis, true);
// read metadata of first image
IIOMetadata metadata = reader.getImageMetadata(0);
String[] names = metadata.getMetadataFormatNames();
int length = names.length;
System.out.println(length);
for (int i = 0; i < length; i++) {
System.out.println( "Format name: " + names[ i ] );
displayMetadata(metadata.getAsTree(names[i]));
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
void readAndDisplayMetadata( byte[] image ) {
try {
// File file = new File( fileName );
ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(image));
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
if (readers.hasNext()) {
// pick the first available ImageReader
ImageReader reader = readers.next();
// attach source to the reader
reader.setInput(iis, true);
// read metadata of first image
IIOMetadata metadata = reader.getImageMetadata(0);
String[] names = metadata.getMetadataFormatNames();
int length = names.length;
System.out.println(length);
for (int i = 0; i < length; i++) {
System.out.println( "Format name: " + names[ i ] );
displayMetadata(metadata.getAsTree(names[i]));
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
void displayMetadata(Node root) {
displayMetadata(root, 0);
}
void indent(int level) {
for (int i = 0; i < level; i++)
System.out.print(" ");
}
void displayMetadata(Node node, int level) {
// print open tag of element
indent(level);
//System.out.println("Attributes: " + node.getAttributes().getLength());
System.out.print("<" + node.getNodeName());
NamedNodeMap map = node.getAttributes();
if (map != null) {
// print attribute values
int length = map.getLength();
for (int i = 0; i < length; i++) {
Node attr = map.item(i);
System.out.print(" " + attr.getNodeName() +
"=\"" + attr.getNodeValue() + "\"");
}
}
Node child = node.getFirstChild();
if (child == null) {
// no children, so close element and return
System.out.println("/>");
return;
}
// children, so close current tag
System.out.println(">");
while (child != null) {
// print children recursively
displayMetadata(child, level + 1);
child = child.getNextSibling();
}
// print close tag of element
indent(level);
System.out.println("</" + node.getNodeName() + ">");
}
public byte[] writeCustomData(BufferedImage buffImg, String key, String value) throws Exception {
ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
//adding metadata
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
IIOMetadataNode textEntry = new IIOMetadataNode("tEXtEntry");
textEntry.setAttribute("keyword", key);
textEntry.setAttribute("value", value);
IIOMetadataNode text = new IIOMetadataNode("tEXt");
text.appendChild(textEntry);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_png_1.0");
root.appendChild(text);
metadata.mergeTree("javax_imageio_png_1.0", root);
//writing the data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream stream = ImageIO.createImageOutputStream(baos);
writer.setOutput(stream);
writer.write(metadata, new IIOImage(buffImg, null, metadata), writeParam);
stream.close();
return baos.toByteArray();
}

Java Buffer Image form online Webcam

I have to write servlet which capture few images from the online Webcam. Every parameter like(URL, Interval, numer, and count) are send by POST method. In my servlet file I have something like that:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String url = request. getParameter("url").toString();
int interwal = Integer.parseInt(request.getParameter("interwal").toString());
int nrSt = Integer.parseInt(request.getParameter("nr").toString());
int il = Integer.parseInt(request.getParameter("il").toString());
PrintWriter out = response.getWriter();
BufferedImage img;
URL imgURL;
File imgFile;
for(int i=0; i<il; i++){
try{
imgURL = new URL(url);
img = ImageIO.read(imgURL);
imgFile = new File("E:\\image" + (nrSt+i) + ".jpg");
ImageIO.write(img, "png", imgFile);
out.print("Saved image" + (nrSt+i) + ".jpg<br>");
} catch(IOException e){
out.print("Error reading Image!");
e.printStackTrace();
}
try {
Thread.sleep(interwal*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
What I must change to capture image form for examle this webcam: cam
Using a webcam page can be much more difficult. The one you chose as example uses a dynamic image URL which is calculated on the page using JavaScript - but it is simple enough to easily extract what you need. The next problem is that the image URL points to a service which answers with multi-part responses which ImageIO.read() does not seem to understand.
The following standalone code seems to successfully acquire the webcam image:
public static void main(String[] args) {
try {
// get webcam page
URL url = new URL("...your example URL.../webcam/campob.html");
InputStreamReader isr = new InputStreamReader(url.openStream(), "UTF-8");
Scanner scanner = new Scanner(isr);
final Pattern nullDelimiter = Pattern.compile("<<<>>>");
String html = scanner.useDelimiter(nullDelimiter).next();
scanner.close();
// extract image URL from HTML
final Pattern extractPattern = Pattern.compile(
"^var BaseURL = \"([^\"]+)\".*"
+ "^var ImageResolution = \"([^\"]+)\".*"
+ "^var File = \"([^\"]+)\"",
Pattern.MULTILINE|Pattern.DOTALL);
Matcher m = extractPattern.matcher(html);
if (!m.find()) throw new RuntimeException();
URL imgURL = new URL(m.group(1) + m.group(3) + m.group(2));
System.out.println("imgURL=" + imgURL);
// read headers into buffer
InputStream is = imgURL.openStream();
byte[] buffer = new byte[131072];
int bytes = 0;
Pattern headersPattern = Pattern.compile(
"^Content-Length:\\s*(\\d+)\\s*$.*?^$\\r?\\n",
Pattern.MULTILINE|Pattern.DOTALL);
while (bytes < buffer.length) {
int count = is.read(buffer, bytes, buffer.length - bytes);
if (count < 0) break;
bytes += count;
m = headersPattern.matcher(new String(buffer, "ASCII"));
if (m.find()) break;
}
// read rest of image bytes into buffer
int offset = m.end();
int contentLength = Integer.parseInt(m.group(1));
int limit = Math.min(buffer.length, offset + contentLength);
while (bytes < limit) {
int count = is.read(buffer, bytes, limit - bytes);
if (count < 0) break;
bytes += count;
}
is.close();
System.out.println("bytes=" + bytes + " offset=" + offset);
// read image from buffer (start after header)
is = new ByteArrayInputStream(buffer);
is.skip(offset);
Image img = ImageIO.read(is);
System.out.println(img);
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
Note that the code is lacking real error handling, the buffer has fixed size etc.

Java - user-mapped section open error

When I try to write to the file specified it comes up with the error below. I have tried closing the FileInputStream but I still come up with the same problem.
Here is the relevant code:
Error log:
Error: C:\Path\Hours Log.csv (The requested operation cannot be performed on a file with a user-mapped section open)
Code:
Creating the log:
private void writeLog() throws IOException{
//set up vars and write directories
File yearStatDir = new File("C:\\Path);
File yearStatPath = new File(yearStatDir + "\\" + "Hours Log.csv");
String yearStatString = yearStatPath.toString();
//read the files
String existingYearLog = readLogFile(yearStatString, yearStatPath);
//write the updated file
String hoursString = "1";
String dataYear = existingYearLog + hoursString;
String folderYear = "Satistics\\Yearly data\\" + yearString;
writeFile(dataYear, ".csv", folderYear, "Hours Log");
}
Writing the file:
private void writeFile(String data, String fileType, String folder, String fileName){
try{
File fileDir = new File("C:\\Path\\" + folder);
File filePath = new File(fileDir + "\\"+ fileName + fileType);
writeDir(fileDir);
// Create file
FileWriter fstream = new FileWriter(filePath);
try (BufferedWriter out = new BufferedWriter(fstream)) {
out.write(data);
}
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
Reading the file:
private static String readLogFile(String path, File f) throws IOException {
if (f.exists()){
try (FileInputStream stream = new FileInputStream(new File(path))) {
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
/* Instead of using default, pass in a decoder. */
fc.close();
return Charset.defaultCharset().decode(bb).toString();
}
}
else {
return "";
}
}
For anyone that comes across this, here is the alternative code that I am using now:
private static String readLogFile(String path) throws IOException {
File f = new File(path);
if(f.exists()) {
FileInputStream fis = new FileInputStream(f);
Integer fileLength = (int) (long) f.length();
byte[] b = new byte[fileLength];
int read = 0;
while (read < b.length) {
read += fis.read(b, read, b.length - read);
}
String text = new String(b);
return text;
} else {
String text = "";
return text;
}
}

Reading in bytes produced by PHP script in Java to create a bitmap

I'm having trouble getting the compressed jpeg image (stored as a blob in my database).
here is the snippet of code I use to output the image that I have in my database:
if($row = mysql_fetch_array($sql))
{
$size = $row['image_size'];
$image = $row['image'];
if($image == null){
echo "no image!";
} else {
header('Content-Type: content/data');
header("Content-length: $size");
echo $image;
}
}
here is the code that I use to read in from the server:
URL sizeUrl = new URL(MYURL);
URLConnection sizeConn = sizeUrl.openConnection();
// Get The Response
BufferedReader sizeRd = new BufferedReader(new InputStreamReader(sizeConn.getInputStream()));
String line = "";
while(line.equals("")){
line = sizeRd.readLine();
}
int image_size = Integer.parseInt(line);
if(image_size == 0){
return null;
}
URL imageUrl = new URL(MYIMAGEURL);
URLConnection imageConn = imageUrl.openConnection();
// Get The Response
InputStream imageRd = imageConn.getInputStream();
byte[] bytedata = new byte[image_size];
int read = imageRd.read(bytedata, 0, image_size);
Log.e("IMAGEDOWNLOADER", "read "+ read + " amount of bytes");
Log.e("IMAGEDOWNLOADER", "byte data has length " + bytedata.length);
Bitmap theImage = BitmapFactory.decodeByteArray(bytedata, 0, image_size);
if(theImage == null){
Log.e("IMAGEDOWNLOADER", "the bitmap is null");
}
return theImage;
My logging shows that everything has the right length, yet theImage is always null.
I'm thinking it has to do with my content type. Or maybe the way I'm uploading?
Try this function. It works for me:
Bitmap loadPhotoBitmap(URL url) {
Bitmap bitmap = null;
InputStream in = null;
BufferedOutputStream out = null;
try {
FileOutputStream fos = new FileOutputStream("/sdcard/photo-tmp.jpg");
BufferedOutputStream bfs = new BufferedOutputStream(fos);
in = new BufferedInputStream(url.openStream(),
IO_BUFFER_SIZE);
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
copy(in, out);
out.flush();
final byte[] data = dataStream.toByteArray();
bfs.write(data, 0, data.length);
bfs.flush();
BitmapFactory.Options opt = new BitmapFactory.Options();
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opt);
} catch (IOException e) {
android.util.Log.e(LOG_TAG, "Could not load file: " + this, e);
} finally {
closeStream(in);
closeStream(out)
closeStream(bfs);
}
return bitmap;
}

Categories