Couleur d’un pixel dans un TBitmap

Dans cet article, nous allons voir comment changer la couleur des pixels dans un Fmx::Graphics::TBitmap.

Pour cela, on va utiliser une image PNG qui possède seulement deux couleurs: du blanc et du noir.
Cœur

Tout d’abord, il faut créer un projet FireMonkey dans lequel il faut ajouter un composant TImage.

Ensuite, il faut ajouter le fichier d’en-tête suivant pour utiliser TAlphaColorArray:

#include <FMX.Utils.hpp>

Par la suite, vous pouvez ajouter ce code dans le constructeur de la Form.

Fmx::Graphics::TBitmap* LBitmap = NULL;
try
{
    LBitmap = new Fmx::Graphics::TBitmap("C:\\images\\heart.png");
 
    TBitmapData LBitmapData;
    if(LBitmap->Map(TMapAccess::ReadWrite, LBitmapData))
    {
        try
        {
            TAlphaColorArray* LColorArray;
            for(int y = 0; y < LBitmapData.Height; ++y)
            {
                LColorArray = static_cast<TAlphaColorArray*>
                    (LBitmapData.GetScanline(y));
                for(int x = 0; x < LBitmapData.Width; ++x)
                {
                    void* LPixel = &LColorArray->data[x];
                    const System::Uitypes::TAlphaColor LColor =
                        PixelToAlphaColor(LPixel, LBitmapData.PixelFormat);
                    if(LColor == TAlphaColorRec::White)
                    {   // Change le blanc en rouge
                        AlphaColorToPixel(TAlphaColorRec::Red,
                            LPixel, LBitmapData.PixelFormat);
                    }
                    else if(LColor == TAlphaColorRec::Black)
                    {   // Change le noir en violet
                        AlphaColorToPixel(TAlphaColorRec::Violet,
                            LPixel, LBitmapData.PixelFormat);
                    }
                }
            }
        }
        __finally
        {
            LBitmap->Unmap(LBitmapData);
        }
    }
 
    Image1->Bitmap->Assign(LBitmap);
}
__finally
{
    delete LBitmap;
}

Voilà, maintenant vous devriez obtenir ceci à l’exécution:

Résultat changement de couleur

MD5 et SHA1 avec l’unité System::Hash

Dans un article précédent, j’avais montré comment calculer un hachage MD5 et SHA1 avec Indy. Je me suis rendu compte cette semaine qu’il existait depuis C++Builder XE8 une manière d’effectuer ces mêmes calculs sans avoir de dépendance sur la bibliothèque de communication Indy.

Tout d’abord, il faut ajouter le fichier d’en-tête suivant:

#include <System.Hash.hpp>

Pour MD5, il faut ce code:

String __fastcall TForm1::GetHashMD5(const String AFileName)
{
    System::Hash::THashMD5 LMd5 = System::Hash::THashMD5::Create();
    System::Classes::TFileStream* LFileStream = NULL;
    try
    {
        LFileStream = new System::Classes::TFileStream(AFileName,
            fmOpenRead | fmShareDenyWrite);
        System::DynamicArray<System::Byte> Buffer;
        Buffer.Length = LFileStream->Size;
        LFileStream->Read(&Buffer[0], Buffer.Length);
        LMd5.Update(Buffer);
    }
    __finally
    {
        delete LFileStream;
    }
    return LMd5.HashAsString().UpperCase();
}

Pour SHA1, on utilise ce code:

String __fastcall TForm1::GetHashSHA1(const String AFileName)
{
    System::Hash::THashSHA1 LSha1 = System::Hash::THashSHA1::Create();
    System::Classes::TFileStream* LFileStream = NULL;
    try
    {
        LFileStream = new System::Classes::TFileStream(AFileName,
            fmOpenRead | fmShareDenyWrite);
        System::DynamicArray<System::Byte> Buffer;
        Buffer.Length = LFileStream->Size;
        LFileStream->Read(&Buffer[0], Buffer.Length);
        LSha1.Update(Buffer);
    }
    __finally
    {
        delete LFileStream;
    }
    return LSha1.HashAsString().UpperCase();
}

Une nouvelle version de l’IDE, C++Builder 10 Seattle, est maintenant disponible. L’unité System::Hash a un nouveau membre. Il s’agit de THashSHA2. Il implémente la famille de fonctions de hachage SHA-2:

enum DECLSPEC_DENUM TSHA2Version : unsigned char { SHA224, SHA256, SHA384, SHA512, SHA512_224, SHA512_256 };

CRC32 avec Zlib et Boost

Dans un article précédent, j’avais montré comment calculer un CRC32 avec Indy. Maintenant, dans celui-ci, je vais vous montrer comment effectuer le même travail avec Zlib et Boost qui sont aussi inclus avec C++Builder.

Tout d’abord, il faut ajouter les fichiers d’en-têtes:

#include <System.Zlib.hpp>
#include <boost/crc.hpp>

Pour la méthode qui utilise Zlib:

String __fastcall TForm1::GetCRC32Zlib(const String AFileName)
{
    String Result;
 
    System::Classes::TMemoryStream* LMemoryStream = NULL;
    try
    {
        LMemoryStream = new System::Classes::TMemoryStream();
        LMemoryStream->LoadFromFile(AFileName);
        const unsigned __int64 LVal = System::Zlib::crc32(0,
            static_cast<System::Byte*>(LMemoryStream->Memory),
            LMemoryStream->Size);
        Result = System::Sysutils::IntToHex(LVal, 8);
    }
    __finally
    {
        delete LMemoryStream;
    }
 
    return Result;
}

Pour la méthode qui utilise Boost:

String __fastcall TForm1::GetCRC32Boost(const String AFileName)
{
    String Result;
 
    System::Classes::TMemoryStream* LMemoryStream = NULL;
    try
    {
        LMemoryStream = new System::Classes::TMemoryStream();
        LMemoryStream->LoadFromFile(AFileName);
        boost::crc_32_type crc_ccitt;
        crc_ccitt.process_bytes(
            static_cast<System::Byte*>(LMemoryStream->Memory),
            LMemoryStream->Size);
        const unsigned __int64 LVal = crc_ccitt.checksum();
        Result = System::Sysutils::IntToHex(LVal, 8);
    }
    __finally
    {
        delete LMemoryStream;
    }
 
    return Result;
}

Voilà, vous avez maintenant le choix entre plusieurs méthodes pour la prochaine fois où vous aurez à utiliser un contrôle de redondance cyclique sur un fichier.

Hachage d’un fichier avec Indy

J’aime bien utiliser la bibliothèque Crypto++ pour calculer le hachage d’un fichier. Par contre, des fois il m’arrive de vouloir utiliser cette fonctionnalité sans rien télécharger de plus. Heureusement Indy, qui est inclus dans RAD Studio, nous permet de faire cela facilement.

Dans cet article, on verra comment faire un CRC32, MD5 et SHA1.

En premier, on ajoute les fichiers d’en-têtes:

#include <IdHashCRC.hpp>
#include <IdHashMessageDigest.hpp>
#include <IdHashSHA.hpp>

Pour le CRC32 on ajoute cette méthode:

String __fastcall TForm1::GetHashCRC32(const String AFileName)
{
    String Result;

    TIdHashCRC32* LCrc32 = NULL;
    System::Classes::TFileStream* LFileStream = NULL;
    try
    {
        LCrc32 = new TIdHashCRC32();
        LFileStream = new System::Classes::TFileStream(AFileName,
            fmOpenRead | fmShareDenyWrite);
        const unsigned __int64 LVal = LCrc32->HashValue(LFileStream);
        Result = System::Sysutils::IntToHex(LVal, 8);
    }
    __finally
    {
        delete LFileStream;
        delete LCrc32;
    }

    return Result;
}

Pour le MD5 on ajoute cette méthode:

String __fastcall TForm1::GetHashMD5(const String AFileName)
{
    String Result;

    TIdHashMessageDigest5* LMd5 = NULL;
    System::Classes::TFileStream* LFileStream = NULL;
    try
    {
        LMd5 = new TIdHashMessageDigest5();
        LFileStream = new System::Classes::TFileStream(AFileName,
            fmOpenRead | fmShareDenyWrite);
        Result = LMd5->HashStreamAsHex(LFileStream);
    }
    __finally
    {
        delete LFileStream;
        delete LMd5;
    }

    return Result;
}

Pour le SHA1 on ajoute cette méthode:

String __fastcall TForm1::GetHashSHA1(const String AFileName)
{
    String Result;

    TIdHashSHA1* LSha1 = NULL;
    System::Classes::TFileStream* LFileStream = NULL;
    try
    {
        LSha1 = new TIdHashSHA1();
        LFileStream = new System::Classes::TFileStream(AFileName,
            fmOpenRead | fmShareDenyWrite);
        Result = LSha1->HashStreamAsHex(LFileStream);
    }
    __finally
    {
        delete LFileStream;
        delete LSha1;
    }

    return Result;
}

Il est à noter que Indy supporte aussi ces classes:

  • TIdHashSHA224
  • TIdHashSHA256
  • TIdHashSHA384
  • TIdHashSHA512

Pour tester le code, on peut ajouter un contrôle TMemo et mettre le code suivant dans le constructeur.

const String LFileName = "C:\\monfichier.xyz"; // Le fichier doit exister
Memo1->Lines->Add("CRC32: " + GetHashCRC32(LFileName));
Memo1->Lines->Add("MD5  : " + GetHashMD5(LFileName));
Memo1->Lines->Add("SHA1 : " + GetHashSHA1(LFileName));

Si on veut être certain que le résultat est valide, on peut vérifier avec un logiciel comme HashTab:

HashTab

Compression de fichiers avec FWZip

Dans un article précédent j’avais parlé de la classe TZipFile qui permet de faire de la compression de fichiers. Elle est très pratique. Par contre, il y a une fonctionnalité manquante qui est importante pour moi. Il s’agit de l’ajout d’un mot de passe à l’archive. C’est une limitation qui est connue d’Embarcadero depuis C++Builder XE2. Malheureusement il n’y a pas encore de solution qui a été apportée.

Je suis tombé par hasard sur une bibliothèque qui supporte cette fonctionnalité. Il s’agit de FWZip de Александр (Rouse_) Багель. Elle est codée en Pascal Objet et fonctionne sur Win32 et Win64 dans des projets VCL et FireMonkey. Elle peut être téléchargée sur GitHub.

C’est très simple à utiliser. Il faut d’abord ajouter les fichiers suivants à votre projet:

  • FWZipConsts.pas
  • FWZipCrc32.pas
  • FWZipCrypt.pas
  • FWZipReader.pas
  • FWZipStream.pas
  • FWZipWriter.pas
  • FWZipZLib.pas

The tadalafil for sale cheap pharmaceutical market has been loaded with diverse choices of medicinal drugs which have been proving to be extremely helpful for getting recovered from the severe adverse reactions. To buy steroids in UK you should visit anabolicmuscles.com. anabolicmuscles.com have become most cialis buy online learningworksca.org trusted and acknowledge steroid supplier in UK since 2002. You’re safe now… you’re safe now… » Whoa! Sounds familiar, eh? Are you that overprotective over your smartphone-specifically, your iPhone? Hello! Who wouldn’t? Considering how much iPhone costs these days; one cannot simply afford cheap sildenafil an iPhone. Why? According to his repeated clinical research based on a large quantity of patients with chronic prostatitis, doctor Miller best levitra price makes progress in curing this disease by applying a new method.

On ajoute ensuite le fichier d’en-tête et la bibliothèque nécessaire.

#include <FWZipWriter.hpp>
#pragma comment(lib, "Shlwapi") // Pour PathCanonicalizeW / PathCanonicalizeA

Pour écrire une archive, on utilise ce code:

    TFWZipWriter* Zip = new TFWZipWriter(false,
        Fwzipzlib::TCompressionLevel::clLevel3, "MotDePasse");

    Zip->AddFile("C:\\img\\img0.png");
    Zip->AddFile("C:\\img\\img1.png");

    Zip->BuildZip("C:\\img\\images.zip");

    delete Zip;

Et voilà, maintenant lors de l’extraction des fichiers, un mot de passe sera demandé.

7-Zip Enter password window
Fenêtre de saisie de mot passe du logiciel 7-Zip

L’API PageSpeed v2

Dans cet article je vais revisiter l’article que j’avais écrit en mai 2012 sur l’utilisation de l’API PageSpeed de Google. Cette fois-ci c’est C++Builder XE7 qui sera utilisé avec la version 2 de l’API. Tout comme la première fois, les résultats seront présentés dans un diagramme circulaire à l’aide du contrôle TChart. En plus du code qui sera légèrement différent, un composant TImage sera utilisé pour y afficher une capture d’écran du site web.

La première étape est de créer un nouveau projet FireMonkey. Dans la Form il faut insérer un TRESTClient, un TRESTRequest, un TRESTResponse, un TChart, un TImage et un TLayout dans lequel il y aura un TEdit un TButton. On aligne le contrôle TLayout à Bottom et vous pouvez donner comme texte à votre bouton le mot « Analyser ».

Voici ce à quoi l’interface devrait ressembler:
Analyseur de site web

Dans votre fichier cpp voici la liste de fichier d’en-tête à utiliser ainsi que la macro qui va contenir votre clef d’API. N’essayez pas d’utiliser celle-ci, il s’agit de caractères écrits de façon aléatoire.

#include <System.JSON.hpp>
#include <FMXTee.Series.hpp>
#include <System.NetEncoding.hpp>
#define GOOGLEAPIKEY "dskk1j3sW4WBYdkjds8sSDSD" // Clef d'API

Voici le code à ajouter dans votre constructeur:

    Chart1->Title->Text->Text = "Statistique de la page";
    Chart1->Legend->Title->Text->Text = "Ressource en octets";
    Chart1->Legend->Alignment = TLegendAlignment::laBottom;
    Chart1->BevelOuter = TPanelBevel::bvNone;
    Series::TPieSeries *Series = new Series::TPieSeries(this);
    Series->Marks->Visible = false;
    Chart1->AddSeries(Series);

Étant donné que nous accéderons à un site web qui utilise SSL (https), les fichiers ssleay32.dll et libeay32.dll devront être distribués avec votre application Windows. Une version Win32 et Win64 des fichiers est disponible sur le site web suivant: http://indy.fulgan.com/SSL.

La prochaine étape est d’ajouter le code dans l’événement OnClick du bouton.

    Chart1->Series[0]->Clear(); // Efface le contenu du diagramme

    RESTClient1->BaseURL =
        "https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url=" +
        Edit1->Text + "&key=" GOOGLEAPIKEY + "&screenshot=true";
    RESTRequest1->Execute();

    TJSONObject* Obj = static_cast<TJSONObject*>(RESTResponse1->JSONValue);
    TJSONPair* Pair = Obj->Get("pageStats");
    if(Pair)
    {
        TJSONNumber* Answer;
        TJSONObject* PageStats = static_cast<TJSONObject*>(Pair->JsonValue);
        if((Pair = PageStats->Get("htmlResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "HTML", TAlphaColor(claGreen));
        }
        if((Pair = PageStats->Get("cssResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "CSS", TAlphaColor(claOrange));
        }
        if((Pair = PageStats->Get("imageResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "Image", TAlphaColor(claYellow));
        }
        if((Pair = PageStats->Get("javascriptResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "JavaScript", TAlphaColor(claRed));
        }
        if((Pair = PageStats->Get("otherResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "Autre", TAlphaColor(claBlue));
        }
    }
    Pair = Obj->Get("screenshot");
    if(Pair)
    {
        TJSONObject* Screenshot = static_cast<TJSONObject*>(Pair->JsonValue);
        if((Pair = Screenshot->Get("data")) != NULL)
        {
            TJSONString* Answer = static_cast<TJSONString*>(Pair->JsonValue);
            String Value = Answer->Value();
            // On change de base64url à base64
            Value = ReplaceStr(ReplaceStr(Value, "_", "/"), "-", "+");
            // On transforme de base64 vers stream
            TBytes LDAta = TNetEncoding::Base64->DecodeStringToBytes(Value);
            TBytesStream* LStream = new TBytesStream(LDAta);
            try
            {
                Image1->Bitmap->LoadFromStream(LStream);
            }
            __finally
            {
                delete LStream;
            }
        }
    }

Un petit mot sur la ligne 49. La documentation de l’API PageSpeed à propos des données de l’image dit:

Base64-encoded screenshot of the page that was analyzed.

Les données peuvent comporter des caractères moins (-) et souligné (_), donc la documentation est erronée si on se fie à RFC 4648 section 5:

This encoding may be referred to as « base64url ». This encoding should not be regarded as the same as the « base64 » encoding and should not be referred to as only « base64 ». Unless clarified otherwise, « base64 » refers to the base 64 in the previous section.

This encoding is technically identical to the previous one, except for the 62:nd and 63:rd alphabet character, as indicated in Table 2.

Google n’aurait donc pas dû dire qu’il s’agit de base64. Il aurait dû dire que c’est du base64url. C’est pour cette raison que je remplace les deux caractères.

Pourtant, dans d’autres API comme celui de Gmail, Google met la bonne information:

The entire email message in an RFC 2822 formatted and base64url encoded string.

En terminant, je vous rappelle qu’un nouvel outil dans RAD Studio XE7 vous permet de tester les API REST. Il se trouve Tools / Rest Debugger. Voici une capture d’écran du logiciel:
RESTDebugger

Comment déboguer sur la OUYA avec RAD Studio

La OUYA est une console de jeu vidéo qui fonctionne sous le système d’exploitation Android. Il est donc possible grâce à FireMonkey de créer des applications pour cette plateforme. Bien sûr, les déboguer à partir de l’IDE serait un grand avantage. C’est ce que le logiciel adb nous permet de faire. Tout d’abord il faut démarrer la OUYA et aller dans le menu MANAGE / SYSTEM / DEVELOPPEMENT. Il faut activer ADB et ADB OVER NETWORK comme démontré dans la capture d’écran suivante:
OUYA ADB ON
L’adresse IP et le numéro de port vous seront utiles bientôt. Il faut d’abord se connecter à la OUYA. Pour cela l’application Android Debug Bridge (adb) située dans le dossier /<sdk>/platform-tools sera utilisée. Dans le SDK Manager pour Android on trouve ce chemin dans la section Adb location. Vous devez aller dans ce dossier et taper la ligne de commande suivante:
adb connect 192.168.1.104:5555
Si tout fonctionne le résultat devrait être: connected to 192.168.1.104:5555

Ensuite, ouvrez ou créez un nouveau projet de type Multi-Device Application dans RAD Studio. Sélectionnez le Target Android. Dans la section Target de celui-ci OUYA Console devrait apparaitre. Si ce n’est pas le cas il faut faire un Refresh.

OUYA Console Target

Il est maintenant possible de compiler le fichier APK et de tester l’application directement sur la console. Une fois fermée, elle devrait être disponible dans la section MAKE / SOFTWARE.

Si vous voulez simplement installer l’application, il est possible d’aller dans le menu MAKE / UPLOAD afin d’activer le téléchargement vers la OUYA.
OUYA Upload APK
Il vous suffit simplement d’ouvrir le lien donné dans votre navigateur web préféré et de déposer le fichier APK dans la zone appropriée.
Upload APK

Il est possible de faire d’autres tâches intéressantes avec adb. Par exemple, j’ai enregistré une capture d’écran sur la OUYA avec la ligne de commande suivante:
adb shell screencap -p /sdcard/screencap.png
Ensuite j’ai transferé l’image vers mon disque local C: avec cette ligne de commande:
adb pull /sdcard/screencap.png c:\

RAD Studio XE6: Interface bilingue?

Habituellement j’installe toujours RAD Studio en anglais car je suis habitué au vocabulaire technique dans la langue de Shakespeare. À la suite de l’installation de la version d’essai je me suis retrouvé avec une version complètement bilingue. Cela m’a pris plusieurs minutes avant de m’en apercevoir. Dans l’interface on voit un Find côtoyer un Chercher, un Output à coté d’un Sortie et ainsi de suite. Je vous laisse regarder par vous-mêmes:

RAD Studio XE6 Bilingue

À la suite d’un redémarrage causé par un plantage de l’EDI tout est redevenu normal. J’ai maintenant mon interface en anglais comme spécifié lors de l’installation.

J’ai bien sûr rapporté le bug à Embarcadero, mais ils sont incapables de le reproduire. Tenez-moi au courant si vous observez ce problème.

Server-Sent Events avec C++Builder

Les Server-Sent Events (SSE) servent à pousser des informations à partir d’un serveur HTTP vers un navigateur web. Habituellement c’est le client qui doit demander l’information au serveur, mais avec cette méthode c’est le contraire.

Le principe est simple: le client fait une requête à une adresse web dans le but de recevoir des évènements DOM. Pour effectuer cela, c’est EventSource de l’API JavaScript qui sera utilisé. Il est important de dire que les Server-Sent Events ne sont pas encore supportés dans Internet Explorer.

La première étape est de créer un nouveau projet C++Builder. Dans la Form il faut insérer un TIdHTTPServer. C’est ce contrôle de Indy qui sera utilisé pour le serveur. On commence d’abord par démarrer le serveur avec ligne de code dans le constructeur:

    IdHTTPServer1->Active = true;

Dans l’évènement OnCommandGet du TIdHTTPServer on ajoute ce code:

    if(ARequestInfo->URI == "/demo")
    {
        TIdTCPConnection* Connection = AContext->Connection;
        while(Connection->Connected())
        {
            System::Word Hour, Min, Sec, MSec;
            Now().DecodeTime(&Hour, &Min, &Sec, &MSec);
            String Message = "Voici l'heure sur le serveur: " +
                Format("%.2d:%.2d:%.2d.%.3d", ARRAYOFCONST((Hour, Min, Sec, MSec)));

            Connection->IOHandler->WriteBufferOpen();
            Connection->IOHandler->WriteLn("HTTP/1.1 200 OK");
            Connection->IOHandler->WriteLn("Content-Type: text/event-stream; charset=UTF-8");
            Connection->IOHandler->WriteLn("Cache-Control: no-cache");
            Connection->IOHandler->Write("data: " + Message + "\n\n");
            Connection->IOHandler->WriteBufferClose();

            Sleep(100); // Une petite pause
        }
    }
    else
    {
        AResponseInfo->ContentText =
            "<!doctype html>"
            "<html>"
            "    <head>"
            "        <title>Server-Sent Events</title>"
            "        <script type = \"text/javascript\">"
            ""
            "        var source = new EventSource(\"demo\");"
            "        source.onmessage = function(event)"
            "        {"
            "            document.getElementById(\"result\").innerHTML = event.data;"
            "        };"
            ""
            "        </script>"
            "    </head>"
            "    <body>"
            "        <p id=\"result\"></p>"
            "    </body>"
            "</html>";
    }

Voilà, maintenant il suffit d’ouvrir votre navigateur web à l’adresse 127.0.0.1 vous devriez voir l’heure de votre PC qui s’actualise à tous les 100ms.

Utiliser l’API Graph de Facebook avec C++Builder

Facebook se passe sans doute de présentation, par contre son API est peut-être moins connu. Dans cet article nous irons chercher les informations publiques d’un utilisateur qui ne nécessitent aucune autorisation.

La première étape est de créer un nouveau projet FireMonkey HD. Dans la Form il faut insérer un TIdHTTP, un TIdSSLIOHandlerSocketOpenSSL, un TStringGrid, un TImage, un contrôle TEdit, un TLabel et finalement un TButton. Vous pouvez donner comme texte à votre bouton le mot « Rechercher » et pour le TLabel vous pouvez y inscrire « Nom d’utilisateur: ». Je vous propose de placer les composants dans la fenêtre de la manière suivante:
Pour ceux qui se le demande j’ai utilisé le style Air.Style. Ça change un peu des fenêtres Windows que l’on voit tout le temps.

Dans votre fichier cpp voici le fichier d’en-tête à ajouter:

#include <Data.DBXJSON.hpp>

Voici le code à ajouter dans votre constructeur:

    IdHTTP1->IOHandler = IdSSLIOHandlerSocketOpenSSL1;

    // Ceci est nécessaire pour les redirections
    IdHTTP1->HandleRedirects = true;

    // Propriété par défaut pour le contrôle grille
    StringGrid1->ShowSelectedCell = false;
    StringGrid1->ReadOnly = true;
    StringGrid1->RowCount = 0;

    // Ajout de la première colonne
    StringGrid1->AddObject(new TStringColumn(this));
    StringGrid1->Columns[0]->Header = L"Nom";
    StringGrid1->Columns[0]->Width = 150;

    // Ajout de la deuxième colonne
    StringGrid1->AddObject(new TStringColumn(this));
    StringGrid1->Columns[1]->Header = L"Valeur";
    StringGrid1->Columns[1]->Width = 150;

Étant donné que nous accéderons à un site web qui utilise SSL (https), la première ligne de code est critique. Sans elle, une exception dans la classe EIdIOHandlerPropInvalid produira le message « IOHandler value is not valid ». Parce que nous utilisons OpenSSL, les fichiers ssleay32.dll et libeay32.dll devront être distribués avec votre application.

La prochaine étape est d’ajouter le code dans l’événement OnClick du bouton.

    System::Classes::TMemoryStream* ResponseContent = new System::Classes::TMemoryStream;

    try
    {
        // On vide la liste avant d'ajouter les valeurs
        StringGrid1->RowCount = 0;
        Image1->Bitmap = NULL;

        String URL = "https://graph.facebook.com/" + Edit1->Text;

        String Response = IdHTTP1->Get(URL);

        TJSONObject* Obj = static_cast<TJSONObject*>(TJSONObject::ParseJSONValue(Response));
        TJSONPair* Pair;
        TJSONString* Answer;

        if((Pair = Obj->Get("id")) != NULL)
        {   // ID Facebook
            const int Pos = StringGrid1->RowCount;
            StringGrid1->RowCount++;
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            StringGrid1->Cells[0][Pos] = "ID";
            StringGrid1->Cells[1][Pos] = AnsiDequotedStr(Answer->ToString(), '\"');
        }
        if((Pair = Obj->Get("name")) != NULL)
        {   // Nom complet
            const int Pos = StringGrid1->RowCount;
            StringGrid1->RowCount++;
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            StringGrid1->Cells[0][Pos] = "Nom";
            StringGrid1->Cells[1][Pos] = AnsiDequotedStr(Answer->ToString(), '\"');
        }
        if((Pair = Obj->Get("first_name")) != NULL)
        {   // Prénom
            const int Pos = StringGrid1->RowCount;
            StringGrid1->RowCount++;
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            StringGrid1->Cells[0][Pos] = "Prénom";
            StringGrid1->Cells[1][Pos] = AnsiDequotedStr(Answer->ToString(), '\"');
        }
        if((Pair = Obj->Get("last_name")) != NULL)
        {   // Nom de famille
            const int Pos = StringGrid1->RowCount;
            StringGrid1->RowCount++;
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            StringGrid1->Cells[0][Pos] = "Nom de famille";
            StringGrid1->Cells[1][Pos] = AnsiDequotedStr(Answer->ToString(), '\"');
        }
        if((Pair = Obj->Get("gender")) != NULL)
        {   // Sexe (female ou male)
            const int Pos = StringGrid1->RowCount;
            StringGrid1->RowCount++;
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            StringGrid1->Cells[0][Pos] = "Sexe";
            StringGrid1->Cells[1][Pos] = AnsiDequotedStr(Answer->ToString(), '\"');
        }

        // Téléchargement de l'image
        IdHTTP1->Get(URL + "/picture", ResponseContent);

        Image1->Bitmap = new Fmx::Types::TBitmap(ResponseContent);
    }
    catch(...)
    {
    }

    delete ResponseContent;

Dans le code on insère dans la liste seulement quelques informations, mais il en existe plusieurs autres qui sont disponibles.

À présent, vous connaissez le minimum requis pour commencer à vous amuser avec cette interface API .