Closed panpf closed 11 months ago
Android (Pixel 6 emulator) also has these lines:
When you draw a rect with floating values, it becomes antialised (with transparent color) on its borders.
When you connect 2 such rects, the blending result also isn't completely opaque.
To avoid this, you need to round positions and sizes. There is no solution I am aware of that can be implemented on the framework level.
My real need is to draw an image and I have a simplified example of drawing image tiles.
It needs to add this dependency:
implementation("io.github.panpf.zoomimage:zoomimage-compose:1.0.0-beta05")
And a card image resource, sample_huge_card.jpg:
Please run the following code on the desktop platform:
@Composable
fun DrawTilesExample() {
val cardImageSize = IntSize(7557, 5669)
val cardThumbnailImageSize = cardImageSize / 8
val density = LocalDensity.current
val cardThumbnailDpSize = remember(density, cardThumbnailImageSize) {
with(density) {
DpSize(cardThumbnailImageSize.width.toDp(), cardThumbnailImageSize.height.toDp())
}
}
Box(Modifier.fillMaxSize()) {
var tiles by remember { mutableStateOf(emptyList<Tile>()) }
val logger = rememberZoomImageLogger()
val zoomState = rememberZoomableState(logger)
Box(modifier = Modifier
.size(cardThumbnailDpSize)
.zoom(logger, zoomState) // double tap zoom、drag pan, from zoomimage library
.drawWithContent {
drawContent()
tiles.forEach { tile ->
val imageBitmap = tile.imageBitmap
val srcRect = tile.srcRect
val drawRect = calculateTileDrawRect(cardImageSize, cardThumbnailImageSize, srcRect)
drawImage(
imageBitmap,
srcOffset = IntOffset.Zero,
srcSize = IntSize(imageBitmap.width, imageBitmap.height),
dstOffset = drawRect.topLeft,
dstSize = drawRect.size,
)
}
}
)
if (tiles.isEmpty()) {
CircularProgressIndicator(Modifier.align(Alignment.Center))
}
LaunchedEffect(Unit) {
tiles = decodeTiles("sample_huge_card.jpg", cardImageSize)
}
}
}
private fun calculateTileSrcRects(imageSize: IntSize, columnCount: Int, rowCount: Int): List
private fun calculateTileDrawRect(imageSize: IntSize, thumbnailSize: IntSize, srcRect: IntRect): IntRect { val widthScale: Float = imageSize.width / (thumbnailSize.width.toFloat()) val heightScale: Float = imageSize.height / (thumbnailSize.height.toFloat()) // // all floor. Render the result, with gaps // val drawRect = IntRect( // left = floor(srcRect.left / widthScale).toInt(), // top = floor(srcRect.top / heightScale).toInt(), // right = floor(srcRect.right / widthScale).toInt(), // bottom = floor(srcRect.bottom / heightScale).toInt() // ) // // all ceil. Render the result, with gaps // val drawRect = IntRect( // left = ceil(srcRect.left / widthScale).toInt(), // top = ceil(srcRect.top / heightScale).toInt(), // right = ceil(srcRect.right / widthScale).toInt(), // bottom = ceil(srcRect.bottom / heightScale).toInt() // ) // // all left top floor, right bottom ceil. Render the result, the tiles are misplaced // val drawRect = IntRect( // left = floor(srcRect.left / widthScale).toInt(), // top = floor(srcRect.top / heightScale).toInt(), // right = ceil(srcRect.right / widthScale).toInt(), // bottom = ceil(srcRect.bottom / heightScale).toInt() // ) // all round. Render the result, with gaps val drawRect = IntRect( left = round(srcRect.left / widthScale).toInt(), top = round(srcRect.top / heightScale).toInt(), right = round(srcRect.right / widthScale).toInt(), bottom = round(srcRect.bottom / heightScale).toInt() ) return drawRect }
@OptIn(ExperimentalComposeUiApi::class)
suspend fun decodeTiles(resourcePath: String, imageSize: IntSize): List
data class Tile(val srcRect: IntRect, val imageBitmap: ImageBitmap)
4. Double tap on the image to zoom in it, then drag the image and you will see a white gap, the gap is the background of the window
![Snipaste_2023-11-14_14-00-31](https://github.com/JetBrains/compose-multiplatform/assets/3250512/65cdbd5a-478a-40dc-ae2b-5b8141bf6c08)
I tried using round in the calculateTileDrawRect function to adjust the drawRect as you said, but it still didn't solve the problem.
Please help me solve this problem, whether it is adjusting drawRect or srcRect
In the second snippet we scale the canvas, so it also messes with coordinates of its content. Disabling antialiasing helps in this case:
drawIntoCanvas {
it.drawImageRect(
imageBitmap,
srcOffset = IntOffset.Zero,
srcSize = IntSize(imageBitmap.width, imageBitmap.height),
dstOffset = drawRect.topLeft,
dstSize = drawRect.size,
paint = Paint().apply {
isAntiAlias = false
}
)
}
In the second snippet we scale the canvas, so it also messes with coordinates of its content. Disabling antialiasing helps in this case:
drawIntoCanvas { it.drawImageRect( imageBitmap, srcOffset = IntOffset.Zero, srcSize = IntSize(imageBitmap.width, imageBitmap.height), dstOffset = drawRect.topLeft, dstSize = drawRect.size, paint = Paint().apply { isAntiAlias = false } ) }
This is useful, thank you very much!
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
Describe the bug I tried splitting a component into a fixed number of grids and drawing a rectangle for each grid. On the desktop platform there is always a gap between the cells. On the Android platform it fits perfectly.
Affected platforms
Versions
To Reproduce
Screenshots Running effect on desktop platform:
Running effect on Android:
Additional context
Please help me to solve this problem!