How to translate byte[] to PImage?

edited February 2016 in Library Questions

in Server sketch, i take a picture with Processing’s Video library and send a byte array to client’s buffer

like this,,

/**
void mousePressed() {
 capture.save(“temp.jpg");
 byte[] b=loadBytes(“temp.jpg");
 server.write(b);
} 
*/

but i have no idea how to convert this byte array to PImage format in Client’s sketch.

is there any byte[] to Pimage converting method in processing???

Answers

  • There does not appear to be one, but here is the relevant code that Processing uses to load in jpg files:

    // For jpeg, gif, and png, load them using createImage(),
        // because the javax.imageio code was found to be much slower.
        // http://dev.processing.org/bugs/show_bug.cgi?id=392
        try {
          if (extension.equals("jpg") || extension.equals("jpeg") ||
              extension.equals("gif") || extension.equals("png") ||
              extension.equals("unknown")) {
            byte bytes[] = loadBytes(filename);
            if (bytes == null) {
              return null;
            } else {
              //Image awtImage = Toolkit.getDefaultToolkit().createImage(bytes);
              Image awtImage = new ImageIcon(bytes).getImage();
    
              if (awtImage instanceof BufferedImage) {
                BufferedImage buffImage = (BufferedImage) awtImage;
                int space = buffImage.getColorModel().getColorSpace().getType();
                if (space == ColorSpace.TYPE_CMYK) {
                  System.err.println(filename + " is a CMYK image, " +
                                     "only RGB images are supported.");
                  return null;
                  /*
                  // wishful thinking, appears to not be supported
                  // https://community.oracle.com/thread/1272045?start=0&tstart=0
                  BufferedImage destImage =
                    new BufferedImage(buffImage.getWidth(),
                                      buffImage.getHeight(),
                                      BufferedImage.TYPE_3BYTE_BGR);
                  ColorConvertOp op = new ColorConvertOp(null);
                  op.filter(buffImage, destImage);
                  image = new PImage(destImage);
                  */
                }
              }
    
              PImage image = new PImage(awtImage);
              if (image.width == -1) {
                System.err.println("The file " + filename +
                                   " contains bad image data, or may not be an image.");
              }
    
              // if it's a .gif image, test to see if it has transparency
              if (extension.equals("gif") || extension.equals("png") ||
                  extension.equals("unknown")) {
                image.checkAlpha();
              }
    
    //          if (params != null) {
    //            image.setParams(g, params);
    //          }
              return image;
            }
          }
        } catch (Exception e) {
          // show error, but move on to the stuff below, see if it'll work
          e.printStackTrace();
        }
    

    I must say it seems like a suboptimal way to do it. There should be no need to write a temp jpg file to disk just to load it in again (unless you need that file on your disk of course). Maybe something like server.write(capture.pixels) works. Be aware that the PImage pixels array is not the same as a jpg pixels array.

  • edited February 2016

    I must say it seems like a suboptimal way to do it.

    I hope they were careful enough to use toLowerCase() on extension: extension = extension.toLowerCase();

    http://docs.Oracle.com/javase/8/docs/api/java/lang/String.html#toLowerCase-- :-S

    If what I see is the whole code, Processing will always miss uppercase picture extension names like ".JPG", ".Png", etc.!!! 8-}

  • Yes they do, I did not post the whole loadImage() method, only the relevant part.

    For clarity I meant to say that Czerny's way was suboptimal as it involves writing a PImage to disk as a jpg (which involves taking a Fourier transform of the image), read it in again as bytes, send it to the server and convert it back to a PImage, while you could send the PImage as bytes directly using its internal pixels array.

  • edited February 2016

    Based on my solution "aRGB_Shifting_Conversion" here:
    https://forum.Processing.org/two/discussion/13411/how-to-write-a-large-int-as-as-bytes

    I did "Pixels[]_To_Byte[]_Conversion" for this thread using Server & Client too:
    https://Processing.org/reference/libraries/net/index.html

    The new extra function is from_pixels_to_byte_array(), which invokes to_aRGB_array():

    /**
     * Pixels[]_To_Byte[]_Conversion (v1.02)
     * GoToLoop (2016-Feb-08)
     *
     * forum.Processing.org/two/discussion/14814/how-to-translate-byte-to-pimage
     * forum.Processing.org/two/discussion/13792/color-bit-shifting
     * forum.Processing.org/two/discussion/13411/how-to-write-a-large-int-as-as-bytes
     */
    
    import processing.net.Server;
    import processing.net.Client;
    import processing.serial.Serial;
    
    byte[] output, input;
    int idx;
    
    void setup() {
      size(200, 150);
      noLoop();
      frameRate(100);
      background((color) random(#000000));
    
      loadPixels();
      output = from_pixels_to_byte_array(pixels);
      input = new byte[output.length];
    
      final int port = (int) random(20000, 50000);
      new Server(this, port);
      new Client(this, "localhost", port);
    
      //new Serial(this, Serial.list()[0]).write(output);
    }
    
    void draw() {
      surface.setTitle(str(idx));
    }
    
    void serverEvent(final Server s, final Client c) {
      s.write(output);
      println("We have a new client:", c.ip());
    }
    
    void clientEvent(final Client c) {
      input[idx++] = (byte) c.read();
      redraw = true;
    
      if (idx == input.length)
        println("Transmission complete! Received:"
          , idx, "bytes from"
          , width*height, "pixels");
    }
    
    static final byte[] from_pixels_to_byte_array(final color[] p, byte... t) {
      final byte[] argb = new byte[Integer.BYTES];
      final int len = p.length, size = len<<2;
    
      if (t == null || t.length < size)  t = new byte[size];
    
      for (int i = 0; i < size; i += Integer.BYTES) {
        t[i] = to_aRGB_array(p[i>>2], argb)[0];
        t[i+1] = argb[1];
        t[i+2] = argb[2];
        t[i+3] = argb[3];
      }
    
      return t;
    }
    
    static final byte[] to_aRGB_array(final color c, final byte... t) {
      final byte a = (byte) (c >>> 030);
      final byte r = (byte) (c >>  020 & 0xff);
      final byte g = (byte) (c >>  010 & 0xff);
      final byte b = (byte) (c         & 0xff);
    
      if (t == null || t.length < Integer.BYTES)  return new byte[] {a, r, g, b};
    
      t[0] = a;
      t[1] = r;
      t[2] = g;
      t[3] = b;
    
      return t;
    }
    
  • Differrent approach but same isse. I have some uuencoded PNG's and JPG's. Decoding is pretty easy. After saveByte pictures can be viewed. But I want to display them without to store them on disk. Using avtImage and conversion to PIMage failed. Any hints or ideas?

    THX f41ardu

Sign In or Register to comment.