axmolengine / axmol

Axmol Engine – A Multi-platform Engine for Desktop, XBOX (UWP) and Mobile games. (A fork of Cocos2d-x-4.0)
https://axmol.dev
MIT License
844 stars 192 forks source link

ax::ui::WebView cannot display local image #2031

Closed asnagni closed 4 weeks ago

asnagni commented 1 month ago

Hi, We are using ax::ui::WebView to display some information to the user. in the process we may just display a local png image. By local I mean an image residing on the device. Unfortunately it looks like it is not possible. We tried many things but so far nothing is working. Perhaps we are doing something wrong? Some help will be welcome.

For testing, you can use this image: output_inline_15367

This is the code to display a png image in a ax::ui::WebView.

std::string imagePath = "file://" + FileUtils::getInstance()->getWritablePath() + "reportsFolder/output_inline_15367.png";
std::string baseURL  = "file://" + FileUtils::getInstance()->getWritablePath();
std::string htmlContent = "<html><head></head><body><img src=\"" + imagePath + "\" alt=\"image info\" /></body></html>";

auto webView = ax::ui::WebView::create();
webView->loadHTMLString(htmlContent, baseURL);
this->addChild(webView);

This is the result that I get:

image

  1. create a png in your writable
  2. try to load the image in a ax::ui::WebView
smilediver commented 1 month ago

I don't know if that is possible, but as a workaround you should be able to embed image data directly into html like this: <img src="data:image/png;base64,base_64_encoded_png_image_data_goes_here">.

asnagni commented 1 month ago

Yes, it's possible and it's a good idea. I will try that. I should work. It will keep you posted.

asnagni commented 1 month ago

Hi smilediver, Embedding the image (base64 encoded) in the Html page worked. I will use this patch for now because it is not possible to use a local link to image.

Thank you for the suggestion, I do appreciate.

Stay safe

aismann commented 1 month ago

Hi smilediver, Embedding the image (base64 encoded) in the Html page worked. I will use this patch for now because it is not possible to use a local link to image.

Thank you for the suggestion, I do appreciate.

Stay safe

@asnagni Plz tell us the "running" version of your code snippet too. Thanks. Maybe a Q/R will added to the wiki.

asnagni commented 1 month ago

Hi aismann, Sure I can share with the community the workaround that I have, no problem:

What you need to do is to perform a base64 encoding of the image that you have. I do that using this function:

Step 1: use the function for the base64 encoding

     //////////////////////////////////////// base64 encode string ////////////////////////////////////////
    static const std::string base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";

    std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) 
    {
        std::string ret;
        int i = 0;
        int j = 0;
        unsigned char char_array_3[3];
        unsigned char char_array_4[4];

        while (in_len--) 
        {
            char_array_3[i++] = *(bytes_to_encode++);
            if (i == 3) 
            {
                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;

                for (i = 0; (i < 4); i++)
                    ret += base64_chars[char_array_4[i]];
                i = 0;
            }
        }

        if (i)
        {
            for (j = i; j < 3; j++)
                char_array_3[j] = '\0';

            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);

            for (j = 0; (j < i + 1); j++)
                ret += base64_chars[char_array_4[j]];

            while ((i++ < 3))
                ret += '=';
        }

        return ret;
    }

Step 2: get the bytes (the data) from the file (png) and encode it

auto path = FileUtils::getInstance()->getNativeWritableAbsolutePath();
std::string fileFullPath = path + std::string("temp/myImageSnapshotFile.png");

std::ifstream imageFile(fileFullPath, std::ios::binary);

if(imageFile.is_open())
{
    // You need to seek to the end of the file to determine its size
    imageFile.seekg(0, std::ios::end);
    std::streampos fileSize = imageFile.tellg();
    imageFile.seekg(0, std::ios::beg);

    // Resize the string to fit the file content
    readBuffer.resize(fileSize);

    // Now you can read the file content into the string
    imageFile.read(&buffer[0], fileSize);

    // Now the final step: Convert readBuffer to Base64
    std::string base64Image = base64_encode(reinterpret_cast<const unsigned char*>(readBuffer.data()), (unsigned int)readBuffer.size());
    std::string strToUseForWebView = "data:image/png;base64," + base64Image;
}

"strToUseForWebView" is the string that you need to use to embed your local image in the ax::ui::WebView object that you have.

I hope that helps. Stay safe