Merge "Add ability to decode only image information with ImageDecoder" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c5557807e9
BIN
core/tests/coretests/res/drawable-nodpi/animated_webp.webp
Normal file
BIN
core/tests/coretests/res/drawable-nodpi/animated_webp.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.graphics;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ImageDecoderTest {
|
||||
|
||||
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
|
||||
@Test
|
||||
public void onDecodeHeader_png_returnsPopulatedData() throws IOException {
|
||||
ImageDecoder.Source src =
|
||||
ImageDecoder.createSource(mContext.getResources(), R.drawable.gettysburg);
|
||||
ImageDecoder.ImageInfo info = ImageDecoder.decodeHeader(src);
|
||||
assertThat(info.getSize().getWidth()).isEqualTo(432);
|
||||
assertThat(info.getSize().getHeight()).isEqualTo(291);
|
||||
assertThat(info.getMimeType()).isEqualTo("image/png");
|
||||
assertThat(info.getColorSpace()).isNotNull();
|
||||
assertThat(info.getColorSpace().getModel()).isEqualTo(ColorSpace.Model.RGB);
|
||||
assertThat(info.getColorSpace().getId()).isEqualTo(0);
|
||||
assertThat(info.isAnimated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDecodeHeader_animatedWebP_returnsPopulatedData() throws IOException {
|
||||
ImageDecoder.Source src =
|
||||
ImageDecoder.createSource(mContext.getResources(), R.drawable.animated_webp);
|
||||
ImageDecoder.ImageInfo info = ImageDecoder.decodeHeader(src);
|
||||
assertThat(info.getSize().getWidth()).isEqualTo(278);
|
||||
assertThat(info.getSize().getHeight()).isEqualTo(183);
|
||||
assertThat(info.getMimeType()).isEqualTo("image/webp");
|
||||
assertThat(info.getColorSpace()).isNotNull();
|
||||
assertThat(info.getColorSpace().getModel()).isEqualTo(ColorSpace.Model.RGB);
|
||||
assertThat(info.getColorSpace().getId()).isEqualTo(0);
|
||||
assertThat(info.isAnimated()).isTrue();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void onDecodeHeader_invalidSource_throwsException() throws IOException {
|
||||
ImageDecoder.Source src = ImageDecoder.createSource(new File("/this/file/does/not/exist"));
|
||||
ImageDecoder.decodeHeader(src);
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void onDecodeHeader_invalidResource_throwsException() throws IOException {
|
||||
ImageDecoder.Source src =
|
||||
ImageDecoder.createSource(mContext.getResources(), R.drawable.box);
|
||||
ImageDecoder.decodeHeader(src);
|
||||
}
|
||||
}
|
||||
@@ -627,11 +627,19 @@ public final class ImageDecoder implements AutoCloseable {
|
||||
*/
|
||||
public static class ImageInfo {
|
||||
private final Size mSize;
|
||||
private ImageDecoder mDecoder;
|
||||
private final boolean mIsAnimated;
|
||||
private final String mMimeType;
|
||||
private final ColorSpace mColorSpace;
|
||||
|
||||
private ImageInfo(@NonNull ImageDecoder decoder) {
|
||||
mSize = new Size(decoder.mWidth, decoder.mHeight);
|
||||
mDecoder = decoder;
|
||||
private ImageInfo(
|
||||
@NonNull Size size,
|
||||
boolean isAnimated,
|
||||
@NonNull String mimeType,
|
||||
@Nullable ColorSpace colorSpace) {
|
||||
mSize = size;
|
||||
mIsAnimated = isAnimated;
|
||||
mMimeType = mimeType;
|
||||
mColorSpace = colorSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -647,7 +655,7 @@ public final class ImageDecoder implements AutoCloseable {
|
||||
*/
|
||||
@NonNull
|
||||
public String getMimeType() {
|
||||
return mDecoder.getMimeType();
|
||||
return mMimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -657,7 +665,7 @@ public final class ImageDecoder implements AutoCloseable {
|
||||
* return an {@link AnimatedImageDrawable}.</p>
|
||||
*/
|
||||
public boolean isAnimated() {
|
||||
return mDecoder.mAnimated;
|
||||
return mIsAnimated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,7 +677,7 @@ public final class ImageDecoder implements AutoCloseable {
|
||||
*/
|
||||
@Nullable
|
||||
public ColorSpace getColorSpace() {
|
||||
return mDecoder.getColorSpace();
|
||||
return mColorSpace;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1798,12 +1806,39 @@ public final class ImageDecoder implements AutoCloseable {
|
||||
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
|
||||
@NonNull Source src) {
|
||||
if (listener != null) {
|
||||
ImageInfo info = new ImageInfo(this);
|
||||
try {
|
||||
listener.onHeaderDecoded(this, info, src);
|
||||
} finally {
|
||||
info.mDecoder = null;
|
||||
}
|
||||
ImageInfo info =
|
||||
new ImageInfo(
|
||||
new Size(mWidth, mHeight), mAnimated, getMimeType(), getColorSpace());
|
||||
listener.onHeaderDecoded(this, info, src);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ImageInfo} from a {@code Source}.
|
||||
*
|
||||
* <p>Returns the same {@link ImageInfo} object that a usual decoding process would return as
|
||||
* part of {@link OnHeaderDecodedListener}.
|
||||
*
|
||||
* @param src representing the encoded image.
|
||||
* @return ImageInfo describing the image.
|
||||
* @throws IOException if {@code src} is not found, is an unsupported format, or cannot be
|
||||
* decoded for any reason.
|
||||
* @hide
|
||||
*/
|
||||
@WorkerThread
|
||||
@NonNull
|
||||
public static ImageInfo decodeHeader(@NonNull Source src) throws IOException {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ImageDecoder#decodeHeader");
|
||||
try (ImageDecoder decoder = src.createImageDecoder(true /*preferAnimation*/)) {
|
||||
// We don't want to leak decoder so resolve all properties immediately.
|
||||
return new ImageInfo(
|
||||
new Size(decoder.mWidth, decoder.mHeight),
|
||||
decoder.mAnimated,
|
||||
decoder.getMimeType(),
|
||||
decoder.getColorSpace());
|
||||
} finally {
|
||||
// Close the ImageDecoder#decodeHeader trace.
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user