/*
* This file provided by Facebook is for non-commercial testing and evaluation
* purposes only. Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.facebook.fresco.samples.showcase.imageformat.keyframes;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import com.facebook.common.internal.Closeables;
import com.facebook.drawee.backends.pipeline.DrawableFactory;
import com.facebook.imageformat.ImageFormat;
import com.facebook.imageformat.ImageFormatCheckerUtils;
import com.facebook.imagepipeline.common.ImageDecodeOptions;
import com.facebook.imagepipeline.decoder.ImageDecoder;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.image.QualityInfo;
import com.facebook.keyframes.KeyframesDrawableBuilder;
import com.facebook.keyframes.deserializers.KFImageDeserializer;
import com.facebook.keyframes.model.KFImage;
import java.io.IOException;
import java.io.InputStream;
/**
* Decoder and related classes for loading and displaying Keyframe animated images.
*/
public class KeyframesDecoderExample {
public static final ImageFormat IMAGE_FORMAT_KEYFRAMES
= new ImageFormat("KEYFRAMES", "keyframes");
public static ImageFormat.FormatChecker createFormatChecker() {
return new KeyframesFormatChecker();
}
public static ImageDecoder createDecoder() {
return new KeyframesDecoder();
}
public static DrawableFactory createDrawableFactory() {
return new KeyframesDrawableFactory();
}
private static class KeyframesFormatChecker implements ImageFormat.FormatChecker {
private static final int HEADER_SIZE = 100;
private static final byte[] JSON_OBJECT_FIRST_BYTE =
ImageFormatCheckerUtils.asciiBytes("{");
@Override
public int getHeaderSize() {
return HEADER_SIZE;
}
/**
* Although keyframe files do not have an explicit header, we try to match by looking for a JSON
* file start and known mandatory keys.
*/
@Nullable
@Override
public ImageFormat determineFormat(byte[] headerBytes, int headerSize) {
// JSON files must start with a opening curly brace
if (!ImageFormatCheckerUtils.startsWithPattern(
headerBytes,
JSON_OBJECT_FIRST_BYTE)) {
return null;
}
// we expect the format version to be in the header of any proper keyframe file
final String expectedFormatVersionKey = "formatVersion";
final String headerString = new String(headerBytes);
if (!headerString.contains(expectedFormatVersionKey)) {
return null;
}
return IMAGE_FORMAT_KEYFRAMES;
}
}
private static class KeyframesDecoder implements ImageDecoder {
@Override
public CloseableImage decode(
EncodedImage encodedImage,
int length,
QualityInfo qualityInfo,
ImageDecodeOptions options) {
InputStream encodedInputStream = null;
try {
encodedInputStream = encodedImage.getInputStream();
return new CloseableKeyframesImage(
KFImageDeserializer.deserialize(encodedInputStream));
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
Closeables.closeQuietly(encodedInputStream);
}
}
}
private static class CloseableKeyframesImage extends CloseableImage {
private boolean mClosed;
private final KFImage mImage;
CloseableKeyframesImage(KFImage image) {
mImage = image;
}
KFImage getImage() {
return mImage;
}
@Override
public int getSizeInBytes() {
return 0;
}
@Override
public void close() {
mClosed = true;
}
@Override
public boolean isClosed() {
return mClosed;
}
@Override
public int getWidth() {
return (int) mImage.getCanvasSize()[0];
}
@Override
public int getHeight() {
return (int) mImage.getCanvasSize()[1];
}
@Override
public boolean isStateful() {
return true;
}
}
private static class KeyframesDrawableFactory implements DrawableFactory {
@Override
public boolean supportsImageType(CloseableImage image) {
return image instanceof CloseableKeyframesImage;
}
@Nullable
@Override
public Drawable createDrawable(CloseableImage image) {
KFImage kfImage = ((CloseableKeyframesImage) image).getImage();
return new AnimatableKeyframesDrawable(
new KeyframesDrawableBuilder().withImage(kfImage).build());
}
}
}