ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Is there a nice way to convert the built-in JPEG compressed image message to an AWT BufferedImage?

asked 2013-04-05 09:26:56 -0500

dljsjr gravatar image

updated 2013-04-05 09:28:50 -0500

Like it says on the tin, we need to process a compressed_image transport from Java code. We aren't developing on Android and so can't leverage any of the Android-specific stuff packaged in to rosjava.

Specifically, we need to go from a CompressedImage message to a native AWT BufferedImage. But to do this, we need a lot of information required to decompress the image that we can't seem to get a hold of (things like width and height, which I suppose we could get from the CameraInfo but we're trying to keep the number of subscription handlers to a minimum because they seem to be pretty heavyweight in all of our benchmarks).

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted

answered 2013-04-05 10:35:50 -0500

dljsjr gravatar image

Looks like this was as simple as using a ByteArrayInputStream and We ran in to some hiccups because we forgot to offset from the ChannelBuffer but we got it figured out.

edit flag offensive delete link more


Hey, working on the same problem, what do you mean by offset the ChannelBuffer?

Robocop87 gravatar image Robocop87  ( 2014-12-15 05:28:10 -0500 )edit

I'm having the same problem also, could you post more details about your solution?

jubeira gravatar image jubeira  ( 2017-04-11 14:28:56 -0500 )edit

answered 2017-04-17 08:01:29 -0500

jubeira gravatar image

updated 2017-04-17 08:55:31 -0500

For the record, here's the way I found to subscribe to a compressed image topic and save the received images to files using rosjava (no Android required):

public void onStart(ConnectedNode node) {
  final Log log = node.getLog();
  latch = new CountDownLatch(0);
  Subscriber<CompressedImage> subscriber = node.newSubscriber(topic, "sensor_msgs/CompressedImage");"Subscribed to " + topic);

  subscriber.addMessageListener(new MessageListener<CompressedImage>() {
      public void onNewMessage(CompressedImage message) {
"New image is here! Format: " + message.getFormat());

          if (!message.getFormat().contains("jpeg")) {
              log.warn("Only jpeg images are supported");

          // The latch allows the node to finish saving the image before a new one arrives.
          if (latch.getCount() == 0) {
              latch = new CountDownLatch(1);
              ChannelBuffer buffer = message.getData();
    "Array length: " + buffer.array().length);
              try {
                  // Look for the start of the image inside the buffer
                  // In the tests with TangoRosStreamer, the offset is always 0x3F,
                  // perhaps it's not necessary to search for the index every time.
                  int imageStart = Bytes.indexOf(buffer.array(), JPG_START);
                  if (imageStart < 0) {
                      throw new Exception("Invalid JPG format: start not found");

                  File outputFile = new File("image_" + Integer.toString(imgNumber) + ".jpg");
                  OutputStream outStream = new FileOutputStream(outputFile);
                  outStream.write(buffer.array(), imageStart, buffer.array().length - imageStart);
        "Wrote file");
              } catch (Exception e) {
                  System.out.println("Listener exception: " + e.getClass() + " msg: " + e.getMessage());
              } finally {

The byte array can also be converted to a BufferedImage after getting the index of the start (see this answer: )

edit flag offensive delete link more

Question Tools


Asked: 2013-04-05 09:26:56 -0500

Seen: 1,073 times

Last updated: Apr 17 '17