Support trimmed images in BootAnimation
Each frame directory may optionally contain a `trim.txt` to specify
how the image was trimmed relative to the animation's full size.
See FORMAT.md for more details.
Bug: 29055299
Change-Id: I7a291e9a52b4bbe50a29c519f6a4d0e2cc0389d7
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index e8fcd3b..e849f4b 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -596,15 +596,15 @@
// read all the data structures
const size_t pcount = animation.parts.size();
void *cookie = NULL;
- ZipFileRO* mZip = animation.zip;
- if (!mZip->startIteration(&cookie)) {
+ ZipFileRO* zip = animation.zip;
+ if (!zip->startIteration(&cookie)) {
return false;
}
ZipEntryRO entry;
char name[ANIM_ENTRY_NAME_MAX];
- while ((entry = mZip->nextEntry(cookie)) != NULL) {
- const int foundEntryName = mZip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
+ while ((entry = zip->nextEntry(cookie)) != NULL) {
+ const int foundEntryName = zip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
ALOGE("Error fetching entry file name");
continue;
@@ -614,22 +614,29 @@
const String8 path(entryName.getPathDir());
const String8 leaf(entryName.getPathLeaf());
if (leaf.size() > 0) {
- for (size_t j=0 ; j<pcount ; j++) {
+ for (size_t j = 0; j < pcount; j++) {
if (path == animation.parts[j].path) {
uint16_t method;
// supports only stored png files
- if (mZip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
+ if (zip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
if (method == ZipFileRO::kCompressStored) {
- FileMap* map = mZip->createEntryFileMap(entry);
+ FileMap* map = zip->createEntryFileMap(entry);
if (map) {
Animation::Part& part(animation.parts.editItemAt(j));
if (leaf == "audio.wav") {
// a part may have at most one audio file
part.audioFile = map;
+ } else if (leaf == "trim.txt") {
+ part.trimData.setTo((char const*)map->getDataPtr(),
+ map->getDataLength());
} else {
Animation::Frame frame;
frame.name = leaf;
frame.map = map;
+ frame.trimWidth = animation.width;
+ frame.trimHeight = animation.height;
+ frame.trimX = 0;
+ frame.trimY = 0;
part.frames.add(frame);
}
}
@@ -640,7 +647,33 @@
}
}
- mZip->endIteration(cookie);
+ // If there is trimData present, override the positioning defaults.
+ for (Animation::Part& part : animation.parts) {
+ const char* trimDataStr = part.trimData.string();
+ for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
+ const char* endl = strstr(trimDataStr, "\n");
+ // No more trimData for this part.
+ if (endl == NULL) {
+ break;
+ }
+ String8 line(trimDataStr, endl - trimDataStr);
+ const char* lineStr = line.string();
+ trimDataStr = ++endl;
+ int width = 0, height = 0, x = 0, y = 0;
+ if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
+ Animation::Frame& frame(part.frames.editItemAt(frameIdx));
+ frame.trimWidth = width;
+ frame.trimHeight = height;
+ frame.trimX = x;
+ frame.trimY = y;
+ } else {
+ ALOGE("Error parsing trim.txt, line: %s", lineStr);
+ break;
+ }
+ }
+ }
+
+ zip->endIteration(cookie);
return true;
}
@@ -707,12 +740,9 @@
bool BootAnimation::playAnimation(const Animation& animation)
{
const size_t pcount = animation.parts.size();
- const int xc = (mWidth - animation.width) / 2;
- const int yc = ((mHeight - animation.height) / 2);
nsecs_t frameDuration = s2ns(1) / animation.fps;
-
- Region clearReg(Rect(mWidth, mHeight));
- clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
+ const int animationX = (mWidth - animation.width) / 2;
+ const int animationY = (mHeight - animation.height) / 2;
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
@@ -759,22 +789,25 @@
initTexture(frame);
}
+ const int xc = animationX + frame.trimX;
+ const int yc = animationY + frame.trimY;
+ Region clearReg(Rect(mWidth, mHeight));
+ clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
if (!clearReg.isEmpty()) {
Region::const_iterator head(clearReg.begin());
Region::const_iterator tail(clearReg.end());
glEnable(GL_SCISSOR_TEST);
while (head != tail) {
const Rect& r2(*head++);
- glScissor(r2.left, mHeight - r2.bottom,
- r2.width(), r2.height());
+ glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
glClear(GL_COLOR_BUFFER_BIT);
}
glDisable(GL_SCISSOR_TEST);
}
- // specify the y center as ceiling((mHeight - animation.height) / 2)
- // which is equivalent to mHeight - (yc + animation.height)
- glDrawTexiOES(xc, mHeight - (yc + animation.height),
- 0, animation.width, animation.height);
+ // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
+ // which is equivalent to mHeight - (yc + frame.trimHeight)
+ glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
+ 0, frame.trimWidth, frame.trimHeight);
if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) {
drawTime(mClock, part.clockPosY);
}