Sending base64 URLs from Android WebView to Javascript can be tricky due to the limitation on the URL length, which may result in a refusal

Trying to send a base64 image to JavaScript is proving challenging as I keep encountering an error in Android Studio:

W/chromium: [WARNING:navigator_impl.cc(280)] Refusing to load URL as it exceeds 2097152 characters.

Despite attempting to use loadDataWithBaseURL, I am struggling to get the JavaScript to execute properly - leaving me uncertain if it's a viable solution.

The code I'm using works for some images but fails with larger ones, resulting in the aforementioned error.

If anyone has any insights or solutions, they would be greatly appreciated!

if (resultCode == RESULT_OK)
{
    Uri selectedImage = intent.getData();
    myWebView.loadUrl("javascript:setFileUri('" + selectedImage.toString() + "')");
    String path = getRealPathFromURI(this, selectedImage);
    //myWebView.loadUrl("javascript:setFilePath('" + path + "')");


    Bitmap bm = BitmapFactory.decodeFile(path);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
    byte[] b = baos.toByteArray();

    String encodedImage = Base64.encodeToString(b, Base64.DEFAULT);

    myWebView.loadUrl("javascript:setFilePath('" + encodedImage + "')");
}

Answer №1

If you're still in search of a solution for sending an image to Javascript, I went through the same struggle today. The loadUrl method was causing me trouble with the '2097152' error, so I decided to give evaluateJavascript a try. Unfortunately, I encountered webview syntax errors. However, after some experimentation, I managed to make it work using the following approach:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);

try {
    final String retFunction = "imageReturnFunction('data:image/png;base64," + URLEncoder.encode(encoded, "UTF-8") + "');";

    runOnUiThread(new Runnable() {
        public void run() {
            webView.evaluateJavascript(retFunction, null);
        }
    });
} catch(Exception ex) {
    ex.printStackTrace();
}

In my case, I required the format to be a dataURL (which is often needed in JS applications), but feel free to adjust the code to fit your specific requirements. Hopefully, this solution proves helpful to you.

Answer №2

Referring to bastecklein's response

const functionJS = `"$jsEntryPoint('data:image/jpeg;base64,' +
                     base64String.replace('\n', '') 
                    +'');"`;

Answer №3

Despite my delayed response, a sudden solution emerged when I faced a problem that required reducing the size of a string passed to a WebView. Below is a potential solution that worked for me and might be helpful for you:

 public static String prepareImageForWebView(String img64) {
    final int IMAGE_MAX_SIZE = 0x100000; // 1048576
    if (img64.length() > IMAGE_MAX_SIZE) {
        byte[] bytes = Base64.decode(img64, Base64.DEFAULT);

        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, o);

        int scale = 1;
        while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
            scale++;
        }

        if (scale > 1) {
            scale--;

            o = new BitmapFactory.Options();
            o.inSampleSize = scale;
            bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, o);
            
            assert bitmap != null;
            int height = bitmap.getHeight();
            int width = bitmap.getWidth();

            double y = Math.sqrt(IMAGE_MAX_SIZE / (((double) width) / height));
            double x = (y / height) * width;

            Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) x, (int) y, true);
            bitmap.recycle();
            bitmap = scaledBitmap;

            System.gc();
        }

        if (bitmap == null) {
            return img64;
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, baos);
        bytes = baos.toByteArray();
        return Base64.encodeToString(bytes, Base64.DEFAULT);
    } else {
        return img64;
    }
}

To use this function, follow the sample code below:

 image = "<img style=\"display:inline;height:auto; max-width:100%;\" " +
                "src=\"data:image/jpg; base64," +
                prepareImageForWebView(imageData) + "\" />";
webView.loadData(image, "text/html", "UTF-8");

If needed, adjust the value of IMAGE_MAX_SIZE to control the output size of the Base64 string. For instance, recompressing a 6 MB base64 file can retain sufficient quality for clear text reading in an A4-sized image.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Haxe: Ways to keep the android menu bar hidden for a seamless user experience

Currently in the process of building an app using haxe/openfl and utilizing the flashdevelop IDE. The default setup for a new project includes a properly configured Android manifest to prevent the Android menu bars from appearing. However, I noticed that w ...

GSON simplifies mapping data to different fields in a flat structure

I am currently working on an Android app that utilizes Retrofit for API calls. Within my code, I have a class structure as shown below: class Foo { String bar; Map<String, String> map; } When GSON serializes this class into JSON, it produces t ...

How come modifications to a node package are not reflected in a React.js application?

After running "npm install" to install node modules, I made some changes to a module. The modifications are highlighted in a red rectangle. https://i.sstatic.net/KXdye.png The "find" command line tool only detected one file with that name. Next, I launc ...

The element possesses an implicit 'any' type as the expression containing 'string' cannot index the type '{}'

Question: I encountered the error "No index signature with a parameter of type 'string' was found on type '{}'. Below is the code snippet where the error occurred: const dnsListObj = {}; for (const key of dnsList) { dnsLis ...

How to prompt device to seek user permission again with ios 13 DeviceOrientationEvent.requestPermission

Apple introduced the API DeviceOrientationEvent.requestPermission in iOS 13, requiring user action to trigger it such as a click or tap. The issue I'm facing is that once the user denies permission, the result appears to be cached, preventing me from ...

Using app.get('env') in local development and live production settings

var express = require('express'); var app = express(); var db_url; if(app.get('env') == "development"){ db_url = 'mongodb://127.0.0.1:27017/localhost'; }else{ db_url = 'something else'; } console.log(app.get(&apos ...

What are the differences between using .val() and .innerHTML?

When working with JQuery and trying to access elements, I have noticed that the method for retrieving content differs depending on the element type. For example, if I have a form with a textarea and want to get the text inside of it, I would use $("textare ...

The React Native app mysteriously crashes repeatedly without generating any error logs when using the same component multiple

Currently, I am developing in React Native app Version 0.70. Encountering a peculiar issue where the React Native app crashes without any error logs in the console. Below is the snippet of my code where most crashes seem to happen: import { ...

AngularJS is throwing a RangeError, indicating that the time value is invalid when calling Date.toISOString

For my project, I need to display the date picker in jQuery (angular-jquery-datepicker) with the date formatted correctly for the user's timezone. I can successfully show dates in both USA and EU formats. When the user sets these dates, I have to save ...

What is the reason for the PHP condition not functioning properly unless I explicitly echo the variable?

When the variable is echoed in the code below, the condition works, but if it's not echoed, the condition fails to work. What could be causing this issue? The original code snippet: $msg=$_SESSION['$msg']; echo $msg; if($msg != null){ ?> ...

Are you experiencing issues with emojis not displaying correctly in the Facebook JSON data?

Spent countless hours scouring through questions and answers on various tech platforms, but I still can't seem to crack this issue. Let's dive into the problem at hand, shall we? Take a look at this JSON object extracted from Facebook's down ...

Having trouble getting the lightning to cooperate

Currently, I am diving into three.js and encountered a baffling issue. I successfully created a cube that responds to the A and D keys for rotation, but I am struggling to implement proper lighting. Despite referencing several examples and attempting to re ...

Distinguishing between native and custom error objects: a comprehensive guide

When working with errors in my node app, I find it challenging to handle both custom and native errors seamlessly. Errors are not just ordinary JavaScript objects, which adds complexity to error handling. To manage custom errors, I am experimenting with t ...

Struggling to convert a CSV file into an array of objects

I have stored CSV files in my application and now I need to convert them into an array of objects using csv-parse. You can find more information about csv-parse here. When I try to require the csv file, I encounter the following error: Error: Ingredient ...

What is the reason behind the inability to set a maximum width for containers?

Here's a piece of XML code that I'm working with, and I need to figure out how to set the max width for the linear layout to 600dp. Why is it that Android doesn't allow this kind of customization? EDIT: The main question here is not about h ...

Is it possible to create a destructor specifically for handling RXJS Observables?

I am working on an Angular application where I need to receive SSE events from a server and then process the data. After some research, I came across a solution that involves wrapping the SSE EventSource into an Observable. Here is the code snippet: impor ...

Implement CSRF protection for wicket ajax requests by adding the necessary header

I'm currently working on a website created with Apache Wicket and we're looking to enhance its security by implementing CSRF protection. Our goal is to keep it stateless by using a double submit pattern. For forms, we are planning to include a h ...

Searching through a MySQL array with a deductive filter using either PHP or JavaScript

Looking for a way to filter an array using a four step process based on three conditions. Here is an example of the array pulled from the database: Array ( [0] => Array ( [playlist_id] => 199 [playlist_name] => Christmas [playlist_status] => ...

Invoking a PHP class through an AJAX response handler code

I'm attempting to access a PHP-File using AJAX. When I use a basic PHP-File like this: <?php header('Content-Type: text/html; charset=utf-8'); header('Cache-Control: must-revalidate, pre-check=0, no-store, no-cache, max-age=0, pos ...

What is the best way to ensure that a status is updated only when needed in a JavaScript code?

Recently, I've been working on a project to develop a 5th Edition D&D Character Generator App (I know, nerdy but fun!). One challenge I'm facing is how to ask specific questions based on the character's level without repeating all previous q ...