public static boolean convert(
      byte[] objectData,
      ImageData imageData,
      GenericColorSpace decodeColorData,
      PdfObject newSMask,
      PdfObjectReader currentPdfFile)
      throws PdfException {

    newSMask.setFloatArray(PdfDictionary.Decode, new float[] {1, 0});

    final PdfArrayIterator Filters = newSMask.getMixedArray(PdfDictionary.Filter);

    boolean isMaskJPX = false;
    // check not handled elsewhere
    int firstValue;
    if (Filters != null && Filters.hasMoreTokens()) {
      while (Filters.hasMoreTokens()) {
        firstValue = Filters.getNextValueAsConstant(true);
        // isDCT=firstValue==PdfFilteredReader.DCTDecode;
        isMaskJPX = firstValue == PdfFilteredReader.JPXDecode;
      }
    }

    byte[] objData = currentPdfFile.readStream(newSMask, true, true, false, false, false, null);

    imageData.setObjectData(objData);
    imageData.setDepth(1);
    imageData.setWidth(newSMask.getInt(PdfDictionary.Width));
    imageData.setHeight(newSMask.getInt(PdfDictionary.Height));
    int newDepth = newSMask.getInt(PdfDictionary.BitsPerComponent);

    // JPEG2000 causes us special difficulties as we not actually decoding objectData because
    // it is JPEG2000 and we decode as part of image handling because Java does byte[] to image
    // directly
    //
    // This code fixes specific example by getting the actual data and ignoring empty mask but will
    // probably need developing further if we find other examples
    if (isMaskJPX) { // see case 17665 for example
      BufferedImage img =
          decodeColorData.JPEG2000ToRGBImage(
              imageData.getObjectData(),
              imageData.getWidth(),
              imageData.getHeight(),
              null,
              -1,
              -1,
              8);
      img = ColorSpaceConvertor.convertColorspace(img, 10);

      objData = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
      imageData.setObjectData(objData);
      boolean isEmptyMask = true;
      for (final byte b : objectData) {
        if (b != 0) {
          isEmptyMask = false;
          break;
        }
      }
      if (isEmptyMask) {
        imageData.setObjectData(null);
      }

      // we need to unset this as e have handled the JPX filter
      newSMask.setMixedArray(PdfDictionary.Filter, null);
    }

    if (newDepth != PdfDictionary.Unknown) {
      imageData.setDepth(newDepth);
    }

    return objData == null;
  }
  static GenericColorSpace downSample(
      ImageData imageData, GenericColorSpace decodeColorData, int sampling, byte[] index) {

    final boolean hasIndex =
        decodeColorData.getIndexedMap() != null
            && (decodeColorData.getID() == ColorSpaces.DeviceRGB
                || decodeColorData.getID() == ColorSpaces.CalRGB
                || decodeColorData.getID() == ColorSpaces.DeviceCMYK
                || decodeColorData.getID() == ColorSpaces.ICC
                || decodeColorData.getID() == ColorSpaces.DeviceN);

    int comp;

    int indexCount = 1;

    if (hasIndex) { // convert to sRGB
      comp = 1;

      imageData.setCompCount(3);
      indexCount = 3;
      index = decodeColorData.convertIndexToRGB(index);

      // actually sRGB now so reset colorspace
      decodeColorData = new DeviceRGBColorSpace();

    } else {
      comp = decodeColorData.getColorComponentCount();
    }

    int newW = imageData.getWidth() / sampling;
    int newH = imageData.getHeight() / sampling;
    byte[] data = imageData.getObjectData();

    final int oldSize = data.length;

    int x, y, xx, yy, jj;

    int origLineLength;
    // black and white
    if (imageData.getWidth() * imageData.getHeight() == oldSize
        || decodeColorData.getID() == ColorSpaces.DeviceGray) {
      comp = 1;
    }

    final byte[] newData;

    if (hasIndex) { // hard-coded to 3 values
      newData = new byte[newW * newH * indexCount];
      origLineLength = imageData.getWidth();
    } else {
      newData = new byte[newW * newH * comp];
      origLineLength = imageData.getWidth() * comp;
    }
    // scan all pixels and down-sample
    for (y = 0; y < newH; y++) {
      for (x = 0; x < newW; x++) {

        // allow for edges in number of pixels left
        int wCount = sampling, hCount = sampling;
        final int wGapLeft = imageData.getWidth() - x;
        final int hGapLeft = imageData.getHeight() - y;
        if (wCount > wGapLeft) {
          wCount = wGapLeft;
        }
        if (hCount > hGapLeft) {
          hCount = hGapLeft;
        }

        int[] indexAv;
        for (jj = 0; jj < comp; jj++) {
          int byteTotal = 0;
          int count = 0;
          int ptr;
          final int newPtr;
          //noinspection ObjectAllocationInLoop
          indexAv = new int[indexCount];
          // count pixels in sample we will make into a pixel (ie 2x2 is 4 pixels , 4x4 is 16
          // pixels)
          for (yy = 0; yy < hCount; yy++) {
            for (xx = 0; xx < wCount; xx++) {

              ptr =
                  ((yy + (y * sampling)) * origLineLength)
                      + (((x * sampling * comp) + (xx * comp) + jj));
              if (ptr < oldSize) {
                if (!hasIndex) {
                  byteTotal += (data[ptr] & 255);
                } else {
                  for (int aa = 0; aa < indexCount; aa++) {
                    indexAv[aa] += (index[(((data[ptr] & 255) * indexCount) + aa)] & 255);
                  }
                }

                count++;
              }
            }
          }

          // set value as white or average of pixels
          if (hasIndex) {
            newPtr = jj + (x * indexCount) + (newW * y * indexCount);
            for (int aa = 0; aa < indexCount; aa++) {
              newData[newPtr + aa] = (byte) ((indexAv[aa]) / count);
            }
          } else if (count > 0) {
            newPtr = jj + (x * comp) + (newW * y * comp);
            newData[newPtr] = (byte) ((byteTotal) / count);
          }
        }
      }
    }

    imageData.setObjectData(newData);
    imageData.setWidth(newW);
    imageData.setHeight(newH);

    return decodeColorData;
  }