# loadImage() with base64 encoded jpg

**URL:** <https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681>\
**Category:** Electronics (Arduino, etc.)\
**Created:** [January 3, 2026, 10:20am UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681 "2026-01-03T10:20:09Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![papertree](https://avatars.discourse-cdn.com/v4/letter/p/46a35a/32.png) [@papertree](https://discourse.processing.org/u/papertree)\
**Post date:** [January 3, 2026, 10:20am UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/1 "2026-01-03T10:20:09Z")

</div>

I am writing a program that gets an image encoded in base64 through the Serial port. I want to then load that image in my Processing program to analyze it.

It seems that loadImage() should work with base64 encoded data, provided you use the right header ([reference](https://github.com/processing/processing/pull/5933)), but even the gist used in the pull request throws a `NullPointerException`.

I have checked out the discussions i will post on a comment (this forum only lets new users post 2 links per post, for some reason) but nothing seems to work. I get either `NullPointerException` or `IllegalArgumentException`. Any help would be appreciated!

Here’s my code:

```auto
import processing.serial.*;

import java.awt.Image;
import java.awt.Toolkit;
import java.util.Base64;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;

processing.serial.Serial myPort;
String val;
PImage feed;
PrintWriter debug;

void setup(){
  size(800, 800);
  //print(Serial.list());
  String portName = "COM3";
  
  debug = createWriter("debug.txt");
  
  myPort = new processing.serial.Serial(this, portName, 2000000);

}

void draw(){
  background(0);
  if(myPort.available() > 0){
    val = myPort.readStringUntil('\n');
    if(val != null){
      println(" _______________________");
      debug.println(val.substring(873)); //Get rid of a bunch of characters prior to the base64 image
      val = val.substring(val.indexOf("/"));
      println(val.length());

      if(val.startsWith("/")){
        
        //This throws NullPointerException on image(feed, 0, 0)
          //String data = "data:image/jpg;base64,"+val;
          //feed = loadImage(data);
        
        try {
          feed = DecodePImageFromBase64(val);
        } 
        catch (IOException e) {
          println(e);
        }
        
        image(feed, 0, 0);
      }
    }
  }
}

public PImage DecodePImageFromBase64(String i_Image64) throws IOException
{
  PImage result = null;
  byte[] decodedBytes = Base64.getDecoder().decode(i_Image64);
  println("Base64");

  ByteArrayInputStream in = new ByteArrayInputStream(decodedBytes);
  BufferedImage bImageFromConvert = ImageIO.read(in);
  BufferedImage convertedImg = new BufferedImage(bImageFromConvert.getWidth(), bImageFromConvert.getHeight(), BufferedImage.TYPE_INT_ARGB);
  convertedImg.getGraphics().drawImage(bImageFromConvert, 0, 0, null);
  result = new PImage(convertedImg);

  return result;
}

void keyPressed() {
  debug.flush(); // Writes the remaining data to the file
  debug.close(); // Finishes the file
  exit(); // Stops the program
}

```

I know I am getting the right serial data because I get it printed to a .txt file, and converting it with [this tool](https://onlinejpgtools.com/convert-base64-to-jpg) gives me a valid image.

Using the code above, I get one of two errors:

1. IllegalArgumentException: Input byte array has incorrect ending byte at 145536
2. IllegalArgumentException: Input byte array has wrong 4-byte ending unit

I will also post an example of an encoded image.

---

<div class="post-metadata">

**Author:** ![papertree](https://avatars.discourse-cdn.com/v4/letter/p/46a35a/32.png) [@papertree](https://discourse.processing.org/u/papertree)\
**Post date:** [January 3, 2026, 10:20am UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/2 "2026-01-03T10:20:50Z")

</div>

Here are the discussions I checked out (1/3)  
[this discussion](https://discourse.processing.org/t/use-loadimage-with-base64-encoded-png/5897), [this discussion](https://forum.processing.org/one/topic/how-to-load-an-image-in-base64-with-processing-js.html)

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 3, 2026, 8:55pm UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/4 "2026-01-03T20:55:06Z")

</div>

Hello @papertree,

Welcome to the forum.

Assuming the system silenced you automatically for _enthusiasm_ and you will be back soon!

I simplified your code without the serial and this works on my end:

```processing
import java.awt.Image;
import java.awt.Toolkit;
import java.util.Base64;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;

PImage feed;

String val = "data:image/jpeg;base64,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";

void setup() 
  {
  size(200, 200);
  noLoop();
  }

void draw() 
  {
  background(0);

  // Remove the "data:image/jpeg;base64," prefix (if exists)
  if (val.startsWith("data:image/jpeg;base64,"))
    {
    val = val.substring("data:image/jpeg;base64,".length());
    //println(base64Str);
    //println();
    }

  try 
    {
    feed = DecodePImageFromBase64(val);
    }
  catch (IOException e) 
    {
    println(e);
    }

  image(feed, 0, 0);
  }

public PImage DecodePImageFromBase64(String i_Image64) throws IOException
  {
  PImage result = null;
  byte[] decodedBytes = Base64.getDecoder().decode(i_Image64);
  println("Base64");

  ByteArrayInputStream in = new ByteArrayInputStream(decodedBytes);
  BufferedImage bImageFromConvert = ImageIO.read(in);
  BufferedImage convertedImg = new BufferedImage(bImageFromConvert.getWidth(), bImageFromConvert.getHeight(), BufferedImage.TYPE_INT_ARGB);
  convertedImg.getGraphics().drawImage(bImageFromConvert, 0, 0, null);
  result = new PImage(convertedImg); //Depracated but works

  return result;
  }

```

![test](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/0/9/095f2bfdc969be328c4c2ba0de7558efb733a496.jpeg)

I used this to create the encoded string:

> **[Base64 Image Encoder](https://www.base64-image.de/)**
>
> Optimize your images and convert them to base64 online. Drag & Drop your files, copy to clipboard with a click and use the result in HTML and CSS.

`:)`

---

<div class="post-metadata">

**Author:** ![papertree2](https://avatars.discourse-cdn.com/v4/letter/p/9f8e36/32.png) [@papertree2](https://discourse.processing.org/u/papertree2)\
**Post date:** [January 5, 2026, 10:59am UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/5 "2026-01-05T10:59:39Z")

</div>

Hi,  
Since the Forum wouldn’t give me access again, and I am really hitting a wall with this, I had to create another account..

Your sketch works for me too, yay! I since discovered that, since I changed the code that took and encoded the images, the base64 strings I was receiving through the Serial port were missing some characters, which meant that they weren’t valid files anyway.

However, I am now getting 100% correct strings, and the encoder still doesn’t work. Here’s an example of a base64 encoded jpeg file, and here’s my current sketch:

```java
import processing.serial.*;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.Base64;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;

processing.serial.Serial myPort;

PImage feed = null;

String val = "";

void setup() 
  {
  size(320, 240);
  String portName = "COM3";
  myPort = new processing.serial.Serial(this, portName, 115200);

  
  //noLoop();
  }

void draw() 
  {
  background(0);
  if(myPort.available() > 0){
  
    val = myPort.readStringUntil('\n');
    if(val != null){
      println(val); //THIS prints a correct base64-encoded jpeg string
      
      // Remove the "data:image/jpeg;base64," prefix (if exists)
      if (val.startsWith("data:image/jpeg;base64,"))
        {
        val = val.substring("data:image/jpeg;base64,".length());
        }
    
      try 
        {
        feed = DecodePImageFromBase64(val);
        }
      catch (IOException e) 
        {
        println(e);
        }
    
      image(feed, 0, 0);
    }
  }
}

public PImage DecodePImageFromBase64(String i_Image64) throws IOException{
  PImage result = null;
  println(i_Image64);//THIS prints a correct base64-encoded jpeg string

  byte[] decodedBytes = Base64.getDecoder().decode(i_Image64); //IllegalArgumentException: Input byte array has incorrect ending byte at 6372. String is correct JPG
  println(decodedBytes.length);

  ByteArrayInputStream in = new ByteArrayInputStream(decodedBytes);
  BufferedImage bImageFromConvert = ImageIO.read(in);
  BufferedImage convertedImg = new BufferedImage(bImageFromConvert.getWidth(), bImageFromConvert.getHeight(), BufferedImage.TYPE_INT_ARGB);
  convertedImg.getGraphics().drawImage(bImageFromConvert, 0, 0, null);
  result = new PImage(convertedImg); //Depracated but works

  return result;
}

```

As you can see, I just edited your code to add the Serial reading. The `println(val)` before sending it to the `DecodePImageFromBase64()` function prints a valid base64-encoded jpeg string, and the `println(i_Image64)` prints the exact same string, but `Base64.getDecoder().decode(i_image64)` throws `Input array has incorrect ending byte` OR `Illegal base64 character d` (always `d`, the character never changes).

Could this be a problem of the decoder? Should I look into using another library?

---

<div class="post-metadata">

**Author:** ![sableraph](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/sableraph/32/251_2.png) [@sableraph](https://discourse.processing.org/u/sableraph)\
**Post date:** [January 6, 2026, 2:39pm UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/6 "2026-01-06T14:39:58Z")

</div>

> [@papertree2](#):
>
> Since the Forum wouldn’t give me access again, and I am really hitting a wall with this, I had to create another account..

Hi @papertree / @papertree2,

It looks like your account was mistakenly flagged by Discourse’s automatic spam detection. I have removed the flag on your original account so you should be able to log back in. Sorry for the inconvenience.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 7, 2026, 2:40am UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/7 "2026-01-07T02:40:21Z")

</div>

Hello @papertree,

If this sends the terminating character it needs to be trimmed on receiving end:  
_[https://docs.arduino.cc/language-reference/en/functions/communication/serial/println/](https://docs.arduino.cc/language-reference/en/functions/communication/serial/println/)_

Reference:  
_[trim() / Reference / Processing.org](https://processing.org/reference/trim_.html)_

Example:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/6/5/658ba54c099affb5aad55276d9b9258ef78d2157.png)

Try `while (myPort.available() > 0)` in your loop:  
_[readStringUntil() / Libraries / Processing.org](https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html)_  
Although… it may be blocking for a large frame of data ending in a `\n`.

This uses virtual COM ports on PC and works:

```processing
import processing.serial.*;

import java.awt.Image;
import java.awt.Toolkit;
import java.util.Base64;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;

processing.serial.Serial portTx;
processing.serial.Serial portRx;

String imgTxt = "data:image/jpeg;base64,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";
String val = "";

PImage feed = null;

void setup()
  {
  size(200, 200);
  println(imgTxt.length());
  //imgTxt = imgTxt + "\n";

  printArray(processing.serial.Serial.list());

  String comRx = "COM4";
  portRx = new processing.serial.Serial(this, comRx, 115200);
  portRx.clear();

  String comTx = "COM5";
  portTx = new processing.serial.Serial(this, comTx, 115200); // Fixed variable name

  //portRx.readStringUntil('\n');

  // Think of this as Arduino
  thread("txtImage"); // start thread to generate data;
  }

void draw()
  {
  //background(0);
  while (portRx.available() > 0)
    {
    //println(portRx.available());
    val = portRx.readStringUntil('\n');

    if (val != null)
      {
      val = val.trim();
      println("test");
      println(val); //THIS prints a correct base64-encoded jpeg string

      // Remove the "data:image/jpeg;base64," prefix (if exists)
      if (val.startsWith("data:image/jpeg;base64,"))
        {
        println("here", val.length());
        val = val.substring("data:image/jpeg;base64,".length());
        }
      try
        {
        feed = DecodePImageFromBase64(val);
        println("ok");
        }
      catch (IOException e)
        {
        println(e);
        }
      image(feed, 0, 0);  
      }
    }
  }

public PImage DecodePImageFromBase64(String i_Image64) throws IOException {
  PImage result = null;
  println(i_Image64);//THIS prints a correct base64-encoded jpeg string

  byte[] decodedBytes = Base64.getDecoder().decode(i_Image64); //IllegalArgumentException: Input byte array has incorrect ending byte at 6372. String is correct JPG
  println(decodedBytes.length);

  ByteArrayInputStream in = new ByteArrayInputStream(decodedBytes);
  BufferedImage bImageFromConvert = ImageIO.read(in);
  BufferedImage convertedImg = new BufferedImage(bImageFromConvert.getWidth(), bImageFromConvert.getHeight(), BufferedImage.TYPE_INT_ARGB);
  convertedImg.getGraphics().drawImage(bImageFromConvert, 0, 0, null);
  result = new PImage(convertedImg); //Depracated but works

  return result;
  }

// Think of this as the Arduino
void txtImage() {
  println("Thread 1");
  println(imgTxt.length());
  //while (true)
    {
    if (portTx != null) {
      println("Thread 2");

      // Loop through every character in the Base64 string
      for (int i = 0; i < imgTxt.length(); i++)
        {
        portTx.write(imgTxt.charAt(i));
        //println(i, imgTxt.charAt(i));
        //delay(1); // 1ms delay per character to stabilize transmission
        }

      // Send the terminal newline so readStringUntil('\n') triggers
      portTx.write('\n');
      println("Finished sending full string.");
      }
    }
  }
``'
You will not be able to run above until you have virtual COM ports available.
The code works and displays the image.

Reference:
https://en.wikipedia.org/wiki/Virtual_COM_port

``:)``
```

---

<div class="post-metadata">

**Author:** ![papertree](https://avatars.discourse-cdn.com/v4/letter/p/46a35a/32.png) [@papertree](https://discourse.processing.org/u/papertree)\
**Post date:** [January 7, 2026, 4:01pm UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/8 "2026-01-07T16:01:19Z")

</div>

@sableraph Thanks! Really appreciate it.

---

<div class="post-metadata">

**Author:** ![papertree](https://avatars.discourse-cdn.com/v4/letter/p/46a35a/32.png) [@papertree](https://discourse.processing.org/u/papertree)\
**Post date:** [January 7, 2026, 4:03pm UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/9 "2026-01-07T16:03:34Z")

</div>

Hi @glv,

I had no idea the Arduino `serial.println()` method printed a `\r` at the end of the data.

Thanks for your `trim()` suggestion inside or Processing, everything works as expected now! I haven’t encountered the `Illegal base64 character d` again, either, so that was the issue there also.

Thanks a lot again!

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 7, 2026, 8:00pm UTC](https://discourse.processing.org/t/loadimage-with-base64-encoded-jpg/47681/10 "2026-01-07T20:00:07Z")

</div>

> [@papertree](#):
>
> Thanks a lot again!

You are very welcome!

`:)`
