library/src/main/java/com/felipecsl/gifimageview/library/GifDecoder.java
private Bitmap setPixels(GifFrame currentFrame, GifFrame previousFrame) {
    // Final location of blended pixels.
    final int[] dest = mainScratch;

    // clear all pixels when meet first frame
    if (previousFrame == null) {
      Arrays.fill(dest, 0);
    }

    // fill in starting image contents based on last image's dispose code
    if (previousFrame != null && previousFrame.dispose > DISPOSAL_UNSPECIFIED) {
      // We don't need to do anything for DISPOSAL_NONE, if it has the correct pixels so will our
      // mainScratch and therefore so will our dest array.
      if (previousFrame.dispose == DISPOSAL_BACKGROUND) {
        // Start with a canvas filled with the background color
        int c = 0;
        if (!currentFrame.transparency) {
          c = header.bgColor;
          if (currentFrame.lct != null && header.bgIndex == currentFrame.transIndex) {
            c = 0;
          }
        } else if (framePointer == 0) {
          // TODO: We should check and see if all individual pixels are replaced. If they are, the
          // first frame isn't actually transparent. For now, it's simpler and safer to assume
          // drawing a transparent background means the GIF contains transparency.
          isFirstFrameTransparent = true;
        }
        fillRect(dest, previousFrame, c);
      } else if (previousFrame.dispose == DISPOSAL_PREVIOUS) {
        if (previousImage == null) {
          fillRect(dest, previousFrame, 0);
        } else {
          // Start with the previous frame
          int downsampledIH = previousFrame.ih / sampleSize;
          int downsampledIY = previousFrame.iy / sampleSize;
          int downsampledIW = previousFrame.iw / sampleSize;
          int downsampledIX = previousFrame.ix / sampleSize;
          int topLeft = downsampledIY * downsampledWidth + downsampledIX;
          previousImage.getPixels(dest, topLeft, downsampledWidth,
              downsampledIX, downsampledIY, downsampledIW, downsampledIH);
        }
      }
    }

    // Decode pixels for this frame into the global pixels[] scratch.
    decodeBitmapData(currentFrame);

    int downsampledIH = currentFrame.ih / sampleSize;
    int downsampledIY = currentFrame.iy / sampleSize;
    int downsampledIW = currentFrame.iw / sampleSize;
    int downsampledIX = currentFrame.ix / sampleSize;
    // Copy each source line to the appropriate place in the destination.
    int pass = 1;
    int inc = 8;
    int iline = 0;
    boolean isFirstFrame = framePointer == 0;
    for (int i = 0; i < downsampledIH; i++) {
      int line = i;
      if (currentFrame.interlace) {
        if (iline >= downsampledIH) {
          pass++;
          switch (pass) {
            case 2:
              iline = 4;
              break;
            case 3:
              iline = 2;
              inc = 4;
              break;
            case 4:
              iline = 1;
              inc = 2;
              break;
            default:
              break;
          }
        }
        line = iline;
        iline += inc;
      }
      line += downsampledIY;
      if (line < downsampledHeight) {
        int k = line * downsampledWidth;
        // Start of line in dest.
        int dx = k + downsampledIX;
        // End of dest line.
        int dlim = dx + downsampledIW;
        if (k + downsampledWidth < dlim) {
          // Past dest edge.
          dlim = k + downsampledWidth;
        }
        // Start of line in source.
        int sx = i * sampleSize * currentFrame.iw;
        int maxPositionInSource = sx + ((dlim - dx) * sampleSize);
        while (dx < dlim) {
          // Map color and insert in destination.
          int averageColor;
          if (sampleSize == 1) {
            int currentColorIndex = ((int) mainPixels[sx]) & 0x000000ff;
            averageColor = act[currentColorIndex];
          } else {
            // TODO: This is substantially slower (up to 50ms per frame) than just grabbing the
            // current color index above, even with a sample size of 1.
            averageColor = averageColorsNear(sx, maxPositionInSource, currentFrame.iw);
          }
          if (averageColor != 0) {
            dest[dx] = averageColor;
          } else if (!isFirstFrameTransparent && isFirstFrame) {
            isFirstFrameTransparent = true;
          }
          sx += sampleSize;
          dx++;
        }
      }
    }

    // Copy pixels into previous image
    if (savePrevious && (currentFrame.dispose == DISPOSAL_UNSPECIFIED
        || currentFrame.dispose == DISPOSAL_NONE)) {
      if (previousImage == null) {
        previousImage = getNextBitmap();
      }
      previousImage.setPixels(dest, 0, downsampledWidth, 0, 0, downsampledWidth,
          downsampledHeight);
    }

    // Set pixels for current image.
    Bitmap result = getNextBitmap();
    result.setPixels(dest, 0, downsampledWidth, 0, 0, downsampledWidth, downsampledHeight);
    return result;
  }
private Bitmap setPixels(GifFrame currentFrame, GifFrame previousFrame) {
    // Final location of blended pixels.
    final int[] dest = mainScratch;

    // clear all pixels when meet first frame
    if (previousFrame == null) {
      Arrays.fill(dest, 0);
    }

    // fill in starting image contents based on last image's dispose code
    if (previousFrame != null && previousFrame.dispose > DISPOSAL_UNSPECIFIED) {
      // We don't need to do anything for DISPOSAL_NONE, if it has the correct pixels so will our
      // mainScratch and therefore so will our dest array.
      if (previousFrame.dispose == DISPOSAL_BACKGROUND) {
        // Start with a canvas filled with the background color
        int c = 0;
        if (!currentFrame.transparency) {
          c = header.bgColor;
          if (currentFrame.lct != null && header.bgIndex == currentFrame.transIndex) {
            c = 0;
          }
        } else if (framePointer == 0) {
          // TODO: We should check and see if all individual pixels are replaced. If they are, the
          // first frame isn't actually transparent. For now, it's simpler and safer to assume
          // drawing a transparent background means the GIF contains transparency.
          isFirstFrameTransparent = true;
        }
        fillRect(dest, previousFrame, c);
      } else if (previousFrame.dispose == DISPOSAL_PREVIOUS) {
        if (previousImage == null) {
          fillRect(dest, previousFrame, 0);
        } else {
          // Start with the previous frame
          int downsampledIH = previousFrame.ih / sampleSize;
          int downsampledIY = previousFrame.iy / sampleSize;
          int downsampledIW = previousFrame.iw / sampleSize;
          int downsampledIX = previousFrame.ix / sampleSize;
          int topLeft = downsampledIY * downsampledWidth + downsampledIX;
          previousImage.getPixels(dest, topLeft, downsampledWidth,
              downsampledIX, downsampledIY, downsampledIW, downsampledIH);
        }
      }
    }

    // Decode pixels for this frame into the global pixels[] scratch.
    decodeBitmapData(currentFrame);

    int downsampledIH = currentFrame.ih / sampleSize;
    int downsampledIY = currentFrame.iy / sampleSize;
    int downsampledIW = currentFrame.iw / sampleSize;
    int downsampledIX = currentFrame.ix / sampleSize;
    // Copy each source line to the appropriate place in the destination.
    int pass = 1;
    int inc = 8;
    int iline = 0;
    boolean isFirstFrame = framePointer == 0;
    for (int i = 0; i < downsampledIH; i++) {
      int line = i;
      if (currentFrame.interlace) {
        if (iline >= downsampledIH) {
          pass++;
          switch (pass) {
            case 2:
              iline = 4;
              break;
            case 3:
              iline = 2;
              inc = 4;
              break;
            case 4:
              iline = 1;
              inc = 2;
              break;
            default:
              break;
          }
        }
        line = iline;
        iline += inc;
      }
      line += downsampledIY;
      if (line < downsampledHeight) {
        int k = line * downsampledWidth;
        // Start of line in dest.
        int dx = k + downsampledIX;
        // End of dest line.
        int dlim = dx + downsampledIW;
        if (k + downsampledWidth < dlim) {
          // Past dest edge.
          dlim = k + downsampledWidth;
        }
        // Start of line in source.
        int sx = i * sampleSize * currentFrame.iw;
        int maxPositionInSource = sx + ((dlim - dx) * sampleSize);
        while (dx < dlim) {
          // Map color and insert in destination.
          int averageColor;
          if (sampleSize == 1) {
            int currentColorIndex = ((int) mainPixels[sx]) & 0x000000ff;
            averageColor = act[currentColorIndex];
          } else {
            // TODO: This is substantially slower (up to 50ms per frame) than just grabbing the
            // current color index above, even with a sample size of 1.
            averageColor = averageColorsNear(sx, maxPositionInSource, currentFrame.iw);
          }
          if (averageColor != 0) {
            dest[dx] = averageColor;
          } else if (!isFirstFrameTransparent && isFirstFrame) {
            isFirstFrameTransparent = true;
          }
          sx += sampleSize;
          dx++;
        }
      }
    }

    // Copy pixels into previous image
    if (savePrevious && (currentFrame.dispose == DISPOSAL_UNSPECIFIED
        || currentFrame.dispose == DISPOSAL_NONE)) {
      if (previousImage == null) {
        previousImage = getNextBitmap();
      }
      previousImage.setPixels(dest, 0, downsampledWidth, 0, 0, downsampledWidth,
          downsampledHeight);
    }

    // Set pixels for current image.
    Bitmap result = getNextBitmap();
    result.setPixels(dest, 0, downsampledWidth, 0, 0, downsampledWidth, downsampledHeight);
    return result;
  }
Creates new frame image from current data (and previous frames as specified by their
disposition codes).