diff options
Diffstat (limited to 'tools/aapt/Images.cpp')
-rw-r--r-- | tools/aapt/Images.cpp | 162 |
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; |