0

I'm sending a Bitmap using Socket where Client is my .apk and Server is a Delphi executable.

The Bitmap is sent with success, but when is received on Server, Bitmap is empty with 0KB of size.

So, i want any suggestion or solution if possible, for solve this trouble.

Here is my code until now:

Android (client)

public class MainActivity extends Activity {

    Socket clientSocket;

    private static final int SERVERPORT = 60;
    private static final String SERVER_IP = "192.168.25.227";

    byte[] tmpbytes = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new ClientThread()).start();

    }

        public Bitmap takeScreenshot() {

           View rootView = findViewById(android.R.id.content).getRootView();
           rootView.setDrawingCacheEnabled(true);
           return rootView.getDrawingCache();

        }

        public void getBytes() throws IOException {

            try
            {

            Bitmap bmp = takeScreenshot();

            int bytes = bmp.getByteCount();
            ByteBuffer buffer = ByteBuffer.allocate(bytes); 
            bmp.copyPixelsToBuffer(buffer); 

            byte[] array = buffer.array(); 
            int start=0;
            int len=array.length;
            if (len < 0)
            throw new IllegalArgumentException("Negative length not allowed");
            if (start < 0 || start >= array.length)
            throw new IndexOutOfBoundsException("Out of bounds: " + start);

            OutputStream out = clientSocket.getOutputStream(); 
            DataOutputStream dos = new DataOutputStream(out);

            dos.writeInt(len);
            if (len > 0) {
            dos.write(array, start, len);
            }



          }

            catch (UnknownHostException e) {
                //System.out.println(e.toString());
            } 

            catch (IOException e) {
                //System.out.println(e.toString());
            } 

            catch (Exception e1) {
                //Log.e("clients", e1.toString());
                //Toast.makeText(MainActivity.this, e1.toString(), Toast.LENGTH_LONG).show();
                System.out.println(e1.toString());
            }

        }

        class ClientThread implements Runnable { 

            @Override
            public void run() {

                try {

                    InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

                    clientSocket = new Socket(serverAddr, SERVERPORT);

                    //new Thread(new CommsThread()).start();

                    Thread.sleep(1000);

                    getBytes();

                } catch (Exception e1) {
                    //Log.e("clients", e1.toString());
                    //Toast.makeText(MainActivity.this, e1.toString(), Toast.LENGTH_LONG).show();
                    System.out.println(e1.toString());
                } 

            }
        }

}

Delphi (server)

var
 Form1: TForm1;

stSize: integer;   
Stream: TMemoryStream; 
bmp: TBitmap; 
FSize: Integer;
writing: Boolean;

procedure TForm1.FormCreate(Sender: TObject);
begin
Stream:= TMemoryStream.Create;
writing:= False;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  BytesReceived: Longint;
  CopyBuffer: Pointer; { buffer for copying }
  ChunkSize: Integer;
  TempSize: Integer;
const
  MaxChunkSize: Longint = 8192; { copy in 8K chunks }
begin

  If FSize=0 then
  begin
    If Socket.ReceiveLength>SizeOf(TempSize) then
    begin
      Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
      Stream.SetSize(TempSize);
      FSize:= TempSize //Threadsafe code!
    End;
  End;

  If (FSize>0) and not(writing) then
  begin
    GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
    writing:= True;
    While Socket.ReceiveLength>0 do
    Begin
      ChunkSize:= Socket.ReceiveLength;
      If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
      BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
      Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
      Dec(FSize,BytesReceived);
    End;
  end;

  If FSize=0 then begin

  Stream.Position := 0;
  bmp:=TBitmap.Create; 
  bmp.LoadFromStream(Stream); 
  Image1.Picture.Graphic := bmp; 
  Stream.SetSize(0);
  bmp.Free;
  FSize:= 0;
end;

FreeMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
Writing:= False;
end;

:

after suggestion of Remy Lebeau, my changes done still dont't works :-(

Delphi

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  BytesReceived: Longint;
  CopyBuffer: Pointer;
  ChunkSize: Integer;
  TempSize: Integer;
const
  MaxChunkSize: Longint = 8192;
begin

  If FSize=0 then
  begin
    If Socket.ReceiveLength>SizeOf(TempSize) then
    begin
      Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
      TempSize := ntohl(TempSize); // Changed to ntohl
      Stream.SetSize(TempSize);
      FSize:= TempSize
    End;
  End;

  If (FSize>0) and not(writing) then
  begin
    GetMem(CopyBuffer, MaxChunkSize);
    writing:= True;
    While Socket.ReceiveLength>0 do
    Begin
      ChunkSize:= Socket.ReceiveLength;
      If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
      BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
      Stream.Write(CopyBuffer^, BytesReceived);
      Dec(FSize,BytesReceived);
    End;
  end;

  If FSize=0 then begin

  Stream.Position := 0;
  png:=TPngImage.Create;  // Changed to TPNGImage here
  png.LoadFromStream(Stream);
  Image1.Picture.Assing(png);
  Stream.SetSize(0);
  png.Free;
  FSize:= 0;
end;

FreeMem(CopyBuffer, MaxChunkSize);
Writing:= False;
end;

Android

public void getBytes() throws IOException {

            try
            {

            Bitmap bmp = takeScreenshot();

            ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
            bmp.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos); 
            byte[] array = bos.toByteArray();
            OutputStream out = socket.getOutputStream(); 
            DataOutputStream dos = new DataOutputStream(out);
            dos.writeInt(array.length);
            dos.write(array, 0, array.length);

          }

            catch (UnknownHostException e) {
                //System.out.println(e.toString());
            } 

            catch (IOException e) {
                //System.out.println(e.toString());
            } 

            catch (Exception e1) {
                //Log.e("clients", e1.toString());
                //Toast.makeText(MainActivity.this, e1.toString(), Toast.LENGTH_LONG).show();
                System.out.println(e1.toString());
            }

        }
  • http://stackoverflow.com/questions/39041568/android-trouble-to-send-bitmap-byte-array-over-socket – greenapps Aug 20 '16 at 17:19
  • And again you have not took the time to give a description of what your code should do and really does. You are just dumping a lot of code. Already the third time. – greenapps Aug 20 '16 at 17:22
  • 1
    `I'm sending a Bitmap using Socket`. No. You are sending `len` bytes of a byte array. You filled the byte array with pixels from a bitmap. On server side you should receive `len` bytes. Now what did you receive on the server? You are complaining that the bitmap has size 0. But a bitmap is only constructed afterwards from the received bytes so at first irrelevant. Now tell exactly how many bytes you send and how many you received. Start with some basic debugging. – greenapps Aug 20 '16 at 17:27
  • @greenapps, in server side: `Socket.ReceiveLength` receives a size of 4.` –  Aug 20 '16 at 18:00
  • I see you still haven't taken my critical input from the last time you asked. It's not even advise. Your Delphi code *will not work* when you have more than one client connected. And you've even added more to the mess. – Jerry Dodge Aug 20 '16 at 18:06
  • @JerryDodge, but i'm testing only with one client connected on moment :-). But in this case, if don't works with one client also not will works with more of one. –  Aug 20 '16 at 18:08
  • It's a matter of coding practice. The more you do it the *right* way in the first place, the easier it will be for you to get things working in the future. The more you practice poor coding, the more you'll make those mistakes in the future. It's already poor practice to use global variables at all in the first place (they should at least be part of the form instance). It's even worse that they should be associated with a specific client session. – Jerry Dodge Aug 20 '16 at 18:23
  • @greenapps, `No. You are sending len bytes of a byte array` this is wrong? –  Aug 20 '16 at 18:36

1 Answers1

2

There are many problems with your code.

You are not paying attention to the return value of ReceiveBuf(). It returns the number of bytes actually read, which can be fewer bytes than you requested, or it can return 0 on disconnect, or -1 on error (especially if you are using the server in non-blocking mode). You need to handle those cases. You need to loop the reading of TempSize. And you need to stop looping when you have received exactly FSize number of bytes when reading the pixels.

You are not taking endian into account. DataOutputStream.writeInt() writes the integer bytes in big endian byte order. Delphi on Windows is little endian instead. Your call to ReceiveBuf(TempSize,SizeOf(TempSize)) is reading the integer bytes as-is, so TempSize will be in big endian . You need to convert the value to little endian before you use it. You can use ntohl() for that:

TempSize := ntohl(TempSize);

Your client is only sending the raw pixel data, but TBitmap.LoadFrom...() requires a complete .bmp file, including BITMAPFILEHEADER and BITMAPINFOHEADER headers (see Bitmap Storage) that describe the bitmap and its pixels. You need to send those headers, or at least populate your Stream with them before reading the pixels into it.

However, Android doesn't have good support for the bmp format, so you would be better off using Bitmap.compress() to extract the bitmap data as a PNG instead, and then use a TPNGImage on the Delphi side to load it.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    Thank you very much by you answer :-). You could edit your answer with a code example in Delphi (server side) please? –  Aug 20 '16 at 23:21
  • I have made some changes in client and server (following your suggestions), but still don't works. I edited my question for show it. –  Aug 21 '16 at 00:18
  • @Sormanne you need to call `ntohl()` **after** reading `TempSize`, not **before**. And you didn't loop the reading, like I said. And you are still not handling the return value of `ReceiveBuf()` correct, or looping correctly in general. – Remy Lebeau Aug 21 '16 at 00:41
  • I change it, but without success until now and comes [this error message](http://image.prntscr.com/image/bac407b7b32d4de1b6fb18f0a0383e02.png). You could provide a code example in your answer please? –  Aug 21 '16 at 00:46
  • You want too much things at the same time. I had already said that you should check if the amount of bytes received is equal to the amount of bytes send. But you are mentioning nothing. At this moment you should start to compare the sent array.length with the received TempSize. Now what are the values? Do some basic debugging! – greenapps Aug 21 '16 at 09:02
  • @greenapps, I already said that `Socket.ReceiveLength` in server side have a size of 4. And TempSize already is initialized with a strange value > 4 :-( before this line `If Socket.ReceiveLength>SizeOf(TempSize) then` –  Aug 21 '16 at 11:51
  • @RemyLebeau, give me a code example of your suggestion about server side please, that client side i will try make alone if error still persist. –  Aug 21 '16 at 11:58
  • `I already said that`. No you still not said how many bytes are send. Or how much should be send. Or the value or array.length. Incredible that you twice are not able to give the right info. Incredible that you do not see what some basic debugging is. You should compare that what is send with that what is received. Now start to tell the values. – greenapps Aug 21 '16 at 17:58
  • @Sormanne I haven't had time to write new code for your issue. But have a look at examples I have posted to earlier questions, it will give you some ideas of what is involved. Such as [Error message: “Bitmap Image is not valid” on received from Socket](http://stackoverflow.com/questions/20292986) (particularly the "Common" functions). – Remy Lebeau Aug 21 '16 at 18:17
  • @RemyLebeau, i will wait by your suggestion of Delphi code for this my question :-) –  Aug 21 '16 at 22:59
  • Yes! Put the pressure on! Just sit down. Somebody else will do the work. Not even some basic debugging is done by you. What is it that you cannot give some decent answers on amounts and values to be send and received. Just sitdow. – greenapps Aug 22 '16 at 07:25
  • @greenapps and RemyLebeau, thank you very much by your suggestions and help, i already solved this trouble :-) [see](http://image.prntscr.com/image/61f84cec15374470bb41c616356c40e3.png) –  Aug 22 '16 at 18:46