Solved

How to covert a Bitmap to an array of...

Posted on 1998-12-03
21
551 Views
Last Modified: 2013-12-03
How I can covert a Bitmap to an array of integer or to an array of string.
And How I can convert this array to a Bitmap ?

Thanks.
0
Comment
Question by:borgo
  • 9
  • 8
  • 4
21 Comments
 
LVL 20

Expert Comment

by:Madshi
ID: 1349137
borgo,

with TBitmap.ScanLine property you get access to the rare pixel data. Of course that is not so easy, because you have to look at the color format yourself.
E.g., for 32 bit bitmaps you'll have to read/write width*4 bytes from/to the scanLine property. Then you'll have to write a little loop that read/writes all (height) lines of the bitmap.

Look at this example:

procedure TForm1.Button1Click(Sender: TObject);
var
  x,y : integer;
  BitMap : TBitMap;
  P : PByteArray;
begin
  BitMap := TBitMap.create;
  try
    BitMap.LoadFromFile('..\Images\Splash\256color\factory.bmp');
    for y := 0 to BitMap.height -1 do
    begin
      P := BitMap.ScanLine[y];
      for x := 0 to BitMap.width -1 do
        P[x] := y;
    end;
  canvas.draw(0,0,BitMap);
  finally
    BitMap.free;
  end;
end;

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349138
P.S: If you like pure winAPI more, look at CreateDIBSection, SetDIBits, ...
0
 

Author Comment

by:borgo
ID: 1349139
The example is from the Delphi Help. I have just read it.
The problem is: I have a bitmap. I want to convert it to an array of intger (or string). Then I have to reverse the process.
ScanLine proprerty is a read only property.
Please con you write me a loop example (Delphi4) to do it ?

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349140
borgo,

yes, the ScanLine property is a readonly property. But that does not mean, that you can't use it to change the bitmap pixels!
It is a readonly property because it gives you a pointer to the bitmap buffer. It makes no sense to change the pointer to the bitmap buffer, but nevertheless you can use the readonly pointer to write to the read&write bitmap pixel buffer.
You're right, the example is from the Delphi help. It's just because it fits your needs. Please look at it a little bit close again! It loads a 256 color bitmap, then changes each and every byte of it, then displays the result of this operation. Please compile it and look at the results!

Regards, Madshi.
0
 
LVL 3

Accepted Solution

by:
williams2 earned 300 total points
ID: 1349141
Hi Madshi.

Unfotunately you have done quite a mistake, forgetting that the scanline property reads bytes, and that bitmaps may variate from 256 colors to 32 bit colors (4 bytes pr. pixel).

You also forgot to save the pallete. If you are to use 256 colors, this is important. So.. Maybe your example works in your case above, but else it doesn't work at all!

The following example does the thing you need:

procedure TForm1.Button1Click(Sender: TObject);
Const
  ByteStf = '[0]';
var
  Stream1,Stream2: TMemoryStream;
  S,T: String;
  C: Char;
  Size,i: Integer;
  ByteStuffing: Integer;
  Bitmap: TBitmap;
begin

  // Read into String
  Bitmap:= TBitmap.Create;
  If OpenPictureDialog1.Execute then
  begin
    Bitmap.LoadFromFile(OpenPictureDialog1.FileName);
    Stream1:= TMemoryStream.Create;
    Bitmap.SaveToStream(Stream1);
    Stream1.Position:= 0;
    Size:= Stream1.Size;
    S:= IntToStr(Size)+' ';
    While Stream1.Position<Size do
    begin
      Stream1.Read(C,1);
      if C=#0 then S:= S+ByteStf else S:=S+C;
    End;
    Stream1.Clear;
    Stream1.free;

    // ...

    //Write to string - Fist get size
    i:= 1;
    While S[i]<>' ' do
    begin
      T:= T+S[i];
      inc(i);
    End;
    inc(i);
    Size:= StrToInt(T);
    Stream2:= TMemoryStream.Create;
    Stream2.SetSize(Size);

    //Get the rest
    ByteStuffing:= 0;
    While Stream2.Position<Size do
    begin
      C:= S[i];
      // Test the bytestuffing thing..
      If C='[' then ByteStuffing:= 1 else
      If (C='0') AND (ByteStuffing = 1) then ByteStuffing:= 2 else
      If (C=']') AND (ByteStuffing = 2) then
      begin
        ByteStuffing:= 0;
        Stream2.Position := Stream2.Position - 2;
        C:= #0;
      End;
      Stream2.Write(C,1);
      inc(i);
    End;
    Stream2.Position:= 0;

    Image1.Picture.BitMap.LoadFromStream(Stream2);

    Stream2.clear;
    Stream2.free
  End;
end;

But I must say, I cannot figure out, why you want to have it in a string. :-)

Cheers
/Williams
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349142
williams2,

of course you know, that this stream method is very very very slow!!! AND you get the bitmap file header and all this stuff. So you don't know which bits/bytes you have to read/write in order to read/write specific pixels.
I don't think that is what borgo needs, right borgo?
I really prefer the ScanLine method. It is much faster and gives you only the pixels. Of course you have to look at the palette yourself (that means if you're using 16 or 256 color bitmaps).

I think it depends on for what borgo needs this all.

Regards, Madshi.
0
 
LVL 3

Expert Comment

by:williams2
ID: 1349143
Madshi

Yes, that is correct, I am saving the headers within the bitmap and I'm fully aware of that. Now he also asked how to convert it to a string . You might be aware of the fact that the pallette is always saved within the header, or you might go read the SaveToStream method in Graphics.pas.

You say it is slow, maybe it is, but it is the answer to the question. But as you say, it depends on the purpose.

At least you should be sure about the width, as I mentioned before. If you hsve a 24 bit image you'll only have copied a third of the original bitmap.

Hmm.. I'm working on tomething, that might be able to solve this problem in generel.

Regards
/Williams
0
 

Author Comment

by:borgo
ID: 1349144
Williams2: Your code do what I have tryed to do some days ago.
Thank you very much.
I'm coding an application which sends a bmp between an UDP connection. I think to convert the bmp in a array of integer (or string) and then to send it. Do you think I'm wrong ? What do you think is the best way to do it ?
(You will get your points.)
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349145
borgo,

if you had written in the beginning for what purpose you need it. I thought you wanted to manipulate some pixels in a fast way...

Ok, now it's clear:
You should save it to a memoryStream. The memoryStream object has a memory property that is a pointer to the data buffer.

function BitmapToStr(bmp: TBitmap) : string;
var ms : TMemoryStream;
begin
  ms:=TMemoryStream;
  try
    bmp.WriteToStream(ms);
    // now you can access all the bitmap data through memoryStream's memory property. E.g. converting to a string:
    setLength(result,ms.size);
    Move(ms.Memory^,pointer(result)^,ms.size);
    // now you have all the bitmap data in a string.
  finally ms.Free end;
end;

BTW, this code is much much much faster than Williams' code.  :-))    (Sorry, Williams...)

If you really want to convert it to a string, you can use the following code to convert it back to an image:

function StrToBitmap(str: string) : TBitmap;
var ms : TMemoryStream;
begin
  ms:=TMemoryStream.Create;
  try
    ms.size:=length(str);
    Move(pointer(str)^,ms.Memory^,ms.size);
    result:=TBitmap.Create;
    result.loadFromStream(ms);
  finally ms.Free end;
end;

If you want an array of byte, do something like this:
type TAByte  : array [0..maxInt] of byte;
     TPAByte : ^TAByte;
var  abyte   : TPAByte;
abyte:=ms.Memory^;  // Now you can use e.g. abyte^[0] to access the first byte

If you want an array of integer, do something like this:
type TAInteger  : array[0..maxInt shr 2] of integer;
     TPAInteger : ^TAInteger;
var  aInt       : TPAInteger;
aint:=ms.Memory^;  // Now you can use e.g. aint^[0] to access the first byte
// Note, that you now have to transfer (ms.size div 4) integers... So I wouldn't choose this method...

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349146
P.S: borgo, give the points to Williams, if you like his answer more than mine. (Otherwise of course to me...)    :-)))
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 3

Expert Comment

by:williams2
ID: 1349147
To Madshi:
I will just say, that the purpose of your example was right, but the questions was in some way easy to misunderstand.

To Madshi:
I have allready done this once, where I'll send the whole screen from a server to a client on request.
I think you will appreciate the following example, since byte or char stuffing is both slow and oldfashioned.
I din't use UDP, and I will not recommend using it, as it is unreliable and mostly used for messageservices and server notifications.

In the following example, you should do the following things:
Server:
create New application
Add a OnCreate event procedure from the form object, then replace unit 1 with Section A.
Client:
You do the same here as with the server, just replace unit1 with Section B.

Section A:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ScktComp, ExtCtrls, StdCtrls, ExtDlgs;

Const
  //You may set this to False if you would like the whole image!
  STRETCH = True;
  STRETCH_WIDTH = 200;
  STRETCH_HEIGHT = 150;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    ServerSocket1: TServerSocket;
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
  private
    { Private declarations }
    Stream: TMemoryStream;
    procedure SendNextPart(Socket: TCustomWinSocket);
  public
    { Public declarations }
    Timer: TTimer;
    procedure OnTime(Sender: TObject);
    procedure SendScreen(Socket: TCustomWinSocket);
  protected
    Bitmap: TBitmap;
  end;

var
  Form1: TForm1;


implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Bitmap:= TBitmap.Create;
  if STRETCH then
  begin
    Bitmap.Width:= STRETCH_WIDTH;
    Bitmap.height:= STRETCH_HEIGHT;
  End else
  begin
    Bitmap.Width:= Screen.Width;
    Bitmap.Height:= Screen.Height;
  End;
  Timer:= TTimer.Create(Self);
  Timer.Interval:= 1000;
  Timer.OnTimer:= OnTime;
  Timer.Enabled:= True;
  ServerSocket1:= TServerSocket.Create(Self);
  With ServerSocket1 do
  begin
    Port:= 2500;
    Active:= True;
    ServerType:= stNonBlocking;
    OnClientRead:= ServerSocket1ClientRead;
  End;
  Stream:= TMemoryStream.Create;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  S: String;
Begin
  S:= Socket.ReceiveText;
  If S='Get me the screen' then SendScreen(Socket) else
  If S='Send next' then SendNextPart(Socket) else
  If S='Done' then Socket.Close;
End;

procedure TForm1.SendScreen(Socket: TCustomWinSocket);
var
  Size: Integer;
Begin
  Bitmap.SaveToStream(Stream);
  Size:= Stream.Size;
  Stream.Position:= 0;
  Socket.SendBuf(Size,SizeOf(Size));
End;

procedure TForm1.SendNextPart(Socket: TCustomWinSocket);
const
  MaxChunkSize = 8192; { copy in 8K chunks }
var
  ChunkSize: Integer;
  CopyBuffer: Array[0..MaxChunkSize] of Byte;
Begin
  Chunksize:= Stream.Size-Stream.Position;
  If ChunkSize>0 then
  begin
    If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
    Stream.Read(CopyBuffer,ChunkSize);
    Socket.SendBuf(CopyBuffer,ChunkSize);
  End else
    Stream.Clear; //The final
End;

procedure TForm1.OnTime(Sender: TObject);
var
  dwRop: DWord;
  DC: hDC;
begin
  dwRop:= SRCCOPY;
  DC:= GetDC(0);
  If STRETCH then
    StretchBlt(
      Bitmap.Canvas.Handle, // handle to destination device context
      0, // x-coordinate of destination rectangle's upper-left corner
      0, // y-coordinate of destination rectangle's upper-left corner
      Bitmap.Width, // width of destination rectangle
      Bitmap.Height, // height of destination rectangle
      DC, // handle to source device context
      0, // x-coordinate of source rectangle's upper-left corner
      0, // y-coordinate of source rectangle's upper-left corner
      Screen.Width,      // width of source rectangle
      Screen.Height,      // height of source rectangle
      dwRop        // raster operation code (See below)
    )
  else
    BitBlt(
      Bitmap.Canvas.Handle, // handle to destination device context
      0, // x-coordinate of destination rectangle's upper-left corner
      0, // y-coordinate of destination rectangle's upper-left corner
      Bitmap.Width, // width of destination rectangle
      Bitmap.Height, // height of destination rectangle
      DC, // handle to source device context
      0, // x-coordinate of source rectangle's upper-left corner
      0, // y-coordinate of source rectangle's upper-left corner
      dwRop        // raster operation code (See below)
    );
  ReleaseDC(0,DC)
{
BLACKNESS Fills the destination rectangle using the color associated with
index 0 in the physical palette. (This color is black for the
                default physical palette.)
DSTINVERT Inverts the destination rectangle.
MERGECOPY Merges the colors of the source rectangle with the specified
pattern by using the Boolean AND operator.
MERGEPAINT Merges the colors of the inverted source rectangle with the
colors of the destination rectangle by using the Boolean OR
                operator.
NOTSRCCOPY Copies the inverted source rectangle to the destination.
NOTSRCERASE Combines the colors of the source and destination rectangles
by using the Boolean OR operator and then inverts the resultant
                color.
PATCOPY Copies the specified pattern into the destination bitmap.
PATINVERT Combines the colors of the specified pattern with the colors of
the destination rectangle by using the Boolean XOR operator.
PATPAINT Combines the colors of the pattern with the colors of the
inverted source rectangle by using the Boolean OR operator. The
                result of this operation is combined with the colors of the
                destination rectangle by using the Boolean OR operator.
SRCAND Combines the colors of the source and destination rectangles
by using the Boolean AND operator.
SRCCOPY Copies the source rectangle directly to the destination
rectangle.
SRCERASE Combines the inverted colors of the destination rectangle with
the colors of the source rectangle by using the Boolean AND operator.
SRCINVERT Combines the colors of the source and destination rectangles
by using the Boolean XOR operator.
SRCPAINT Combines the colors of the source and destination rectangles by
using the Boolean OR operator.
WHITENESS Fills the destination rectangle using the color associated with
index 1 in the physical palette. (This color is white for the
                default physical palette.)
}
End;


end.


Section B:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ScktComp, StdCtrls, ExtCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    ProgressBar: TProgressBar;
    Button1: TButton;
    Button2: TButton;
    ClientSocket1: TClientSocket;
    Image1: TImage;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure Button2Click(Sender: TObject);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocket1Disconnect(Sender: TObject;
      Socket: TCustomWinSocket);

  private
    Stream: TMemoryStream;
  public
    Procedure UpdateProgressBar;
  protected
    Bitmap: TBitmap;
    Receiving: Boolean;
    FSize: Integer;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Caption:= 'Connecting..';
  ClientSocket1.Open;
end;

procedure TForm1.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Label1.Caption:= 'Connected';
  Receiving:= False;
  FSize:= 0;
end;

procedure TForm1.ClientSocket1Error(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  ShowMessage('Did you startup the server? I cannot find it!');
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  if ClientSocket1.Active then
    ClientSocket1.Socket.SendText('Get me the screen');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Label1:= TLabel.Create(Self);
  Label1.SetBounds(32,72,32,13);
  Label1.Parent:= Self;
  Label1.Caption:= 'Idle..';
  Button1:= TButton.Create(Self);
  Button1.SetBounds(8,8,75,25);
  Button1.Parent:= Self;
  Button1.Caption:= 'Connect';
  Button1.OnClick:= Button1Click;
  Button2:= TButton.Create(Self);
  Button2.SetBounds(8,40,75,25);
  Button2.Parent:= Self;
  Button2.Caption:= 'Get screen';
  Button2.OnClick:= Button2Click;
  ClientSocket1:= TClientSocket.Create(Self);
  With ClientSocket1 do
  begin
    Active := False;
    ClientType := ctNonBlocking;
    Port := 2500;
    Address := '127.0.0.1';
    OnConnect := ClientSocket1Connect;
    OnDisconnect := ClientSocket1Disconnect;
    OnRead := ClientSocket1Read;
    OnError := ClientSocket1Error;
  end;
  Image1:= TImage.Create(Self);
  Image1.SetBounds(100,0,0,0);
  Image1.AutoSize:= true;
  Image1.Parent:= Self;

  Stream:= TMemoryStream.Create;
  ProgressBar:= TProgressBar.Create(Self);
  ProgressBar.Min:= 0;
  ProgressBar.Align:= alBottom;
  ProgressBar.Parent:= Self;
end;

Procedure TForm1.UpdateprogressBar;
Begin
  ProgressBar.Position:= ProgressBar.Max-FSize;
  progressBar.Update;
End;

procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
const
  MaxChunkSize = 8192; { copy in 8K chunks }
var
  BytesReceived: Longint;
  CopyBuffer: Array[0..MaxChunkSize] of Byte; { buffer for copying }
  ChunkSize: Integer;
  TempSize: Integer;
begin
  If FSize=0 then
  begin
    If Socket.ReceiveLength>=SizeOf(TempSize) then
    begin
      Socket.ReceiveBuf(TempSize,SizeOf(TempSize)); //get the size
      Stream.SetSize(TempSize);
      Stream.Position:= 0;
      ProgressBar.Max:= TempSize;
      FSize:= TempSize; //Threadsafe code!
    End;
  End;
  If (FSize>0) and not(Receiving) then
  begin
    Receiving:= 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);
      UpdateProgressBar;
    End;
    //This is called "to Syncronize trasnsmissions"
    Socket.SendText('Send next');
    If FSize=0 then
    begin
      Socket.SendText('Done');
      Stream.Position:= 0;
      Image1.Picture.Bitmap.LoadFromStream(Stream);
      FSize:= 0;
      ProgressBar.Position:= 0;
//      Stream.SetSize(0);
      Stream.Clear;
    End;
    Receiving:= False;
  End;
end;


procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Label1.Caption:= 'Disconnected';
end;

end.

Cheers
Williams
0
 
LVL 3

Expert Comment

by:williams2
ID: 1349148
Correction:
Sorry! Last message ("To Madshi: ") was ment for borgo. :-)

Regards
Williams
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349149
Williams,

your sources look quite nice. Only one suggestion: Why are you not using the memory property of the TMemoryStream? You could save the CopyBuffer...

Regards, Madshi.
0
 
LVL 3

Expert Comment

by:williams2
ID: 1349150
Very simple Madshi:

I'm doing this because I take care of the Delphi structure. When implementing the memory property directly, you are in a potential risc of getting pointer-errors in your application. That is why exceptions were created in the first place.
Maybe you didn't know it, but 72% of most errors using C/C++ are pointer-errors due to the pointerstructure in C, where most things are implemented by reading from or writing to the memory directly. These errors are sometimes VERY difficult to find.

If you'd really like to, I can easily give you an example without using any stream objects at all, but I think that is not why Streams were invented in the first place.

So when I'm posing an example, you will not see me adding things directly to the memory unless it's an important factor to the algorithm or program. So you won't see that either in Delphi's help support or developer support at www.inprise.com .

Regards,
Williams
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349151
If you would be right: Why should Inprise add a memory property?

No no, it is there to be used. And if you use it, your programs will be faster, because you save some memory copy actions. Of course you have to look that you handle it right, otherwise you'll get exceptions, but you can't simply say: "I use no pointers because they're dangerous". No, you can't get around pointers. And if you look into the Delphi original sources, you'll find that the Delphi programmers use pointers all the time.
And you're definetely NOT in a potential risk of getting pointer-errors, if you're using the memory property of TMemoryStream! Look at my last That's nonsense (sorry...). I'm using it in all my programs, and I can assure you, I've never had any problems with that!
You're right, that most errors in C++ are pointer-errors. But it's the wrong position to don't use pointers at all or to make long roundabout ways just because you're afraid of pointers. Ok, where you don't need them, very nice.

Regards, Madshi.

P.S: My first answer with the ScanLine stuff IS AN EXAMPLE from the Delphi help. And they're using a pointer to the pixel buffer and read and write directly from/to the pixel buffer memory. So you should think about what you said about the Delphi help and the developer support...
P.P.S: Did't mean to insult or annoy you in any way. I'm just a little bit confused, because you're saying somehow, that it's a bad style of programming to use directly memory access - and so you're implying that my programming style is bad, too. And - you will understand that - I DON'T LIKE THAT.
0
 
LVL 3

Expert Comment

by:williams2
ID: 1349152
Madshi:

Please READ the context of my posing, you do not seem to read it carefully before applying the message above.

1. The Delphi programmers can NOT avoid using direct memory access, and they sure know what they do, because they built it. But when I pose an example of using the memory property, I automatically RECOMMEND to use it without a question. You do not know how experienced borgo is about this; If he gets a "Out of memory" exception, I'm responsible for it!

2. You do not seem to know anything about bytestuffing. To your knowledge you cannot typecast binary data to a string. When doing so, the strings looses everything next to the first #0 character. If strings might be WideSting specific ( using Strict Var's or the {$V+} compiler directive ). In that case the string truncates at the first two #0 characters.

3. I said specifically:
"..you will not see me adding things directly to the memory unless it's an important factor to the algorithm or program.."
If the user is experienced enough, he will see that it can be done faster, and then it's HIS OWN RESPONABILITY how to optimze it.
If you would like to read about the OSI-model, you might find, that the data is beeing copied from 5 to 7 times before the actually transmission takes place.

4. The scanline property is ok to use when implementing direct bitmap manipulation, but it is also a way MUCH faster than the canvas.pixel property. When implementing it, you are MAYBE accessing memory that is prior to the screen, which makes accessing it very very slow compared to other parts of the memory.
When copying memoryblocks in memory (as I do with copybuffer), that is not accessed by any hardware or software, the cpu is actually doing it very fast. If you do not believe me, you should go try looking it up.

Note: I think this discussion is brought too far away from it's origin. And I don't think it will be worth it discussing how fast these things can be done prior on examples of how to do it. So please, if you would have me excused!

Regards
Williams
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1349153
(1) and (3): Ok, my point of view is a little bit different, but that's ok...  :-)
(2) You CAN typecast binary data to a Delphi (!) string, as long as you don't convert it to a pchar string, cause the length of Delphi strings is not determined by #0 character but by a length integer in front of the string data. I guess, you know that? I'm doing such stuff every day...
(4) The scanline property is implemented by using DIB functions. That means DeviceIndependentBitmap (I'm sure you know that). So if these bitmaps are device independent, they're surely not in the video memory.

Ok, I agree. We should not spend our time on discussing. It seems that there was a little misunderstanding. I thought you would condemn direct memory access as a bad programming style and YOU just want to protect unexperienced programmers from playing too much with that. Of course I can agree with that...  :-)
0
 

Author Comment

by:borgo
ID: 1349154
Thank you William2 for your answer.
Can you give me one easy and fast advice please ?
This is my code:

procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var
  TempSize: Integer;
begin
  TempStr:=Socket.ReceiveText;
  // I need to use TempStr to read some text
  // Then I use your code.But Socket.ReceiveLength is allways = 0
  // If I delete the line "TempStr:=Socket.ReceiveText;"
  //   all is OK. Why ? Any advice ?
  If (Socket.ReceiveLength)>=(SizeOf(TempSize)) then
    begin
      Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
      Stream.SetSize(TempSize);
      Stream.Position:= 0;
      ..........................................
...........
     
0
 
LVL 3

Expert Comment

by:williams2
ID: 1349155
Yes! When sending text, you should receive the text with writing f.ex.:

S:= Socket.ReceiveText;

This way, you also should expect the incoming string from the opposite part. Unfortunately you cannot test the receivelength property, but the event is the same.

If you like to know another example, you should try read the example I wrote for "ItsMe" at:

             http://www.experts-exchange.com/Q.10104621

it explains how to capture the screen and send it to a client on request. At the bottom I also wrote an example using Francois Piettes freeware components.


Happy C/S developing!

Cheers,
Williams
0
 

Author Comment

by:borgo
ID: 1349156
Many many thanks to Williams :-)

Cheers,

Borgo.
0
 
LVL 3

Expert Comment

by:williams2
ID: 1349157
That's allright dear borgo.

Happy C/S-haunting

Cheers,
Williams
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now