jobject createFromDataWrapper()

in animated-gif/src/main/jni/gifimage/gif.cpp [681:763]


jobject createFromDataWrapper(JNIEnv* pEnv, std::shared_ptr<DataWrapper> spDataWrapper, int maxDimension, bool forceStatic) {
  std::unique_ptr<GifImageNativeContext> spNativeContext(new GifImageNativeContext());
  if (!spNativeContext) {
    throwOutOfMemoryError(pEnv, "Unable to allocate native context");
    return 0;
  }

  int gifError = 0;
  auto spGifFileIn = std::unique_ptr<GifFileType, decltype(&DGifCloseFile2)> {
      DGifOpen(
          (void*) spDataWrapper.get(),
          &directByteBufferReadFun,
          &gifError),
      DGifCloseFile2
  };

  if (spGifFileIn == nullptr) {
    throwIllegalStateException(pEnv, "Error %d", gifError);
    return nullptr;
  }

  int width = spGifFileIn->SWidth;
  int height = spGifFileIn->SHeight;
  size_t wxh = width * height;
  if (wxh < 1 || wxh > SIZE_MAX || width > maxDimension || height > maxDimension) {
    throwIllegalStateException(pEnv, "Invalid dimensions");
    return nullptr;
  }

  // Create the GifWrapper
  spNativeContext->spGifWrapper = std::shared_ptr<GifWrapper>(
    new GifWrapper(std::move(spGifFileIn), spDataWrapper));

  GifFileType* pGifFile = spNativeContext->spGifWrapper->get();

  spNativeContext->pixelWidth = width;
  spNativeContext->pixelHeight = height;

  int error = modifiedDGifSlurp(spNativeContext->spGifWrapper.get(), maxDimension, forceStatic);
  if (error != GIF_OK) {
    throwIllegalStateException(pEnv, "Failed to slurp image %d", error);
    return nullptr;
  }

  if (pGifFile->ImageCount < 1) {
    throwIllegalStateException(pEnv, "No frames in image");
    return nullptr;
  }
  spNativeContext->numFrames = pGifFile->ImageCount;

  // Compute cached fields that require iterating the frames.
  int durationMs = 0;
  std::vector<jint> frameDurationsMs;
  ReaderLock rlock_{spNativeContext->spGifWrapper->getSavedImagesRWLock()};
  for (int i = 0; i < pGifFile->ImageCount; i++) {
    SavedImage* pSavedImage = &pGifFile->SavedImages[i];
    GraphicsControlBlock gcp;
    if (getGraphicsControlBlockForImage(pSavedImage, &gcp)) {
      int frameDurationMs = gcp.DelayTime * 10;
      durationMs += frameDurationMs;
      frameDurationsMs.push_back(frameDurationMs);
    } else {
      frameDurationsMs.push_back(0);
    }
  }
  spNativeContext->durationMs = durationMs;
  spNativeContext->frameDurationsMs = frameDurationsMs;

  // Cache loop count
  spNativeContext->loopCount = spNativeContext->spGifWrapper->getLoopCount();

  // Create the GifImage with the native context.
  jobject ret = pEnv->NewObject(
      sClazzGifImage,
      sGifImageConstructor,
      (jlong) spNativeContext.get());
  if (ret != nullptr) {
    // Ownership was transferred.
    spNativeContext->refCount = 1;
    spNativeContext.release();
  }
  return ret;
}