if (numColors == 0)
if (numColors == 0 && bytesPixel == 4)
  void handleTightRect(int x, int y, int w, int h) throws Exception {    int comp_ctl = rfb.is.readUnsignedByte();    // Flush zlib streams if we are told by the server to do so.    for (int stream_id = 0; stream_id < 4; stream_id++) {      if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) {        tightInflaters[stream_id] = null;      }      comp_ctl >>= 1;    }    // Check correctness of subencoding value.    if (comp_ctl > rfb.TightMaxSubencoding) {      throw new Exception("Incorrect tight subencoding: " + comp_ctl);    }    // Handle solid-color rectangles.    if (comp_ctl == rfb.TightFill) {      byte[] buf = new byte[3];      rfb.is.readFully(buf);      Color bg = new Color(buf[0] & 0xFF, buf[1] & 0xFF, buf[2] & 0xFF);      memGraphics.setColor(bg);      memGraphics.fillRect(x, y, w, h);      scheduleRepaint(x, y, w, h);      return;    }    if (comp_ctl == rfb.TightJpeg) {      // Read JPEG data.      byte[] jpegData = new byte[rfb.readCompactLen()];      rfb.is.readFully(jpegData);      // Create an Image object from the JPEG data.      Image jpegImage = Toolkit.getDefaultToolkit().createImage(jpegData);      // Remember the rectangle where the image should be drawn.      jpegRect = new Rectangle(x, y, w, h);      // Let the imageUpdate() method do the actual drawing, here just      // wait until the image is fully loaded and drawn.      synchronized(jpegRect) {        Toolkit.getDefaultToolkit().prepareImage(jpegImage, -1, -1, this);        try {          // Wait no longer than three seconds.          jpegRect.wait(3000);        } catch (InterruptedException e) {          throw new Exception("Interrupted while decoding JPEG image");        }      }      // Done, jpegRect is not needed any more.      jpegRect = null;      return;    }    // Read filter id and parameters.    int numColors = 0, rowSize = w;    byte[] palette8 = new byte[2];    int[] palette24 = new int[256];    boolean useGradient = false;    if ((comp_ctl & rfb.TightExplicitFilter) != 0) {      int filter_id = rfb.is.readUnsignedByte();      if (filter_id == rfb.TightFilterPalette) {        numColors = rfb.is.readUnsignedByte() + 1;        byte[] buf = new byte[numColors * 3];        rfb.is.readFully(buf);        for (int i = 0; i < numColors; i++) {          palette24[i] = ((buf[i * 3] & 0xFF) << 16 |              (buf[i * 3 + 1] & 0xFF) << 8 |              (buf[i * 3 + 2] & 0xFF));        }        if (numColors == 2)          rowSize = (w + 7) / 8;      } else if (filter_id == rfb.TightFilterGradient) {        useGradient = true;      } else if (filter_id != rfb.TightFilterCopy) {        throw new Exception("Incorrect tight filter id: " + filter_id);      }    }    if (numColors == 0)      rowSize *= 3;    // Read, optionally uncompress and decode data.    int dataSize = h * rowSize;    if (dataSize < rfb.TightMinToCompress) {      // Data size is small - not compressed with zlib.      if (numColors != 0) {        // Indexed colors.        byte[] indexedData = new byte[dataSize];        rfb.is.readFully(indexedData);        if (numColors == 2) {          // Two colors.          decodeMonoData(x, y, w, h, indexedData, palette24);        } else {          // 3..255 colors.          int i = 0;          for (int dy = y; dy < y + h; dy++) {            for (int dx = x; dx < x + w; dx++) {              pixels24[dy * rfb.framebufferWidth + dx] =                  palette24[indexedData[i++] & 0xFF];            }          }        }      } else if (useGradient) {        // "Gradient"-processed data        byte[] buf = new byte[w * h * 3];        rfb.is.readFully(buf);        decodeGradientData(x, y, w, h, buf);      } else {        // Raw truecolor data.        byte[] buf = new byte[w * 3];        int i, offset;        for (int dy = y; dy < y + h; dy++) {          rfb.is.readFully(buf);          offset = dy * rfb.framebufferWidth + x;          for (i = 0; i < w; i++) {            pixels24[offset + i] =                (buf[i * 3] & 0xFF) << 16 |                (buf[i * 3 + 1] & 0xFF) << 8 |                (buf[i * 3 + 2] & 0xFF);          }        }      }    } else {      // Data was compressed with zlib.      int zlibDataLen = rfb.readCompactLen();      byte[] zlibData = new byte[zlibDataLen];      rfb.is.readFully(zlibData);      int stream_id = comp_ctl & 0x03;      if (tightInflaters[stream_id] == null) {        tightInflaters[stream_id] = new Inflater();      }      Inflater myInflater = tightInflaters[stream_id];      myInflater.setInput(zlibData);      try {        if (numColors != 0) {          // Indexed colors.          byte[] indexedData = new byte[dataSize];          myInflater.inflate(indexedData);          if (numColors == 2) {            // Two colors.            decodeMonoData(x, y, w, h, indexedData, palette24);          } else {            // More than two colors.            int i = 0;            for (int dy = y; dy < y + h; dy++) {              for (int dx = x; dx < x + w; dx++) {                pixels24[dy * rfb.framebufferWidth + dx] =                    palette24[indexedData[i++] & 0xFF];              }            }          }        } else if (useGradient) {          // Compressed "Gradient"-filtered data.          byte[] buf = new byte[w * h * 3];          myInflater.inflate(buf);          decodeGradientData(x, y, w, h, buf);        } else {          // Compressed truecolor data.          byte[] buf = new byte[w * 3];          int i, offset;          for (int dy = y; dy < y + h; dy++) {            myInflater.inflate(buf);            offset = dy * rfb.framebufferWidth + x;            for (i = 0; i < w; i++) {              pixels24[offset + i] =                  (buf[i * 3] & 0xFF) << 16 |                  (buf[i * 3 + 1] & 0xFF) << 8 |                  (buf[i * 3 + 2] & 0xFF);            }          }        }      } catch (DataFormatException dfe) {        throw new Exception(dfe.toString());      }    }    handleUpdatedPixels(x, y, w, h);    scheduleRepaint(x, y, w, h);  }