Невозможно создать MotionPhoto, метаданные, не написанные по праву, или процесс создания файла неправильноAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Невозможно создать MotionPhoto, метаданные, не написанные по праву, или процесс создания файла неправильно

Сообщение Anonymous »

Я создаю приложение для Android означало, что объединить файл изображения и видеофайл с MotionPhoto. Я написал пользовательский интерфейс и логику в один файл для доказательства концепции. Код ниже. Но с приложением файла может просмотреть это изображение как статическое фото. < /P>

Код: Выделить всё

import android.media.MediaScannerConnection
import android.net.Uri
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowForward
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.exifinterface.media.ExifInterface
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import coil3.compose.AsyncImage
import java.io.File
import java.io.InputStream

@Composable
fun ImageItem(
getInputStream: (Uri) -> InputStream?
) {

var imageUri by remember { mutableStateOf(null) }
var videoUri by remember { mutableStateOf(null) }

var imageInputStream by remember { mutableStateOf(null) }
var videoInputStream by remember { mutableStateOf(null) }

val imagePicker =
rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
imageUri = uri
imageInputStream = getInputStream(uri)
} else {
Log.d("PhotoPicker", "No media selected")
}
}

val videoPicker =
rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
videoUri = uri
videoInputStream = getInputStream(uri)
} else {
Log.d("PhotoPicker", "No media selected")
}
}

Card {
Row(
modifier = Modifier.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.clip(
RoundedCornerShape(10.dp)
)
.border(
1.dp,
MaterialTheme.colorScheme.surfaceTint,
RoundedCornerShape(10.dp)
)
.clickable {
imagePicker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
.size(75.dp),
contentAlignment = Alignment.Center
) {
when (imageUri) {
null -> Image(
painter = painterResource(R.drawable.ic_image),
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.surfaceTint)
)

else ->  AsyncImage(
model = imageUri,
contentDescription = null,
contentScale = ContentScale.Crop
)
}
}

Spacer(modifier = Modifier.width(8.dp))
Box(
modifier = Modifier
.clip(
RoundedCornerShape(10.dp)
)
.border(
1.dp,
MaterialTheme.colorScheme.surfaceTint,
RoundedCornerShape(10.dp)
)
.clickable {
videoPicker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.VideoOnly))
}
.size(75.dp),
contentAlignment = Alignment.Center
) {
when (videoUri) {
null -> Image(
painter = painterResource(R.drawable.ic_video),
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.surfaceTint)
)

else -> {
val context = LocalContext.current
val exoPlayer = remember {
ExoPlayer.Builder(context).build().apply {
setMediaItem(MediaItem.fromUri(videoUri!!))
prepare()
playWhenReady = true
repeatMode = Player.REPEAT_MODE_ONE
}
}
PlayerSurface(
player = exoPlayer,
surfaceType = SURFACE_TYPE_SURFACE_VIEW
)
}
}
}
Spacer(modifier = Modifier.weight(1f))
val context = LocalContext.current
Icon(
Icons.AutoMirrored.Rounded.ArrowForward,
contentDescription = null,
modifier = Modifier.clickable {
if (imageInputStream != null &&  videoInputStream != null) {

// Create temp JPEG file to store image data and EXIF data
val tempImageFile =
File.createTempFile("temp_image", ".jpg", context.cacheDir)
val motionPhotoFile = File(
context.filesDir,
"dynamic_photo_${System.currentTimeMillis()}.MP.jpg"
)

try {
// Write the image to the temp file
tempImageFile.outputStream().use { imageOutput ->
imageInputStream?.copyTo(imageOutput)
}

// Write image and video to final file
var videoLength: Int
motionPhotoFile.outputStream().use { outputStream ->
// Write image data
tempImageFile.inputStream().use { it.copyTo(outputStream) }

// Record video offset
val videoStartOffset = outputStream.channel.position()

// Write video data
videoInputStream?.copyTo(outputStream)

// Record video length
videoLength = (outputStream.channel.size() - videoStartOffset).toInt()
}

android.util.Log.e("MotionPhoto", "stream size: ${videoInputStream?.readBytes()?.size}, length: $videoLength")
// Add EXIF and XMP metadata to temp file
val exifInterface = ExifInterface(motionPhotoFile)
exifInterface.setAttribute(ExifInterface.TAG_XMP, getXmpMetadata(videoLength))
exifInterface.saveAttributes()

MediaScannerConnection.scanFile(
context,
arrayOf(motionPhotoFile.absolutePath),
arrayOf("image/jpeg", "image/heic")
) { _, uri ->
Log.d("MotionPhoto", "Save success, URI: $uri")
}

} catch (e: Exception) {
Log.e("MotionPhoto", "MotionPhoto save failed: ${e.message}")
} finally {
// delete temp file
tempImageFile.delete()
}
} else {
Log.e("MotionPhoto", "Image or video input stream is null")
}
}
)

Spacer(modifier = Modifier.weight(1f))

Box(
modifier = Modifier
.border(
1.dp,
MaterialTheme.colorScheme.surfaceTint,
RoundedCornerShape(10.dp)
)
.size(75.dp),
contentAlignment = Alignment.Center
) {
when (videoUri) {
else -> Image(
painter = painterResource(R.drawable.ic_image),
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.surfaceTint)
)
}
}
}
}
}

@Preview(showBackground = true)
@Composable
fun ImageItemPreview() {
ImageItem { null }
}

fun getXmpMetadata(videoLengthInBytes: Int): String {
return """
















""".trimIndent()
}
Я ссылался на DOC о Formato Format Version 1.0
https://developer.android.com/media/pla ... matобразно Похоже, метаданные XMP MotionPhoto. Но я понятия не имею, как изменить свой код выше, чтобы написать их. Или неправильное место, которое я пытаюсь написать метаданные.>

Подробнее здесь: https://stackoverflow.com/questions/792 ... reating-fi
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»