in native-filters/src/main/jni/filters/rounding_filter.c [564:632]
static void drawBorder(
JNIEnv* env,
pixel_t* pixelPtr,
const int w,
const int h,
int32_t colorABGR,
int borderWidth) {
// Radius of the circle
const float radius = min(w,h) / 2.0;
//const float borderSize = radius * 0.038;
const float borderSize = min(borderWidth, radius-1);
const float innerRadius = radius - borderSize;
// increase radius to avoid outer border on the sides
// Imaginary center of the circle.
const float centerX = (w - 1.0L) / 2.0;
const float centerY = (h - 1.0L) / 2.0;
if (radius < 1) {
safe_throw_exception(env, "Circle radius too small!");
return;
}
if (w <= 0 || h <= 0 || w > BITMAP_MAX_DIMENSION || h > BITMAP_MAX_DIMENSION) {
safe_throw_exception(env, "Invalid bitmap dimensions!");
return;
}
if (centerX < 0 || centerY < 0 || centerX >= w || centerY >= h) {
safe_throw_exception(env, "Invalid circle center coordinates!");
return;
}
// Clear top/bottom if height > width
const int top_boundary = max(centerY - radius, 0);
const int bottom_boundary = min(centerY + radius, h);
const float outer_r_square = POW2(radius);
const float inner_r_square = POW2(innerRadius);
int inner_x_offset = 0;
float inner_x_offset_sq = 0;
int outer_x_offset = 0;
float outer_x_offset_sq = 0;
pixel_t borderColorPixel = colorABGRtoPixel(colorABGR);
for (int y = top_boundary; y < bottom_boundary; y++) {
// Square formula: (x-cx)^2 + (y-cy)^2 = r^2 <=> (x-cx) = -cx^2 + 2cy*y - y^2 + r^2
outer_x_offset_sq = -POW2(centerY) + (2*centerY*y) - POW2(y) + outer_r_square;
inner_x_offset_sq = -POW2(centerY) + (2*centerY*y) - POW2(y) + inner_r_square;
if(outer_x_offset_sq > 0 && inner_x_offset_sq > 0) {
outer_x_offset = ceil(sqrt(outer_x_offset_sq));
inner_x_offset = ceil(sqrt(inner_x_offset_sq));
int borderSizeInLine = outer_x_offset - inner_x_offset + 1;
if (borderSizeInLine>0) {
paintRowSegment(pixelPtr + y * w + (int) centerX - (int) outer_x_offset, borderSizeInLine, colorABGR);
paintRowSegment(pixelPtr + y * w + (int) centerX + (int) inner_x_offset, borderSizeInLine, colorABGR);
}
// internal border antialiasing
antialiasInternalBorder(pixelPtr, borderColorPixel, y, w, centerX, centerY, inner_x_offset, innerRadius);
} else if (outer_x_offset >= 0) {
outer_x_offset = sqrt(outer_x_offset_sq);
paintRowSegment(pixelPtr + y * w + (int) (centerX - outer_x_offset), (int) outer_x_offset * 2, colorABGR);
} else if (inner_x_offset >= 0) {
inner_x_offset = sqrt(inner_x_offset_sq);
paintRowSegment(pixelPtr + y * w + (int) (centerX - inner_x_offset), (int) outer_x_offset * 2, colorABGR);
}
}
}