Skip to content

Commit bd465ee

Browse files
alperozturk96AndyScherzinger
authored andcommitted
fix: gallery image scaling
Signed-off-by: alperozturk <[email protected]>
1 parent 51b322f commit bd465ee

File tree

2 files changed

+62
-79
lines changed

2 files changed

+62
-79
lines changed

app/src/main/java/com/nextcloud/utils/OCFileUtils.kt

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,34 +30,23 @@ object OCFileUtils {
3030
try {
3131
Log_OC.d(TAG, "Getting image size for: ${ocFile.fileName}")
3232

33-
// Use server-provided imageDimension if available
33+
// Server-provided
3434
ocFile.imageDimension?.let { dim ->
35-
val width = dim.width.toInt().coerceAtLeast(1)
36-
val height = dim.height.toInt().coerceAtLeast(1)
37-
Log_OC.d(TAG, "Using server-provided imageDimension: $width x $height")
38-
return width to height
35+
val w = dim.width.toInt().coerceAtLeast(1)
36+
val h = dim.height.toInt().coerceAtLeast(1)
37+
Log_OC.d(TAG, "Using server-provided imageDimension: $w x $h")
38+
return w to h
3939
}
4040

41-
// Fallback to local file if it exists
41+
// Local file
4242
val path = ocFile.storagePath
4343
if (!path.isNullOrEmpty() && ocFile.exists()) {
44-
// Try EXIF first
45-
val exifSize = getExifSize(path)
46-
if (exifSize != null) {
47-
Log_OC.d(TAG, "EXIF size used: ${exifSize.first} x ${exifSize.second}")
48-
return exifSize
49-
}
50-
51-
// Then try BitmapUtils
52-
val bitmapSize = getBitmapSize(path)
53-
if (bitmapSize != null) {
54-
Log_OC.d(TAG, "BitmapUtils resolution used: ${bitmapSize.first} x ${bitmapSize.second}")
55-
return bitmapSize
56-
}
44+
getExifSize(path)?.let { return it }
45+
getBitmapSize(path)?.let { return it }
5746
}
5847

59-
// Fallback to defaultThumbnailSize
60-
Log_OC.d(TAG, "All sources failed, using default size: $fallback x $fallback")
48+
// 3 Fallback
49+
Log_OC.d(TAG, "Fallback to default size: $fallback x $fallback")
6150
return fallbackPair
6251
} catch (e: Exception) {
6352
Log_OC.e(TAG, "Error getting image size for ${ocFile.fileName}", e)
@@ -68,8 +57,8 @@ object OCFileUtils {
6857

6958
private fun getExifSize(path: String): Pair<Int, Int>? = try {
7059
val exif = ExifInterface(path)
71-
var width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0)
72-
var height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0)
60+
var w = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0)
61+
var h = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0)
7362

7463
val orientation = exif.getAttributeInt(
7564
ExifInterface.TAG_ORIENTATION,
@@ -78,23 +67,24 @@ object OCFileUtils {
7867
if (orientation == ExifInterface.ORIENTATION_ROTATE_90 ||
7968
orientation == ExifInterface.ORIENTATION_ROTATE_270
8069
) {
81-
val tmp = width
82-
width = height
83-
height = tmp
70+
val tmp = w
71+
w = h
72+
h = tmp
8473
}
8574

86-
if (width > 0 && height > 0) width to height else null
75+
if (w > 0 && h > 0) w to h else null
8776
} catch (_: Exception) {
8877
null
8978
}
9079

91-
private fun getBitmapSize(path: String): Pair<Int, Int>? {
92-
return try {
93-
val (w, h) = BitmapUtils.getImageResolution(path).takeIf { it.size == 2 } ?: return null
94-
if (w > 0 && h > 0) w to h else null
95-
} catch (_: Exception) {
96-
null
97-
}
80+
private fun getBitmapSize(path: String): Pair<Int, Int>? = try {
81+
val options = android.graphics.BitmapFactory.Options().apply { inJustDecodeBounds = true }
82+
android.graphics.BitmapFactory.decodeFile(path, options)
83+
val w = options.outWidth
84+
val h = options.outHeight
85+
if (w > 0 && h > 0) w to h else null
86+
} catch (_: Exception) {
87+
null
9888
}
9989

10090
fun getMediaPlaceholder(file: OCFile, imageDimension: Pair<Int, Int>): BitmapDrawable {

app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import com.elyeproj.loaderviewlibrary.LoaderImageView
1919
import com.nextcloud.android.common.ui.theme.utils.ColorRole
2020
import com.nextcloud.utils.OCFileUtils
2121
import com.nextcloud.utils.extensions.makeRounded
22-
import com.nextcloud.utils.extensions.mediaSize
2322
import com.nextcloud.utils.extensions.setVisibleIf
2423
import com.owncloud.android.R
2524
import com.owncloud.android.databinding.GalleryRowBinding
@@ -68,7 +67,7 @@ class GalleryRowHolder(
6867
// Only rebuild if file count changed
6968
if (lastFileCount != requiredCount) {
7069
binding.rowLayout.removeAllViews()
71-
for (file in row.files) {
70+
row.files.forEach { file ->
7271
binding.rowLayout.addView(getRowLayout(file))
7372
}
7473
lastFileCount = requiredCount
@@ -81,11 +80,11 @@ class GalleryRowHolder(
8180
}
8281
}
8382

84-
fun updateRowVisuals() {
85-
bind(currentRow)
86-
}
83+
fun updateRowVisuals() = bind(currentRow)
8784

8885
private fun getRowLayout(file: OCFile): FrameLayout {
86+
val (width, height) = OCFileUtils.getImageSize(file, defaultThumbnailSize)
87+
8988
val checkbox = ImageView(context).apply {
9089
visibility = View.GONE
9190
layoutParams = FrameLayout.LayoutParams(
@@ -98,16 +97,13 @@ class GalleryRowHolder(
9897
}
9998
}
10099

101-
val mediaSize = file.mediaSize(defaultThumbnailSize)
102-
val (width, height) = mediaSize
103-
104100
val shimmer = LoaderImageView(context).apply {
105101
setImageResource(R.drawable.background)
106102
resetLoader()
107103
layoutParams = FrameLayout.LayoutParams(width, height)
108104
}
109105

110-
val drawable = OCFileUtils.getMediaPlaceholder(file, mediaSize)
106+
val drawable = OCFileUtils.getMediaPlaceholder(file, width to height)
111107
val rowCellImageView = ImageView(context).apply {
112108
setImageDrawable(drawable)
113109
adjustViewBounds = true
@@ -122,63 +118,60 @@ class GalleryRowHolder(
122118
}
123119
}
124120

121+
private fun getDimensions(row: GalleryRow): List<Pair<Int, Int>> {
122+
val screenWidthPx = context.resources.displayMetrics.widthPixels.toFloat()
123+
val marginPx = smallMargin.toFloat()
124+
val totalMargins = marginPx * (row.files.size - 1)
125+
val availableWidth = screenWidthPx - totalMargins
126+
127+
val aspectRatios = row.files.map { file ->
128+
val (w, h) = OCFileUtils.getImageSize(file, defaultThumbnailSize)
129+
if (h > 0) w.toFloat() / h else 1.0f
130+
}
131+
132+
val sumAspectRatios = aspectRatios.sum()
133+
134+
// calculate row height based on aspect ratios
135+
val rowHeightFloat = if (sumAspectRatios > 0) availableWidth / sumAspectRatios else defaultThumbnailSize
136+
val finalHeight = rowHeightFloat.toInt()
137+
138+
// for each aspect ratio calculate widths
139+
val finalWidths = aspectRatios.map { ratio -> (rowHeightFloat * ratio).toInt() }.toMutableList()
140+
val usedWidth = finalWidths.sum()
141+
142+
// based on screen width get remaining pixels
143+
val remainingPixels = (availableWidth - usedWidth).toInt()
144+
145+
// add to remaining pixels to last image
146+
if (remainingPixels > 0 && finalWidths.isNotEmpty()) {
147+
val lastIndex = finalWidths.lastIndex
148+
finalWidths[lastIndex] = finalWidths[lastIndex] + remainingPixels
149+
}
150+
151+
return finalWidths.map { w -> w to finalHeight }
152+
}
153+
125154
private fun adjustFile(index: Int, file: OCFile, dims: Pair<Int, Int>, row: GalleryRow) {
126155
val (width, height) = dims
127-
128156
val frameLayout = binding.rowLayout[index] as FrameLayout
129157
val shimmer = frameLayout[0] as LoaderImageView
130158
val thumbnail = frameLayout[1] as ImageView
131159
val checkbox = frameLayout[2] as ImageView
132160

133161
val isChecked = ocFileListDelegate.isCheckedFile(file)
134-
135162
adjustRowCell(thumbnail, isChecked)
136163
adjustCheckBox(checkbox, isChecked)
137164

138165
ocFileListDelegate.bindGalleryRow(shimmer, thumbnail, file, this, dims)
139166

140167
val endMargin = if (index < row.files.size - 1) smallMargin else zero
141-
142168
thumbnail.layoutParams = FrameLayout.LayoutParams(width, height).apply {
143169
setMargins(0, 0, endMargin, smallMargin)
144170
}
145171
shimmer.layoutParams = FrameLayout.LayoutParams(width, height)
146-
147172
frameLayout.requestLayout()
148173
}
149174

150-
private fun getDimensions(row: GalleryRow): List<Pair<Int, Int>> {
151-
val screenWidthPx = context.resources.displayMetrics.widthPixels.toFloat()
152-
val marginPx = smallMargin.toFloat()
153-
154-
val aspectRatios = row.files.map { file ->
155-
val (w, h) = OCFileUtils.getImageSize(file, defaultThumbnailSize)
156-
if (w > 0 && h > 0) w.toFloat() / h.toFloat() else 1f
157-
}
158-
159-
// Start with max height based on largest image
160-
val targetHeight = row.getMaxHeight().coerceAtLeast(1f)
161-
162-
val unscaledWidths = aspectRatios.map { ar -> targetHeight * ar }
163-
164-
// margins
165-
val totalUnscaled = unscaledWidths.sum()
166-
val totalMargins = marginPx * (row.files.size - 1)
167-
val available = screenWidthPx - totalMargins
168-
169-
// calculate shrink ratio
170-
val shrink = available / totalUnscaled
171-
172-
// prepare scaled dimensions
173-
val dims = unscaledWidths.map { w ->
174-
val finalW = (w * shrink).toInt()
175-
val finalH = (targetHeight * shrink).toInt()
176-
finalW to finalH
177-
}
178-
179-
return dims
180-
}
181-
182175
@Suppress("MagicNumber")
183176
private fun adjustRowCell(imageView: ImageView, isChecked: Boolean) {
184177
val scale = if (isChecked) 0.8f else 1.0f

0 commit comments

Comments
 (0)