@@ -193,8 +193,28 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
193193 } else {
194194 @Suppress(" DEPRECATION" ) BitmapRegionDecoder .newInstance(it, false )
195195 }
196+
197+ val imageHeight: Int = decoder!! .height
198+ val imageWidth: Int = decoder!! .width
199+ val orientation = getOrientation(reactContext, Uri .parse(uri))
200+
201+ val (left, top) =
202+ when (orientation) {
203+ 90 -> y to imageHeight - width - x
204+ 180 -> imageWidth - width - x to imageHeight - height - y
205+ 270 -> imageWidth - height - y to x
206+ else -> x to y
207+ }
208+
209+ val (right, bottom) =
210+ when (orientation) {
211+ 90 ,
212+ 270 -> left + height to top + width
213+ else -> left + width to top + height
214+ }
215+
196216 return @use try {
197- val rect = Rect (x, y, x + width, y + height )
217+ val rect = Rect (left, top, right, bottom )
198218 decoder!! .decodeRegion(rect, outOptions)
199219 } finally {
200220 decoder!! .recycle()
@@ -218,12 +238,12 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
218238 private fun cropAndResizeTask (
219239 outOptions : BitmapFactory .Options ,
220240 uri : String ,
221- x : Int ,
222- y : Int ,
223- width : Int ,
224- height : Int ,
225- targetWidth : Int ,
226- targetHeight : Int ,
241+ xPos : Int ,
242+ yPos : Int ,
243+ rectWidth : Int ,
244+ rectHeight : Int ,
245+ outputWidth : Int ,
246+ outputHeight : Int ,
227247 ): Bitmap ? {
228248 Assertions .assertNotNull(outOptions)
229249
@@ -233,6 +253,35 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
233253 // This uses scaling mode COVER
234254
235255 // Where would the crop rect end up within the scaled bitmap?
256+
257+ val bitmap =
258+ openBitmapInputStream(uri)?.use {
259+ // This can use significantly less memory than decoding the full-resolution bitmap
260+ BitmapFactory .decodeStream(it, null , outOptions)
261+ } ? : return null
262+
263+ val orientation = getOrientation(reactContext, Uri .parse(uri))
264+ val (x, y) =
265+ when (orientation) {
266+ 90 -> yPos to bitmap.height - rectWidth - xPos
267+ 270 -> bitmap.width - rectHeight - yPos to xPos
268+ 180 -> bitmap.width - rectWidth - xPos to bitmap.height - rectHeight - yPos
269+ else -> xPos to yPos
270+ }
271+
272+ val (width, height) =
273+ when (orientation) {
274+ 90 ,
275+ 270 -> rectHeight to rectWidth
276+ else -> rectWidth to rectHeight
277+ }
278+ val (targetWidth, targetHeight) =
279+ when (orientation) {
280+ 90 ,
281+ 270 -> outputHeight to outputWidth
282+ else -> outputWidth to outputHeight
283+ }
284+
236285 val cropRectRatio = width / height.toFloat()
237286 val targetRatio = targetWidth / targetHeight.toFloat()
238287 val isCropRatioLargerThanTargetRatio = cropRectRatio > targetRatio
@@ -250,11 +299,6 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
250299 // Decode the bitmap. We have to open the stream again, like in the example linked above.
251300 // Is there a way to just continue reading from the stream?
252301 outOptions.inSampleSize = getDecodeSampleSize(width, height, targetWidth, targetHeight)
253- val bitmap =
254- openBitmapInputStream(uri)?.use {
255- // This can use significantly less memory than decoding the full-resolution bitmap
256- BitmapFactory .decodeStream(it, null , outOptions)
257- } ? : return null
258302
259303 val cropX = (newX / outOptions.inSampleSize.toFloat()).roundToInt()
260304 val cropY = (newY / outOptions.inSampleSize.toFloat()).roundToInt()
@@ -296,30 +340,119 @@ class ImageEditorModuleImpl(private val reactContext: ReactApplicationContext) {
296340 @SuppressLint(" InlinedApi" )
297341 private val EXIF_ATTRIBUTES =
298342 arrayOf(
343+ ExifInterface .TAG_APERTURE_VALUE ,
344+ ExifInterface .TAG_MAX_APERTURE_VALUE ,
345+ ExifInterface .TAG_METERING_MODE ,
346+ ExifInterface .TAG_ARTIST ,
347+ ExifInterface .TAG_BITS_PER_SAMPLE ,
348+ ExifInterface .TAG_COMPRESSION ,
349+ ExifInterface .TAG_BODY_SERIAL_NUMBER ,
350+ ExifInterface .TAG_BRIGHTNESS_VALUE ,
351+ ExifInterface .TAG_CONTRAST ,
352+ ExifInterface .TAG_CAMERA_OWNER_NAME ,
353+ ExifInterface .TAG_COLOR_SPACE ,
354+ ExifInterface .TAG_COPYRIGHT ,
299355 ExifInterface .TAG_DATETIME ,
300356 ExifInterface .TAG_DATETIME_DIGITIZED ,
357+ ExifInterface .TAG_DATETIME_ORIGINAL ,
358+ ExifInterface .TAG_DEVICE_SETTING_DESCRIPTION ,
359+ ExifInterface .TAG_DIGITAL_ZOOM_RATIO ,
360+ ExifInterface .TAG_EXIF_VERSION ,
361+ ExifInterface .TAG_EXPOSURE_BIAS_VALUE ,
362+ ExifInterface .TAG_EXPOSURE_INDEX ,
363+ ExifInterface .TAG_EXPOSURE_MODE ,
301364 ExifInterface .TAG_EXPOSURE_TIME ,
365+ ExifInterface .TAG_EXPOSURE_PROGRAM ,
302366 ExifInterface .TAG_FLASH ,
367+ ExifInterface .TAG_FLASH_ENERGY ,
303368 ExifInterface .TAG_FOCAL_LENGTH ,
369+ ExifInterface .TAG_FOCAL_LENGTH_IN_35MM_FILM ,
370+ ExifInterface .TAG_FOCAL_PLANE_RESOLUTION_UNIT ,
371+ ExifInterface .TAG_FOCAL_PLANE_X_RESOLUTION ,
372+ ExifInterface .TAG_FOCAL_PLANE_Y_RESOLUTION ,
373+ ExifInterface .TAG_PHOTOMETRIC_INTERPRETATION ,
374+ ExifInterface .TAG_PLANAR_CONFIGURATION ,
375+ ExifInterface .TAG_F_NUMBER ,
376+ ExifInterface .TAG_GAIN_CONTROL ,
377+ ExifInterface .TAG_GAMMA ,
304378 ExifInterface .TAG_GPS_ALTITUDE ,
305379 ExifInterface .TAG_GPS_ALTITUDE_REF ,
380+ ExifInterface .TAG_GPS_AREA_INFORMATION ,
306381 ExifInterface .TAG_GPS_DATESTAMP ,
382+ ExifInterface .TAG_GPS_DOP ,
307383 ExifInterface .TAG_GPS_LATITUDE ,
308384 ExifInterface .TAG_GPS_LATITUDE_REF ,
309385 ExifInterface .TAG_GPS_LONGITUDE ,
310386 ExifInterface .TAG_GPS_LONGITUDE_REF ,
387+ ExifInterface .TAG_GPS_STATUS ,
388+ ExifInterface .TAG_GPS_DEST_BEARING ,
389+ ExifInterface .TAG_GPS_DEST_BEARING_REF ,
390+ ExifInterface .TAG_GPS_DEST_DISTANCE ,
391+ ExifInterface .TAG_GPS_DEST_DISTANCE_REF ,
392+ ExifInterface .TAG_GPS_DEST_LATITUDE ,
393+ ExifInterface .TAG_GPS_DEST_LATITUDE_REF ,
394+ ExifInterface .TAG_GPS_DEST_LONGITUDE ,
395+ ExifInterface .TAG_GPS_DEST_LONGITUDE_REF ,
396+ ExifInterface .TAG_GPS_DIFFERENTIAL ,
397+ ExifInterface .TAG_GPS_IMG_DIRECTION ,
398+ ExifInterface .TAG_GPS_IMG_DIRECTION_REF ,
399+ ExifInterface .TAG_GPS_MAP_DATUM ,
400+ ExifInterface .TAG_GPS_MEASURE_MODE ,
311401 ExifInterface .TAG_GPS_PROCESSING_METHOD ,
402+ ExifInterface .TAG_GPS_SATELLITES ,
403+ ExifInterface .TAG_GPS_SPEED ,
404+ ExifInterface .TAG_GPS_SPEED_REF ,
405+ ExifInterface .TAG_GPS_STATUS ,
312406 ExifInterface .TAG_GPS_TIMESTAMP ,
313- ExifInterface .TAG_IMAGE_LENGTH ,
314- ExifInterface .TAG_IMAGE_WIDTH ,
407+ ExifInterface .TAG_GPS_TRACK ,
408+ ExifInterface .TAG_GPS_TRACK_REF ,
409+ ExifInterface .TAG_GPS_VERSION_ID ,
410+ ExifInterface .TAG_IMAGE_DESCRIPTION ,
411+ ExifInterface .TAG_IMAGE_UNIQUE_ID ,
412+ ExifInterface .TAG_ISO_SPEED ,
413+ ExifInterface .TAG_PHOTOGRAPHIC_SENSITIVITY ,
414+ ExifInterface .TAG_JPEG_INTERCHANGE_FORMAT ,
415+ ExifInterface .TAG_JPEG_INTERCHANGE_FORMAT_LENGTH ,
416+ ExifInterface .TAG_LENS_MAKE ,
417+ ExifInterface .TAG_LENS_MODEL ,
418+ ExifInterface .TAG_LENS_SERIAL_NUMBER ,
419+ ExifInterface .TAG_LENS_SPECIFICATION ,
420+ ExifInterface .TAG_LIGHT_SOURCE ,
315421 ExifInterface .TAG_MAKE ,
422+ ExifInterface .TAG_MAKER_NOTE ,
316423 ExifInterface .TAG_MODEL ,
317424 ExifInterface .TAG_ORIENTATION ,
318- ExifInterface .TAG_SUBSEC_TIME ,
425+ ExifInterface .TAG_SATURATION ,
426+ ExifInterface .TAG_SHARPNESS ,
427+ ExifInterface .TAG_SHUTTER_SPEED_VALUE ,
428+ ExifInterface .TAG_SOFTWARE ,
429+ ExifInterface .TAG_SUBJECT_DISTANCE ,
430+ ExifInterface .TAG_SUBJECT_DISTANCE_RANGE ,
431+ ExifInterface .TAG_SUBJECT_LOCATION ,
432+ ExifInterface .TAG_USER_COMMENT ,
319433 ExifInterface .TAG_WHITE_BALANCE
320434 )
321435
322436 // Utils
437+ private fun getOrientation (context : Context , uri : Uri ): Int {
438+ val file = getFileFromUri(context, uri)
439+ if (file == null ) {
440+ return 0
441+ }
442+ val exif = ExifInterface (file.absolutePath)
443+ return when (
444+ exif.getAttributeInt(
445+ ExifInterface .TAG_ORIENTATION ,
446+ ExifInterface .ORIENTATION_NORMAL
447+ )
448+ ) {
449+ ExifInterface .ORIENTATION_ROTATE_90 -> 90
450+ ExifInterface .ORIENTATION_ROTATE_180 -> 180
451+ ExifInterface .ORIENTATION_ROTATE_270 -> 270
452+ else -> 0
453+ }
454+ }
455+
323456 @Throws(IOException ::class )
324457 private fun copyExif (context : Context , oldImage : Uri , newFile : File ) {
325458 val oldFile = getFileFromUri(context, oldImage)
0 commit comments