GeeCON Prague 2014*
The moose likes Java in General and the fly likes programatically reducing size of BufferedImage Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Java » Java in General
Bookmark "programatically reducing size of BufferedImage" Watch "programatically reducing size of BufferedImage" New topic
Author

programatically reducing size of BufferedImage

naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692

I have a BufferedImage whose dimensions are 1440x900 and its size in memory is around 5 mb, now the problem arises when i want to transfer this file over network , my research about this problem get me toward this
I have to make the size of this BufferedImage as small as possible
Does any one know how to proceed, to solve this problem ?


The Only way to learn is ...........do!
Visit my blog http://inaved-momin.blogspot.com/
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2383
    
  28

You should compress the file using one of the many Image file formats before sending it over network.
naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692

Jayesh A Lalwani wrote:You should compress the file using one of the many Image file formats before sending it over network.
thanks for the reply , but i cannot do that because i m sending the image through ObjectOutputStream , and if i compress it then i have to send it using ImageIO.write();
which i don't want ....if i reduce the color of the image , then i guess the image's size will be reduce...? or do you have any other Manipulation technique through which we can reduce the size of image programatically ?
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4571
    
    5

Jayesh has already given the best answer.

naved momin wrote:...if i reduce the color of the image , then i guess the image's size will be reduce...?

What happened when you tried?


luck, db
There are no new questions, but there may be new answers.
naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692

Darryl Burke wrote:Jayesh has already given the best answer.

naved momin wrote:...if i reduce the color of the image , then i guess the image's size will be reduce...?

What happened when you tried?


The things is i haven't given it a try because i think before i put any effort it is wise to first discuss , you never know when you will get the best out of it
I m thinking of reducing color because i have seen in softwares like TeamViewer, successfully improves performance by slightly downgrading the quality of images which they further transport it over the wire.
Downgrading the quality mean they have an option saying adjust color between (Grayscale, 256, High and TrueColor)...so if you are saying i will give it a try but
do you have any other way from which the size of bufferedImage can be reduce a bit from say 5mb to 2 mb or even less
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4571
    
    5

The best way to learn is to try things for yourself.
naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692

Darryl Burke wrote:The best way to learn is to try things for yourself.

thanks for refreshing my bottom line quote
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2383
    
  28

Serializing a BufferredImage may not be the best option here. It depends on the kind of image you are sending. If you are more or less sending an image that has a few colors or huge blocks on uniform color, the serializing the BufferredImage into a byte[] and then compressing the byte[] will give you decent compression. However, for photos/screen captures you would get a low degree of compression

For photos, the best compression would be JPEG compression. Granted it is lossy, which might be ok for some applications. One advantage is you can increase compression by sacrificing quality. For screen captures, PNG will work best (although I might be wrong here). For icons, TIFF will work best. If you want to stay within the serialization framework, you can always make the bean that stores the BufferredImage externalizable, and customize how the image gets serialized and compressed


I would suggest however that you think outside the serialization box here. Applications like Teamviewer and VNC Viewer work well because they stream deltas to the client. They don't send the complete image for every frame. They send the complete image for the first frame. From then onwards, they take deltas of consecutive frame, compress it and send it to the client. Delta Images for screen captures provide a very high level of compression because more or less the screen doesn't change much from frame to frame

For images, you might want to look at the JPIP protocol which is part of the JPEG2000 standard. It allows you to download the resolution of the image that matches your bandwidth and screen resolution. I had worked on this way back when it was in it's infancy. It was very cool. We had a a Google Earth like application (actually we were developing this right when Google Earth came out), and it worked much like Google Earth did. If you opened up an area, it will show you a low resolution of the area, and it would become progressively clearer and clearer as you stayed on the screen. Google Earth does the same thing, except that it progressively downloads differrent JPEG files to get higher resolution. JPIP, OTH, makes this process much easier. You just open a stream to the JPIP server, and you first get a low res image, and then you get a higher res image, and then an even higher res, until you tell the server to stop or the server runs out of resolutions

naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692


first of all thanks jayesh for sharing your wonderful experience with us
I would like to give intro of my application to you ...we are developing an remote control application which will compete head-to-head with VNC & TeamViewer while it will remain OpenSource for both commercial and non commercial use.

every thing is working fine except the image part.

Things i tried but it didn't work
1. First i have used byteArrayOutputStream and written the byte[] to the stream but the array is so huge that it actually took almost second or two for writing to the stream and another 1 second on wire
so total 3 sec it took to reach client side
2. second i have used the ImageIO's read & write method for compressing the image into .jpg it just didn't work.

Things worked
1. Using GzipInputStream and equivalent OutputStream works but as i said earlier compressing is also taking 2-3 sec because of vast image size
2. Serialization framework works but same problem, because of the large image size the time it takes to write image's data to stream is almost 1-2 seconds another 1 second or so over the wire to get delivered to the client from server

What i have researched
I have studied the earlier two softwares but still i don't have much knowledge of this domain, what i know is VNC uses a RFB protocol kind of thing which is pretty simple first it just scan your entire screen and later it just send the pixels which gets changed , in order to achieve this we must know two things
1. First we have to write a code which will actually give us the pixels which gets changed
2. second we need to know the pixels location exactly so that server can replace the old pixels with the new pixels which will give the effect like screen has been changed
But the problem here is i don't know whether this can be done in Java or not if yes can you more knowledgeable guys will provide some help with pseudo code or something so that i can work on it
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2383
    
  28

Yes, the only way you can reduce the size of the data being transmitted is by using deltas. Sending the whole image for every frame has inherent overhead. An easy way of taking a delta between 2 frames would be to XOR the 2 frames. I am not sure whether you are familiar with XOR operation. It's basically a binary operation that operates like this

A B result
0 0 0
0 1 1
1 0 1
1 1 0


Note that the result is 1 only when the bit changes. Also, XOR operation has this property:-

If A XOR B = D
Then A XOR D = B

So, if you have 2 bytes .. you can XOR the bits in the bytes to get the delta byte. Java provides an API that XOR's 2 bytes

SO, if you have 2 frames.. each frame is made up of bytes.. XOR the corresponding bytes together:- byte 1 of first frame XORed with byte 1 of second frame and so on to get a delta byte array. The delta byte array should be the same size as the 2 byte arrays that you started with. Compress this delta byte array. There should be a high degree of compression because the delta for most of pixels should be 0. Send the compressed delta to client. On the client side reverse the operation:- a) decompress b) XOR the delta with the exisdting frame to get new frame c) draw the frame


You should be able to do this pretty fast. XOR is a very very cheap operation. The CPU can actually do it faster than an addition operation. COmpression is a bit CPU intensive, but you will more than make it up in the time saved during IO, even on low latency/high bandwidth networks.


naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692


thanks for the explanation buddy

Am i on the right track ?

Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2383
    
  28

No, what you are doing is compressing the 2 images into jpg, and then doing a delta on the compressed bytes, and then recompressing the delta. This won't help you

Don't do this . because doing ImageIO.write applied jpeg compression on the image



You need to do something like this

I am pretty sure this will work, but to be honest, all the image manipulation work that I had done was in C++, so I'm not very familiar with the Java API. Basically, what you want to do is get the byte array from the raster image.

Also, I would ditch using the array list. It's unnecessary overhead. If you get the raster image from both images, and both images have the same width, height and colors, then the size of both raster byte arrays will be same. For the delta, you can just create a byte array that has the same size as the other 2 byte arrays.
naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692


Oh ..thanks buddy you are so helpful
Ulf Dittmer
Marshal

Joined: Mar 22, 2005
Posts: 42031
    
  64
naved momin,

please stop your habit of quoting the entire post you're replying to every single time. It makes threads unnecessarily hard to read, and contributes nothing to understanding. Quoting is for excerpting short, relevant extracts of a post that you intend to address specifically. It's especially pointless to quote entire posts that directly precede your post.


Ping & DNS - my free Android networking tools app
naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692

Jayesh A Lalwani wrote:
You need to do something like this


the Javadoc says Currently, the Java 2D(tm) API image classes use TYPE_BYTE, TYPE_USHORT, TYPE_INT, TYPE_SHORT, TYPE_FLOAT, and TYPE_DOUBLE DataBuffers to store image data.
so when i retrieve the data from Raster Image it gives me int[] instead of byte[], so i can make byte[] from int[] like this But i m not getting the right results although the time require to send that byte[] has gradually fall down from 148ms to some 15-20ms

on client side i m doing this

For now i m not trying the exor operation and just experimenting with byte[] if this is successful then i will move to xor operation , but i am not getting the desired result , what is happening is that at client side i m getting -1 as a width of a image that means ImageIcon has not been constructed properly from the byte[]...can you help ?
naved momin
Ranch Hand

Joined: Jul 03, 2011
Posts: 692

naved momin wrote:

I just realize that i m reading an int so logically i m reading total 4 bytes (int 32 bytes & 1 byte consist of 8bits) so this code is completely wrong can any one has a work around for this problem please ?
 
GeeCON Prague 2014
 
subject: programatically reducing size of BufferedImage