Reading and Converting JPEG image to String from SD Card Arduino Yun

Hello,

I am trying to read and convert a jpeg image into string to be encoded in base64 in my Arduino Yun's SD card. However, while(picture.available()) is looping forever. I am not sure if I'm not reading the picture correctly using the picture.read() method. Is it possible to read a jpeg image using picture.read() method? I am sharing my code below, any help would be appreciated.

File picture = FileSystem.open("/mnt/sda1/test.jpg");
  
  if(picture){
    Serial.println("not error");
  
    while(picture.available()){
      Serial.println(picture.available());
      c = picture.read();
      s = s + String(c);
      Serial.println(s);
    }
    //picture.close();
  }
  
  s = "";
  
  char pictureArray[s.length()];
  s.toCharArray(pictureArray,s.length());
  
  char outputArray[s.length()];
    
  base64_encode(outputArray,pictureArray,s.length());
      s = s + String(c);

Stop RIGHT NOW. Go look at the String class if you really must use it. There is no reason to wrap a character in a String instance, causing the constructor, the copy operator, and the destructor to poke holes in memory, in order to concatenate a single character onto a String.

      Serial.println(s);

What are you REALLY expecting to see when printing a String built from binary data?

  base64_encode(outputArray,pictureArray,s.length());

Is this function really going to convert an entire jpeg "string" in one block?

PaulS:

      s = s + String(c);

Stop RIGHT NOW. Go look at the String class if you really must use it. There is no reason to wrap a character in a String instance, causing the constructor, the copy operator, and the destructor to poke holes in memory, in order to concatenate a single character onto a String.

::::SNIP::::

@PaulS,
I've seen this before. Often in other languages (ie. php) a function like String() is used to cast an object in to a type. As such, this is a common misunderstanding with C++. You may want to point the OP toward some sort of tutorial on this.

Jesse

yagiz23:
I am trying to read and convert a jpeg image into string to be encoded in base64 in my Arduino Yun's SD card.

You're using a sketch to read an entire file into memory, and then convert it into a BASE64 string. By definition, the result will be twice as big as the image. That means you will need memory that is three times the image size just for the image and converted data, plus you need memory for your other variables, the file I/O buffers, stack, serial buffers, etc. you have a max of 2.5 k bytes of RAM available to your sketch. I hope your image is no more than a few hundred bytes, or it simply won't fit.

This operation is simply NOT appropriate to perform in a sketch. You've got a powerful Linux system on the other end of the Bridge interface, this is a perfect time to use it. Linux includes a base64 command that will do the conversion for you with no further programming. Someone who is more familiar with Linux (sonnyyu?) can help with the command syntax, whether it is installed by default on the Yun, and how to install it if it's not. (I'm away from the Yun at the moment and can't check.)

Each if the two processors on the Yun have their strengths and weaknesses. In the case of the '32U4 running the sketch, real time operations are it's strength, but churning through data is a definite weakness. The Linux processor, however, loves tasks like churning through data and converting files.

opkg update
opkg install coreutils-base64
cd /www
wget -O yun.jpg http://arduino.cc/en/uploads/Main/ArduinoYunFront_2_450px.jpg

Convert to Base64:

/usr/bin/base64 /www/yun.jpg >/www/yun.base64

Convert back to Jpg:

/usr/bin/base64 -d /www/yun.base64 > /www/yun_convert.jpg

confirm it works by browse at "http://arduino.local/yun_convert.jpg"

Put it at script:

nano /mnt/sda1/base64.sh
#!/bin/ash
/usr/bin/base64 $1 > $2
chmod 755 /mnt/sda1/base64.sh

ATmega32u4 code:

void ConvertBase64(String jpgpath, String base64path) {
 Process p;              
 p.begin("/mnt/sda1/base64.sh");      
 p.addParameter(jpgpath); 
 p.addParameter(base64path); 
 p.run();
 while(p.running());  
}

Now we shift heave lift from ATmega32u4 to AR9331.

Sonnyyu thank your for your help. Do the code you provided convert a jpeg image into string? I have not tried the base64_encode function yet but I have seen from the internet that it has no problem encoding a string. My problem is reading an image into string.

yagiz23:
Sonnyyu thank your for your help. Do the code you provided convert a jpeg image into string? I have not tried the base64_encode function yet but I have seen from the internet that it has no problem encoding a string. My problem is reading an image into string.

The code convert jpg file to base64 file, at ATmega32u4 you could read base64 file directly into string.

You might give us more detail what you want to do, we could give you better advice.

yagiz23:
My problem is reading an image into string.

Why do you want to do that?

Re-read my comments above. Unless it's a VERY small image, you CAN'T read it into a string in your sketch. You don't have enough memory. You will either need to do something different (work on parts of the image at a time) or you will need to do it on the Linux side. A sketch running on the '32U4 is not an appropriate way to do image processing. It's like trying to move your household on the back of a little motor scooter, when what you really need is a large truck.

If we new WHY you need to read the image into a string, we may be able to give you advice on a better way to do it. At this point we can only guess what's you're trying to do, and my pretty good guess is that it won't work.

If the Python PIL library works on the Yun it provides a very simple way to manipulate images.

...R

Robin2:
If the Python PIL library works on the Yun it provides a very simple way to manipulate images.

...R

Yes, It does.

opkg update
opkg install python-imaging-library

I will try the code to make the conversion at the Linux side as Sonnyyu posted. My aim is to convert a jpeg image into a base64 string and then upload to firebase. Is it possible to manipulate the python script to return an encoded string in Arduino environment and then use Arduino's methods to upload to Firebase?

yagiz23:
Is it possible to manipulate the python script to return an encoded string in Arduino environment and then use Arduino's methods to upload to Firebase?

The Python script will translate the image file into a base64 encoded file. The Arduino script could then use the FileIO class to read that text file and transfer it to Firebase, but that is another operation that is likely to be easier and more efficient if done by a Linux process. The Arduino sketch will still have to read and process small chunks of the data, it won't be able to read it (or transfer it) all at once.

That's why we are asking what you are ultimately going to do with the file. Unless you NEED the data in the Arduino sketch for some reason, it's probably easiest (and definitely fastest) to do the large data manipulation and network communications on the Linux side.

Someone more versed in Linux (like sonnyyu or jessemonroy650) will have suggestions on how you can easily accomplish this, probably with only a line or two of a shell script (as opposed to a few dozen lines of Arduino sketch.)

My plan was to convert the jpeg image to a base64 encoded string and then send it to Firebase via Bridge library's runShellCommand method. If there are other efficient methods of doing this task only on the linux side, then I appreciate your advice. I will keep you posted about the results of Sonnyyu's proposed method.

yagiz23:
If there are other efficient methods of doing this task only on the linux side, then I appreciate your advice.

You may be interested in develop on PC deploy on Yun which does not use the bridge at all and treats the Linux side more like a regular PC.

...R

Thanks to Sonnyyu, I have managed to convert the jpeg image into base64 string and save it as a text file in Yun's SD card. Now my problem is that I cannot read the entire text file into a single string so that I can use this string to use in the process to upload to Firebase. I am sharing the code I am using to upload an arbitrary String to Firebase.

  firebase.runShellCommand("curl -k -X PATCH https://shms.firebaseio.com/.json --data '{ \"yun\" : \"Temperature: " +String(t)+ " oC Humidity: " +String(h)+ " %                    Heat Index: " +String(hi)+ " oC FlammableGasLevel: " +String(gasSensorValue)+ " ppm" "\"  }'");
while(firebase.running());

Is there a way of uploading the base64 text directly to Firebase from the linux environment and/or reading the entire text file as a single string in the arudino environment?

Thank you

Just a question, why dont you upload the image as a .jpg from the linux side? Why do you need base64?

Because Firebase uses strings, and on the other side I have an Android application taking a base64 string and converting to jpeg from the database.

yagiz23:
Is there a way of uploading the base64 text directly to Firebase from the linux environment

Yes. Your sketch is running a curl command to do the update. That command is actually being performed on the Linux side. You just need a script file to put all of the parameters in.

I would suggest writing a Python script that accepts parameters for your sensor data. The script does the formatting of that data, and the processing of the image, and issues the curl command to do the update. Then, your sketch collects the sensor data, and uses the Process object to run your Python script, passing your sensor data as unformatted parameters. The Python does the rest.

With a setup like this, the sketch does what it's good at: real time control and sensor data collection, and the Linux side does what it's good at: formatting data, processing images, and making network requests.

or reading the entire text file as a single string in the arudino environment?

It's not going to happen. Unless it's a VERY small image file, the Arduino processor simply doesn't have the memory to read in the entire file. There is only 2.5 k bytes of memory, and that is for the stack, and all of your other variables as well. You have to get past the idea of loafing the image file into the sketch, it simply isn't going to happen.

yagiz23:
::::SNIP::::

Is there a way of uploading the base64 text directly to Firebase from the linux environment and/or reading the entire text file as a single string in the arudino environment?

Thank you

@yagiz23,
I guess people were not clear on this. Forget about the "String()" thing. The base64 utility converts the entire file in ONE pass so there is no need to make it strings. And to be clear, firebase can handle the entire file just as long as you give the data in the correct fashion.

To be extra clear, firebase does want all it's data in strings, but it does NOT care how long the string is because anything over 10Megabytes gets truncated. Lastly, I do not expect any single image you have to be larger that 10megabytes. In the worst possible case we will split a file into pieces, if needed.

So, let's just accomplish the task.

Google: firebase store file

The first link explains (in abstract) what you need to do and the limitations.

In the end, you'll need to use the firebase REST API to store your images(files). In your case you'll want to use PUT, not POST in your API call. You can use POST, but then you'll need to remember the key the return to you after every API call. We'll skip that for now.

On the Linux side, SonnyYu gave you most of the instructions, see post #4. After you have converted the jpeg image to a text file, you just upload it to firebase using curl.

So the next step is to use CURL.

Generically, here is you call:

$ curl -X PUT -d @<filename_of_base64text> https://.firebase.io.com/images/.json

At this point, all you need to do is replace the items in between the angle brackets "<>".

START NEW
Okay. One problem, that even I forgot, is that firebase wants to see everything as JSON. That means you will need to modify the base64 file. Basically double quote the label and the value and wrap it in curly braces. Like this:

{"image":"iVBORw0KGgoAAAA....kJggg=="}

I'm sorry I forgot to mention this earlier. I've been bouncing back and forth between, the YUN, my blog and phonegap stuff.... I just forgot this. Sorry again.

END NEW
I hope this is clear. If not, please ask more questions.

Okay. I made a mistake here. I'll get you the correct call in a bit. 8:15pm local time
Okay, I've added new information that should fix the problem. 8:55pm

Jesse