summaryrefslogtreecommitdiff
path: root/tools/aapt/Images.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt/Images.cpp')
-rw-r--r--tools/aapt/Images.cpp162
1 files changed, 151 insertions, 11 deletions
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 5368418f066d..083ca8499b14 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -78,10 +78,24 @@ struct image_info
int32_t layoutBoundsRight;
int32_t layoutBoundsBottom;
+ // Round rect outline description
+ int32_t outlineInsetsLeft;
+ int32_t outlineInsetsTop;
+ int32_t outlineInsetsRight;
+ int32_t outlineInsetsBottom;
+ float outlineRadius;
+ uint8_t outlineAlpha;
+
png_uint_32 allocHeight;
png_bytepp allocRows;
};
+static void log_warning(png_structp png_ptr, png_const_charp warning_message)
+{
+ const char* imageName = (const char*) png_get_error_ptr(png_ptr);
+ fprintf(stderr, "%s: libpng warning: %s\n", imageName, warning_message);
+}
+
static void read_png(const char* imageName,
png_structp read_ptr, png_infop read_info,
image_info* outImageInfo)
@@ -90,6 +104,8 @@ static void read_png(const char* imageName,
int bit_depth, interlace_type, compression_type;
int i;
+ png_set_error_fn(read_ptr, const_cast<char*>(imageName),
+ NULL /* use default errorfn */, log_warning);
png_read_info(read_ptr, read_info);
png_get_IHDR(read_ptr, read_info, &outImageInfo->width,
@@ -120,6 +136,8 @@ static void read_png(const char* imageName,
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(read_ptr);
+ png_set_interlace_handling(read_ptr);
+
png_read_update_info(read_ptr, read_info);
outImageInfo->rows = (png_bytepp)malloc(
@@ -390,6 +408,105 @@ static status_t get_vertical_layout_bounds_ticks(
return NO_ERROR;
}
+static void find_max_opacity(png_byte** rows,
+ int startX, int startY, int endX, int endY, int dX, int dY,
+ int* out_inset)
+{
+ bool opaque_within_inset = true;
+ uint8_t max_opacity = 0;
+ int inset = 0;
+ *out_inset = 0;
+ for (int x = startX, y = startY; x != endX && y != endY; x += dX, y += dY, inset++) {
+ png_byte* color = rows[y] + x * 4;
+ uint8_t opacity = color[3];
+ if (opacity > max_opacity) {
+ max_opacity = opacity;
+ *out_inset = inset;
+ }
+ if (opacity == 0xff) return;
+ }
+}
+
+static uint8_t max_alpha_over_row(png_byte* row, int startX, int endX)
+{
+ uint8_t max_alpha = 0;
+ for (int x = startX; x < endX; x++) {
+ uint8_t alpha = (row + x * 4)[3];
+ if (alpha > max_alpha) max_alpha = alpha;
+ }
+ return max_alpha;
+}
+
+static uint8_t max_alpha_over_col(png_byte** rows, int offsetX, int startY, int endY)
+{
+ uint8_t max_alpha = 0;
+ for (int y = startY; y < endY; y++) {
+ uint8_t alpha = (rows[y] + offsetX * 4)[3];
+ if (alpha > max_alpha) max_alpha = alpha;
+ }
+ return max_alpha;
+}
+
+static void get_outline(image_info* image)
+{
+ int midX = image->width / 2;
+ int midY = image->height / 2;
+ int endX = image->width - 2;
+ int endY = image->height - 2;
+
+ // find left and right extent of nine patch content on center row
+ if (image->width > 4) {
+ find_max_opacity(image->rows, 1, midY, midX, -1, 1, 0, &image->outlineInsetsLeft);
+ find_max_opacity(image->rows, endX, midY, midX, -1, -1, 0, &image->outlineInsetsRight);
+ } else {
+ image->outlineInsetsLeft = 0;
+ image->outlineInsetsRight = 0;
+ }
+
+ // find top and bottom extent of nine patch content on center column
+ if (image->height > 4) {
+ find_max_opacity(image->rows, midX, 1, -1, midY, 0, 1, &image->outlineInsetsTop);
+ find_max_opacity(image->rows, midX, endY, -1, midY, 0, -1, &image->outlineInsetsBottom);
+ } else {
+ image->outlineInsetsTop = 0;
+ image->outlineInsetsBottom = 0;
+ }
+
+ int innerStartX = 1 + image->outlineInsetsLeft;
+ int innerStartY = 1 + image->outlineInsetsTop;
+ int innerEndX = endX - image->outlineInsetsRight;
+ int innerEndY = endY - image->outlineInsetsBottom;
+ int innerMidX = (innerEndX + innerStartX) / 2;
+ int innerMidY = (innerEndY + innerStartY) / 2;
+
+ // assuming the image is a round rect, compute the radius by marching
+ // diagonally from the top left corner towards the center
+ image->outlineAlpha = max(max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
+ max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
+
+ int diagonalInset = 0;
+ find_max_opacity(image->rows, innerStartX, innerStartY, innerMidX, innerMidY, 1, 1,
+ &diagonalInset);
+
+ /* Determine source radius based upon inset:
+ * sqrt(r^2 + r^2) = sqrt(i^2 + i^2) + r
+ * sqrt(2) * r = sqrt(2) * i + r
+ * (sqrt(2) - 1) * r = sqrt(2) * i
+ * r = sqrt(2) / (sqrt(2) - 1) * i
+ */
+ image->outlineRadius = 3.4142f * diagonalInset;
+
+ if (kIsDebug) {
+ printf("outline insets %d %d %d %d, rad %f, alpha %x\n",
+ image->outlineInsetsLeft,
+ image->outlineInsetsTop,
+ image->outlineInsetsRight,
+ image->outlineInsetsBottom,
+ image->outlineRadius,
+ image->outlineAlpha);
+ }
+}
+
static uint32_t get_color(
png_bytepp rows, int left, int top, int right, int bottom)
@@ -531,6 +648,9 @@ static status_t do_9patch(const char* imageName, image_info* image)
}
}
+ // use opacity of pixels to estimate the round rect outline
+ get_outline(image);
+
// If padding is not yet specified, take values from size.
if (image->info9Patch.paddingLeft < 0) {
image->info9Patch.paddingLeft = xDivs[0];
@@ -549,8 +669,8 @@ static status_t do_9patch(const char* imageName, image_info* image)
if (kIsDebug) {
printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName,
- image->info9Patch.getXDivs()[0], image->info9Patch.getXDivs()[1],
- image->info9Patch.getYDivs()[0], image->info9Patch.getYDivs()[1]);
+ xDivs[0], xDivs[1],
+ yDivs[0], yDivs[1]);
printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName,
image->info9Patch.paddingLeft, image->info9Patch.paddingRight,
image->info9Patch.paddingTop, image->info9Patch.paddingBottom);
@@ -918,7 +1038,7 @@ static void analyze_image(const char *imageName, image_info &imageInfo, int gray
gg = *row++;
bb = *row++;
aa = *row++;
-
+
if (isGrayscale) {
*out++ = rr;
} else {
@@ -942,9 +1062,10 @@ static void write_png(const char* imageName,
int bit_depth, interlace_type, compression_type;
int i;
- png_unknown_chunk unknowns[2];
+ png_unknown_chunk unknowns[3];
unknowns[0].data = NULL;
unknowns[1].data = NULL;
+ unknowns[2].data = NULL;
png_bytepp outRows = (png_bytepp) malloc((int) imageInfo.height * sizeof(png_bytep));
if (outRows == (png_bytepp) 0) {
@@ -1018,12 +1139,17 @@ static void write_png(const char* imageName,
}
if (imageInfo.is9Patch) {
- int chunk_count = 1 + (imageInfo.haveLayoutBounds ? 1 : 0);
- int p_index = imageInfo.haveLayoutBounds ? 1 : 0;
- int b_index = 0;
+ int chunk_count = 2 + (imageInfo.haveLayoutBounds ? 1 : 0);
+ int p_index = imageInfo.haveLayoutBounds ? 2 : 1;
+ int b_index = 1;
+ int o_index = 0;
+
+ // Chunks ordered thusly because older platforms depend on the base 9 patch data being last
png_byte *chunk_names = imageInfo.haveLayoutBounds
- ? (png_byte*)"npLb\0npTc\0"
- : (png_byte*)"npTc";
+ ? (png_byte*)"npOl\0npLb\0npTc\0"
+ : (png_byte*)"npOl\0npTc";
+
+ // base 9 patch data
if (kIsDebug) {
printf("Adding 9-patch info...\n");
}
@@ -1033,6 +1159,18 @@ static void write_png(const char* imageName,
// TODO: remove the check below when everything works
checkNinePatchSerialization(&imageInfo.info9Patch, unknowns[p_index].data);
+ // automatically generated 9 patch outline data
+ int chunk_size = sizeof(png_uint_32) * 6;
+ strcpy((char*)unknowns[o_index].name, "npOl");
+ unknowns[o_index].data = (png_byte*) calloc(chunk_size, 1);
+ png_byte outputData[chunk_size];
+ memcpy(&outputData, &imageInfo.outlineInsetsLeft, 4 * sizeof(png_uint_32));
+ ((float*) outputData)[4] = imageInfo.outlineRadius;
+ ((png_uint_32*) outputData)[5] = imageInfo.outlineAlpha;
+ memcpy(unknowns[o_index].data, &outputData, chunk_size);
+ unknowns[o_index].size = chunk_size;
+
+ // optional optical inset / layout bounds data
if (imageInfo.haveLayoutBounds) {
int chunk_size = sizeof(png_uint_32) * 4;
strcpy((char*)unknowns[b_index].name, "npLb");
@@ -1083,6 +1221,7 @@ static void write_png(const char* imageName,
free(outRows);
free(unknowns[0].data);
free(unknowns[1].data);
+ free(unknowns[2].data);
png_get_IHDR(write_ptr, write_info, &width, &height,
&bit_depth, &color_type, &interlace_type,
@@ -1342,7 +1481,7 @@ status_t preProcessImageToCache(const Bundle* bundle, const String8& source, con
return NO_ERROR;
}
-status_t postProcessImage(const sp<AaptAssets>& assets,
+status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
ResourceTable* table, const sp<AaptFile>& file)
{
String8 ext(file->getPath().getPathExtension());
@@ -1350,7 +1489,8 @@ status_t postProcessImage(const sp<AaptAssets>& assets,
// At this point, now that we have all the resource data, all we need to
// do is compile XML files.
if (strcmp(ext.string(), ".xml") == 0) {
- return compileXmlFile(assets, file, table);
+ String16 resourceName(parseResourceName(file->getPath().getPathLeaf()));
+ return compileXmlFile(bundle, assets, resourceName, file, table);
}
return NO_ERROR;