Solved

Delphi: How to decode Base64 encoded string into viewable bitmap image

Posted on 2008-06-12
6
13,108 Views
Last Modified: 2013-11-23
Hi,

I'm referring to previous question titled Decode hex text file into viewable bitmap image, which targeted VB.NET development.
http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22710540.html

Does anybody know how to perform similar task in Delphi?

I also have a string encoded in Base64 , which is the result of capturing a signature image from a PDA. The string looks like below:

PRY7FTcUNBQyFjEYMhozHDYcNx84ITYjMyQxJS8kLSQtJP//QxJCFEIWQhlBG0EdQR9BIUMfQx///1YOVhBUD1IQUBBNEUwTSxZMGE0aTxxRHFMeVR9XHlgbWBlWGFMYURhPGE8Y//9gGl8YXxZfFF8SYBBgDmIPYxFkFGUXZhloFmgUaRFqDmoMagpqCv//Rz1HP0dBR0RGRkZJRktGTUZN//9NPE4+TkBOQ09FT0dQSlFMUEpPR09FTURLRUlFR0RHRP//WzxZO1Y9VD1SP1JBUkNTRVVHWEhaSFpI//9aQVhBVkFTQVFAUUD//2NEY0FiP2I8YjpiOGQ2ZjVoN2o5aztqPWk/Z0BkQGI+Y0BlQWdCakNsQ25EbkT//3w0eTR3NXQ2cjdwOW87cD1yP3RAdkJ4QnpDekP//3k5dzp1OnM6cTpuOW45//8=

here is what the PDA vendor says about the file:
-----------------------------------------------------------------
Ok, the data coming in is basically a list of lines to draw.

To make the data in the first place, a series of points that would create the lines of the signature are recorded, where any pen lift (i.e. the drawing stopped) is recorded as 255,255 to serve as a terminator.

This array of points is turned into a byte array (i.e. line from 2,3 to 40, 50 to 80, 3 becomes byte[] {2,3,40,50, 80, 3} )

This is run through a Microsoft call Convert.ToBase64String to cut down on size (ever seen how big an xml encoded byte array is?) and make it easier to pass the data back into a webservice via a string parameter.  The data will need to be de-converted from this form to get the byte array back out, that is then used to draw the lines in the code sample you supplied.
-----------------------------------------------------------------

How to convert this string back into a viewable Bitmap image using DELPHI? How about in PHP?

I believe that from the byte array, each pair is a point. So to draw the signature you just draw the points. So byte[0] =  31 and byte[1] = 102 is point 1. Then you would draw a line from this point to the next point which is byte[2] and byte[3] and then you would draw a line from this to the next point and so on.

They also sent us a function (in C#) to draw the byte array but how to convert this function into Delphi and PHP?

thanks
Anthony
using System;

using System.Drawing;

using System.Collections;

 

namespace ADS.WorkstationPC

{

	/// <summary>

	/// Summary description for SignatureToBitmap.

	/// </summary>

	public class SignatureToBitmap

	{

		private static SignatureToBitmap UniqueBitmap = new SignatureToBitmap();

		private SignatureToBitmap()

		{

			//

			// TODO: Add constructor logic here

			//

 

		}

		public static Bitmap GetBitmap(byte[] rawsignature)

		{

			Bitmap bmSignature = new Bitmap(254, 254);

			Graphics gr = Graphics.FromImage(bmSignature);

			Pen pen = new Pen(new SolidBrush(Color.Black), 1);

			ArrayList alline = new ArrayList();

			ArrayList alpoint = new ArrayList();

 

			foreach (byte abyte in rawsignature)

			{

				alpoint.Add((int)abyte);

				if (alpoint.Count > 1)

				{

					Point apoint = new Point((int)alpoint[0], (int)alpoint[1]);

					alpoint.Clear(); // clear the array list

					alline.Add(apoint); //adds to the end of the array list

					if (apoint.X == 255) 

						alline.Clear();

                    else if (alline.Count > 1)

					{

						Point firstpoint = (Point)alline[0]; //?

						alline.RemoveAt(0); // removes the element at that index

						gr.DrawLine(pen, firstpoint, apoint);

					}

				}

			}

 

			return bmSignature;

		}

	}

}

Open in new window

byte-array.gif
signature.gif
encodedstring.gif
0
Comment
Question by:COS_IT_AU
  • 3
6 Comments
 
LVL 45

Expert Comment

by:aikimark
Comment Utility
Is the Base64 decoding a problem?  If so, please look at the decoding routine found on this Torry's page:
http://www.swissdelphicenter.ch/torry/showcode.php?id=1524

When you reach this statement:
     x := x mod 256;
You will have the numeric value you seek.  You do not need the next statement to convert this numeric value into a character.  Just add the numeric value to a byte array or list.

Then use the numeric value pairs to paint on a canvas, using a series of .LineTo() and .MoveTo() methods.
References and Tutorials:
http://www.ibrtses.com/delphi/graphicedit1.html
http://www.functionx.com/delphi/gdi/drawing101.htm
http://delphi.about.com/library/bluc/text/uc052102b.htm

After the painting, you will have a bitmap.

Since Base64 uses more characters than bytes, you will be safe to allocate a byte array the same size as the number of characters.
0
 
LVL 26

Accepted Solution

by:
EddieShipman earned 125 total points
Comment Utility
I used SZCodeBaseX (http://www.szutils.net/download.php?ID=2) to encode and decode a small GIF file. Since it was a GIF, I also needed TGIFImage from Torry's
(http://www.torry.net/vcl/graphics/gif/gifimaged7f.zip)

It also worked on a JPG file.
Now, the base64 code that I got came back different than yours. If you could have posted your exact B64 code, then I could test it.

Do you know what extension the file getting from the PDA is?

unit Unit1;
 

interface
 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, ExtCtrls, GIFImage;
 

type

  TForm1 = class(TForm)

    btnEncode: TButton;

    btnDecode: TButton;

    Image1: TImage;

    Memo1: TMemo;

    procedure btnEncodeClick(Sender: TObject);

    procedure btnDecodeClick(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;
 

var

  Form1: TForm1;
 

implementation
 

uses SZCodeBaseX;
 

{$R *.dfm}
 
 

procedure TForm1.btnEncodeClick(Sender: TObject);

var

  ss: TStringStream;

  sl: TStringList;

begin

  sl := TStringList.Create;

  ss := TStringStream.Create('');

  try

    SZEncodeBase64('C:\image10.gif', ss);

    Memo1.Lines.Text := ss.DataString;

    ss.Position := 0;

    sl.LoadFromStream(ss);

    sl.SaveToFile( 'C:\DelphiEncode.txt' );

  finally

    sl.Free;

    ss.Free;

  end;

end;
 

procedure TForm1.btnDecodeClick(Sender: TObject);

var

  strm: TFileStream;

  ss: TStringStream;

  sl: TStringList;

  s: string;

  GIF: TGIFimage;

begin

  strm := TFileStream.Create( 'C:\delphi-Decode.gif', fmCreate );

  sl := TStringList.Create;

  ss := TStringStream.Create(s);

  try

    strm.Position := 0;

    sl.LoadFromFile( 'C:\DelphiEncode.txt' );

    s := sl.Text;

    SZDecodeBase64(ss, strm);

  finally

    sl.Free;

    ss.Free;

    strm.Free;

    GIF := TGIFImage.Create;

    try

      GIF.LoadFromFile('C:\delphi-Decode.gif');

      Image1.Picture.Assign(GIF);

    finally

      GIF.Free;

    end;

  end;

end;
 

end.

Open in new window

0
 
LVL 26

Expert Comment

by:EddieShipman
Comment Utility
Anthony, have you tried this code? Do you have any more input?
0
 
LVL 26

Expert Comment

by:EddieShipman
Comment Utility
It's been over a month, have you tried this, yet? Please accept my answer if it worked for you.
0
 

Author Closing Comment

by:COS_IT_AU
Comment Utility
Hi Eddie, sorry for the delayed response.... Cheers!
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
How to install Selenium IDE and loops for quick automated testing. Get Selenium IDE from http://seleniumhq.org (http://seleniumhq.org) Go to that link and select download selenium in the right hand columnThat will then direct you to their downlo…
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The viewer will learn how to synchronize PHP projects with a remote server in NetBeans IDE 8.0 for Windows.

743 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

16 Experts available now in Live!

Get 1:1 Help Now