最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

reactjs - I can't get the GPS metadata of an image on Android React Native, most show 0 and some 01, 01, 01 - Stack Over

programmeradmin6浏览0评论

I can't get the GPS metadata of an image on Android React Native, I've tested many libraries, most show 0 and some 0/1, 0/1, 0/1, but they are not the correct GPS coordinates.

i tested many libraries but it cant get the correct values of gps:

import React, { useEffect, useState } from "react";
import { Text, View, TouchableOpacity, Image, Modal } from "react-native";
import ImagePicker from "react-native-image-crop-picker";
import { requestPermission } from "../../utils/nativeFunctions";
import { getStyles } from "./styles";
import { useTheme } from "@trizyapp/sdk";
import { CameraIcon, GaleriaIcon } from "../../assets/icons";
import { parse } from "date-fns";
import { writeAsync, readAsync, ExifTags } from "@lodev09/react-native-exify";
import { PermissionsAndroid } from "react-native";

import { convertCoordinates } from "../../utils/convertCoordenadas";
interface Props {
  resource: string;
  setResource: (resource: any) => void;
  onlyModal?: boolean;
  openModal?: boolean;
  handleClose?: () => void;
  setOpenModal?: (openModal: boolean) => void;
}

const CustomImagePicker = ({
  resource,
  setResource,
  onlyModal = false,
  openModal = false,
  handleClose,
}: Props) => {
  const styles = getStyles({});
  const { color: colors, spaces } = useTheme();
  const [openButtonsModal, setOpenButtonsModal] = useState(false);

  const handlePress = () => {
    setOpenButtonsModal(true);
  };

  useEffect(() => {
    if (openModal && !openButtonsModal) {
      setOpenButtonsModal(true);
    }
  }, [openModal]);

  const handleModalClose = () => {
    setOpenButtonsModal(false);
    handleClose && handleClose();
  };

  const extractMetadata = (exifData: any) => {
    if (!exifData) {
      return {
        data_evidencia: null,
        latitude: null,
        longitude: null,
      };
    }

    let latitude = null;
    let longitude = null;

    if (exifData.GPS && exifData.GPS.Latitude && exifData.GPS.Longitude) {
      latitude = exifData.GPS.Latitude;
      longitude = exifData.GPS.Longitude;
    } else if (
      exifData.GPSLatitude !== undefined &&
      exifData.GPSLongitude !== undefined
    ) {
      latitude = exifData.GPSLatitude;
      longitude = exifData.GPSLongitude;
    } else if (
      exifData.latitude !== undefined &&
      exifData.longitude !== undefined
    ) {
      latitude = exifData.latitude;
      longitude = exifData.longitude;
    }

    let dataEvidencia = null;

    const dateFields = [
      "DateTime",
      "DateTimeOriginal",
      "DateTimeDigitized",
      "creationDate",
    ];

    for (const field of dateFields) {
      if (exifData[field]) {
        try {
          let dateString = exifData[field];

          if (dateString.includes(":")) {
            dateString = dateString.replace(
              /^(\d{4}):(\d{2}):(\d{2})/,
              "$1-$2-$3"
            );
            dataEvidencia = parse(
              dateString,
              "yyyy-MM-dd HH:mm:ss",
              new Date()
            );
          } else {
            dataEvidencia = new Date(dateString);
          }

          if (!isNaN(dataEvidencia.getTime())) {
            break;
          }
        } catch (e) {
          console.log(`Error parsing date from ${field}:`, e);
        }
      }
    }

    return {
      data_evidencia: dataEvidencia,
      ...convertCoordinates(longitude, latitude),
    };
  };

  const selectFile = async (tipo: string) => {
    try {
      let permissao = false;

      if (tipo === "camera") {
        permissao = await requestPermission({ tipo: "camera" });
        permissao = await requestPermission({ tipo: "localizacao_midia" });
      } else {
        permissao = await requestPermission({ tipo: "galeria" });
        permissao = await requestPermission({
          tipo: "ler_armazenamento_externo",
        });
        permissao = await requestPermission({ tipo: "localizacao_midia" });
        console.log("Permissão de localizacao_midia", permissao);
      }

      console.log(
        "Status real das permissões:",
        await PermissionsAndroid.check(
          PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
        ),
        await PermissionsAndroid.check(
          PermissionsAndroid.PERMISSIONS.ACCESS_MEDIA_LOCATION
        )
      );

      if (permissao) {
        const options = {
          width: 1000,
          height: 1000,
          cropping: false,
          includeExif: true,
          includeExtra: true,
          compressImageQuality: 0.8,
          forceJpg: true,
        };

        let result = null;

        if (tipo === "camera") {
          permissao = await requestPermission({ tipo: "localizacao" });
          console.log("Permissão de localização:", permissao);
          result = await ImagePicker.openCamera({
            ...options,
            useFrontCamera: false,
          });
        } else {
          result = await ImagePicker.openPicker(options);
        }

        if (result) {
          const imagePath = result.path;

          const tags = await readAsync(imagePath);
          console.log(tags);

          // const tags = await readAsync(imagePath);
          console.log(
            "Raw image result:",
            JSON.stringify(
              {
                path: result.path,
                width: result.width,
                height: result.height,
                mime: result.mime,
                size: result.size,
                exif: result.exif
                  ? // Criar um novo objeto com pares chave-valor
                    Object.fromEntries(
                      Object.entries(result.exif).map(([key, value]) => [
                        key,
                        // Converter valores complexos para formato legível
                        value instanceof Object && !(value instanceof Array)
                          ? value.toString()
                          : value,
                      ])
                    )
                  : null,
              },
              null,
              2
            ) // Formatação com indentação
          );
          const metaData = extractMetadata(result.exif);
          setResource({ image: result.path, metaData });
        }
        handleModalClose();
      }
    } catch (error) {
      Promise.reject(error);
    }
  };

  const renderModal = () => {
    return (
      <Modal
        animationType="slide"
        transparent
        visible={openButtonsModal}
        onRequestClose={() => handleModalClose()}
      >
        <View style={styles.modalMain}>
          <View style={styles.modalView}>
            <View style={{ alignItems: "center" }}>
              <TouchableOpacity onPress={() => selectFile("camera")}>
                <CameraIcon
                  width={spaces.x4}
                  height={spaces.x4}
                  color={colors.grey600}
                />
              </TouchableOpacity>
              <Text style={styles.emptyText}>Câmera</Text>
            </View>
            <View style={{ alignItems: "center" }}>
              <TouchableOpacity onPress={() => selectFile("gallery")}>
                <GaleriaIcon
                  width={spaces.x4}
                  height={spaces.x4}
                  color={colors.grey600}
                />
              </TouchableOpacity>
              <Text style={styles.emptyText}>Galeria</Text>
            </View>
          </View>
        </View>
      </Modal>
    );
  };

  return onlyModal ? (
    renderModal()
  ) : (
    <View style={styles.container}>
      {resource && resource.length > 0 ? (
        <Image
          resizeMode="contain"
          source={{ uri: resource }}
          style={styles.image}
        />
      ) : (
        <TouchableOpacity onPress={handlePress} style={styles.emptyButton}>
          <GaleriaIcon
            width={spaces.x6}
            height={spaces.x6}
            color={colors.grey}
          />
          <Text style={styles.emptyText}>Insira seu arquivo aqui </Text>
          <Text style={styles.emptyText}>(.jpeg, .jpg ou png)</Text>
        </TouchableOpacity>
      )}

      {renderModal()}
    </View>
  );
};

export default CustomImagePicker;
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />


<application
  android:name=".MainApplication"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:allowBackup="false"
  android:theme="@style/AppTheme">
  <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
    android:launchMode="singleTask"
    android:windowSoftInputMode="adjustResize"
    android:exported="true"
    android:screenOrientation="portrait">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
</application>
import React, { useState } from "react";
import { View, Modal, TouchableOpacity } from "react-native";
import { getStyles } from "./styles";
import { useTheme, Button, CloseIcon, Text, SizedBox } from "@trizyapp/sdk";
import { ImagePicker, TextInput } from "../../../../components";
import { DeleteIcon, RefreshIcon, SendIcon } from "../../../../assets/icons";

interface Evidencia {
  imagem_url: string;
  legenda: string;
  data_evidencia: string | null;
  latitude?: number;
  longitude?: number;
}

interface Props {
  open: boolean;
  handleClose: () => void;
  handleRemove: () => void;
  evidencias?: Evidencia[];
  setEvidencias: (evidencias: Evidencia[]) => void;
}

const ModalEvidencia = ({
  open,
  handleClose,
  handleRemove,
  evidencias = [],
  setEvidencias,
}: Props) => {
  const styles = getStyles({});
  const { color: colors, spaces } = useTheme();
  const [openPicker, setOpenPicker] = useState(false);
  const [files, setFiles] = useState<Evidencia[]>(
    evidencias?.length > 0
      ? evidencias
      : [{ imagem_url: "", legenda: "", data_evidencia: null }]
  );

  const toggleModalPicker = () => setOpenPicker((prev) => !prev);

  const updateFile = (index: number, updatedData: Partial<Evidencia>) => {
    console.log(`Atualizando arquivo no índice ${index}:`, updatedData);
    setFiles((prevFiles) =>
      prevFiles.map((file, i) =>
        i === index ? { ...file, ...updatedData } : file
      )
    );
  };

  return (
    <Modal
      transparent
      animationType="slide"
      visible={open}
      onRequestClose={handleClose}
    >
      <View style={styles.modalMain}>
        <View style={styles.modalHeader}>
          <TouchableOpacity onPress={handleClose}>
            <CloseIcon color={"#FFF"} />
          </TouchableOpacity>
          <TouchableOpacity onPress={handleRemove}>
            <DeleteIcon />
          </TouchableOpacity>
        </View>

        <View style={styles.modalView}>
          <View style={styles.content}>
            {files.map((file, index) => (
              <View key={index}>
                <ImagePicker
                  openModal={openPicker}
                  handleClose={() => setOpenPicker(false)}
                  resource={file.imagem_url}
                  setResource={(newValue) =>
                    updateFile(index, {
                      imagem_url: newValue?.image,
                      data_evidencia: newValue?.metaData?.data_evidencia,
                      latitude: newValue?.metaData?.latitude,
                      longitude: newValue?.metaData?.longitude,
                    })
                  }
                />

                <TextInput
                  value={file.legenda}
                  onChangeText={(text) => updateFile(index, { legenda: text })}
                  numberOfLines={2}
                  placeholder="Inserir legenda"
                  maxLength={90}
                />
              </View>
            ))}
          </View>
        </View>

        <SizedBox height={spaces.x1} />

        <View style={styles.modalFooter}>
          <View style={styles.action}>
            <TouchableOpacity
              style={[styles.iconButton, styles.refresh]}
              onPress={toggleModalPicker}
            >
              <RefreshIcon />
            </TouchableOpacity>
            <Text fontColor="white" value="Ficou ruim" />
          </View>

          <View style={styles.action}>
            <TouchableOpacity
              style={[styles.iconButton, styles.send]}
              onPress={() => setEvidencias(files)}
              disabled={!files[0]?.imagem_url}
            >
              <SendIcon />
            </TouchableOpacity>
            <Text fontColor="white" value="Enviar" />
          </View>
        </View>
      </View>
    </Modal>
  );
};

export default ModalEvidencia;

Example of answer:

"path": "file:///storage/emulated/0/Android/data/com.formularios/files/Pictures/3307a61e-b805-49d5-85a7-950ca6b48530.jpg", "width": 2604, "height": 4624, "mime": "image/jpeg", "size": 302829, "exif": { "SubSecTimeOriginal": null, "SubSecTimeDigitized": null, "SubSecTime": null, "DateTimeDigitized": "2025:03:28 16:35:42", "Orientation": "6", "ImageLength": "2604", "GPSProcessingMethod": null, "Make": "samsung", "GPSLongitudeRef": "", "GPSLatitudeRef": "", "Flash": "0", "GPSLatitude": "0/1,0/1,0/1", "ImageWidth": "4624", "GPSDateStamp": null, "GPSAltitudeRef": null, "WhiteBalance": "0", "GPSAltitude": null, "FocalLength": "523/100", "ExposureTime": "0.1", "ISOSpeedRatings": "2500", "Latitude": 0, "DateTime": "2025:03:28 16:35:42", "Longitude": 0, "FNumber": "1.8", "Model": "SM-M315F", "GPSTimeStamp": null, "GPSLongitude": "0/1,0/1,0/1"

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论