0

I have a Client-Server system where server is written in cpp and the client is written is Java (Android application).

The server reads an image from a local directory as an ifstream using read method. The reading process is done inside a loop, where the program reads parts of the image every time. Every time a part of the image is read, it's sent over a socket to the client that collects all the piece inside a byteBuffer and when all the bytes of the image are transfered to the client, the client attempts to turn that array of bytes (after using byteBuffer.array() method) into a Bitmap. This is where the problem begins - I've tried a few methods but it seems that I'm unable to turn this array of bytes into a Bitmap.

From what I understood, this byte array is probably a raw representation of the image, which can't be decodded using methods like BitmapFactory.decodeByteArray() since it wasn't encoded in the first place.

Ultimately, my question is - how can I proccess this array of bytes so that I'll be able to set the image as a source to an ImageView?

Note: I've already made sure that all the data is sent over the socket correctly and the pieces are collected in the right order.

Client code:

    byte[] image_bytes
    byte[] response_bytes;
    private void receive_image ( final String protocol, final int image_size, final int buffer_size)
    {
        if (image_size <= 0 || buffer_size <= 0)
            return;

        Thread image_receiver = new Thread(new Runnable() {
            @Override
            public void run() {
                ByteBuffer byteBuffer = ByteBuffer.allocate(image_size);
                byte[] buffer = new byte[buffer_size];
                int bytesReadSum = 0;
                try {
                    while (bytesReadSum != image_size) {
                        activeReader.read(buffer);
                        String message = new String(buffer);
                        if (TextUtils.substring(message, 0, 5len_of_protocol_number).equals(protocol)) {
                            int bytesToRead = Integer.parseInt(TextUtils.substring(message, 
                                    len_of_protocol_number, 
                                    len_of_protocol_number + len_of_data_len));

                            byteBuffer.put(Arrays.copyOfRange(buffer, 
                                    len_of_protocol_number + len_of_data_len, 
                                    bytesToRead + len_of_protocol_number + len_of_data_len));
                            bytesReadSum += bytesToRead;
                        } else {
                            response_bytes = null;
                            break;
                        }
                    }
                    if (bytesReadSum == image_size) {
                        image_bytes = byteBuffer.array();
                        if (image_bytes.length > 0)
                            response_bytes = image_bytes;
                        else
                            response_bytes = null;
                    }
                } catch (IOException e) {
                    response_bytes = null;
                }
            }
        });
        image_receiver.start();
        try {
            image_receiver.join();
        } catch (InterruptedException e) {
            response_bytes = null;
        }

        if (response_bytes != null) 
        {    
            final ImageView imageIV = (ImageView) findViewById(R.id.imageIV);
            File image_file = new File(Environment.getExternalStorageDirectory(), "image_file_jpg");
            try 
            {
                FileOutputStream stream = new FileOutputStream(image_file);
                stream.write(image_bytes);
            } 
            catch (FileNotFoundException e) 
            {
                e.printStackTrace();
            } 
            catch (IOException e) 
            {
                e.printStackTrace();
            }
            //Here the method returns null
            final Bitmap image_bitmap = BitmapFactory.decodeFile(image_file.getAbsolutePath());
            main.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    imageIV.setImageBitmap(image_bitmap);
                    imageIV.invalidate();
                }
            }
        }
    }
  • What kind of image is sent? Jpg files and png files should be no problem. As a test save the bytearray to file and check if your Android apps can display the file. Same file size? Is bytearray.length the same as file size sent? – greenapps Mar 21 '17 at 13:02
  • `I've already made sure that all the data is sent over the socket correctly`. Please tell how you did that. – greenapps Mar 21 '17 at 13:05
  • `how can I proccess this array of bytes`. You do not need to process or convert the bytes. – greenapps Mar 21 '17 at 13:07
  • `client that collects all the piece inside a byteBuffer`. Why not show your code? – greenapps Mar 21 '17 at 13:09
  • `Setting raw data/byte array as a source of an ImageView`. You mean "a byte array, containing a jpg file, as source for a bitmap". – greenapps Mar 21 '17 at 13:09
  • `which can't be decodded using methods like BitmapFactory.decodeByteArray() since it wasn't encoded in the first place.`. If encoded as jpg or png it is ok. – greenapps Mar 21 '17 at 13:13
  • You did not tell the result of `BitmapFactory.decodeByteArray()` . What did it return? What is the file size of the image? And what it's resolution? – greenapps Mar 21 '17 at 13:14
  • @greenapps 1.The type of the image is JPG. 2. I've checked the beginning of the array of bytes and its end and they both were similar to the onces I saw on the server side before sending. 3. So if I don't need to process or convert the bytes, what am I supposed to do to set these bytes as an image of ImageView? 4. It involves some processing according to my client-server communication protocol. 5. Yes, you could say that. 7. It always returns null. The size of the image is 108 KB (110,603 bytes). height: 720, width: 1250, horizontal resolution: 96 dpi, vertical resolution: 96 dpi – Daniel Goman Mar 21 '17 at 13:27
  • if BitmapFactory.decodeByteArray() can't decode it means that the bytes you're receiving are not good, the way you're receiving those bytes is confusing (I do remember you from the other question :P) – lelloman Mar 21 '17 at 13:38
  • You cannot say at forehand that the bytes are no good. If the image resolution is too big it will return null too. @lelloman – greenapps Mar 21 '17 at 13:41
  • I'm saying it because I saw the code you're using to retrieve them, where did you read that it will return null if the resolution is too high? – lelloman Mar 21 '17 at 13:44
  • `horizontal resolution: 96 dpi, vertical resolution: 96 dpi` ??? – greenapps Mar 21 '17 at 13:44
  • @lelloman, the way the bytes are retrieved is a bit vague, but I rechecked and I'm 99.99% sure that this part is ok. – Daniel Goman Mar 21 '17 at 13:45
  • `where did you read that it will return null if the resolution is too high?`. I experimented it. And you can read it every week again on this site. And you never saw my code ;-). @lelloman – greenapps Mar 21 '17 at 13:47
  • @greenapps how can I find out the ideal resolution on the client side? – Daniel Goman Mar 21 '17 at 13:47
  • Just try to transfer a very small image as test. Say 150x200. WxH. – greenapps Mar 21 '17 at 13:48
  • @greenaps http://prnt.sc/emo46r these are the properties of my image – Daniel Goman Mar 21 '17 at 13:48
  • That 96x96 is nonsense. Images have no dpi. – greenapps Mar 21 '17 at 13:50
  • @greenapps sorry I thought I was writing to Daniel xD, but decodeByteArary() returns null if the image is too big doesnt sound right, what is too big? if it's too big wouldn't it throw an out of memory? – lelloman Mar 21 '17 at 13:51
  • Yes it would throw an out of memory but that is catched within decodeByteArray(). Upon such a catch null is returned. We consider this as a very bad implementation. – greenapps Mar 21 '17 at 13:53
  • @lelloman, I'm not quite sure how it works, though it makes sense that if the image is too big then some of the data of the image won't be included in the bitmap of the image and hence will be lost. – Daniel Goman Mar 21 '17 at 13:53
  • @greenapps I've just tried to send a 150x200 image, 5,865 bytes. The result is the same - null is return from BitmapFactory.decodeByteArray() method. – Daniel Goman Mar 21 '17 at 13:55
  • Well show your code. Isnt it time? And did you save those bytes to file meanwhile? I suggested you to do so long ago. Just first check if you can transfer the bytes of a file unharmed. – greenapps Mar 21 '17 at 13:56
  • The thing is, as lelloman said, my code is somewhat confusing because it has some actions related to my protocol – Daniel Goman Mar 21 '17 at 13:58
  • Why do reluctant posting code? You want help isnt it? – greenapps Mar 21 '17 at 13:59
  • [see this](http://stackoverflow.com/questions/42913041/turning-byte-array-into-bitmap), I'm also digging into the code of decodeByteArray() both in java and the native method but I can't find where out of memory is handled – lelloman Mar 21 '17 at 13:59
  • @greenapps haha well, you got me :D the link sent by lelloman is correct, you can see my client side code there – Daniel Goman Mar 21 '17 at 14:00
  • That is terrible code. I will not look further. Please save the received byte array to file. Then you know if you got the right data. I wait until you report about the results. – greenapps Mar 21 '17 at 16:08
  • @greenapps I've already attempted to save the bytes into a file. Once again, the file returned is null. – Daniel Goman Mar 21 '17 at 16:17
  • The file returned is null? What would that mean? Are you not able to save that byte array to file? Why do you say 'once again'? This is the first time. – greenapps Mar 21 '17 at 16:19
  • By "once again" I refer to the event of getting a null. What I meant to say is that after I wrote into the file I attempted to decode it into a bitmap using BitmapFactory.decodeFile() method, and it returned null. I'll add the code I used in the question. – Daniel Goman Mar 21 '17 at 16:32
  • In that link you post impossible code. Even there i already reacted. You are sending segments you say. And you think that your client can read segment by segment. This does not come true as tcp/ip has its own buffers and delivers chuncks of bytes in unpredictable amounts. So throw away your server code. Just send all bytes of the file in a loop chunck by chunk. And on client side just read all the bytes into one byte array. Do away with that segmented protocol. There is no reason for it. – greenapps Mar 21 '17 at 16:33
  • You should open that file in the Gallery app or with another image viewer just to see if they can display it. I suggested this before. Strange that you did not do this simple check. You could also transfer that file to your pc and see if you can display it there. There are so many checks possible... – greenapps Mar 21 '17 at 16:34
  • @greenapps Actually, I checked it again now and it appears that an image has been saved on the device, but the device is having troubles recognizing it and displaying it. Screen shots: http://prnt.sc/emqirh http://prnt.sc/emqis9 – Daniel Goman Mar 21 '17 at 16:44
  • Maybe not alone your device. Transfer the file to your pc and look there. 108KB looks ok but says nothing. You should check if it is exactly the original file size. – greenapps Mar 21 '17 at 16:48
  • You should close() the FileOutputStream when done. – greenapps Mar 21 '17 at 16:49
  • `byte[] image_bytes = byteBuffer.array();`. That `image_bytes` array cannot be the same as the one you use in `stream.write(image_bytes);`. So what are you doing? – greenapps Mar 21 '17 at 16:58
  • I added some code into the function to be able to display it here with more ease, I corrected it now. – Daniel Goman Mar 21 '17 at 17:07
  • @greenapps I've transfered the image file to my computer and when I attempted to open it, it said "we can't open this file". I've also tried a few image formats like jpg, png and jpeg but no success. I assume that this means that the file is corrupted, am I right? – Daniel Goman Mar 21 '17 at 17:31
  • My god.. what a question. I means that your code to transfer a file is corrupt. Well i said that before. Send the file in a normal way: be glad, that can be done in five lines of code. You can throw away your segmented code then. – greenapps Mar 21 '17 at 17:54
  • @greenapps I feel a pretty stupid for not checking well the bytes. It appears that most of the bytes read from the socket don't match the ones that were sent. There are many NULL, -52 and -85 bytes, which don't appear in the data on the server side. Could you possibly have a clue as to why this is happening? – Daniel Goman Mar 21 '17 at 17:54
  • I already told you several times to throw away your segmented code. It does not work. – greenapps Mar 21 '17 at 17:55
  • @greenapps I'm stubborn about this way because it seems like I need to do it this way in order for something else in the protocol to work. I'll see what I can do with it. – Daniel Goman Mar 21 '17 at 17:56
  • The thing that bother me is that it doesn't make sense that adding a few bytes of information at the beginning of the data corrupts most of the data. Could such a thing actually happen? – Daniel Goman Mar 21 '17 at 17:57
  • Even if the segmented server was coded correct then still your c!ients segmented code is wrong. I already told you why. – greenapps Mar 21 '17 at 17:58
  • OK, I think I'll change some stuff here and there. Thanks a lot for your time and help, and sorry for being sort of a burden :D – Daniel Goman Mar 21 '17 at 18:36

2 Answers2

0

Whenever you exchange data between two machines of different architectures via sockets you need to know the Endianness (big-endian/little-endian) of each machine. If different, you will need to convert bytes to correct the data. Perhaps that's your issue. Here's a link with sample code: Converting Little Endian to Big Endian. You should be able to easily find more articles explaining the concept.

Community
  • 1
  • 1
Gjchoza
  • 187
  • 1
  • 7
  • Thank you for your answer. honestly, I'm not really familiar with the Endianness subject, how do I check the Endianness of each machine? – Daniel Goman Mar 22 '17 at 14:03
  • Find out what machine/operating system the server is and you should be able to determine it. Here's another link that may help: http://searchnetworking.techtarget.com/definition/big-endian-and-little-endian – Gjchoza Mar 22 '17 at 14:07
0

It turned out that something was wrong with my sending protocol. After patching it up a bit it actually worked. Thanks for the help.