GeoTagImage is an open-source Android SDK for GPS-based photo tagging, used in survey apps, property inspection, delivery tracking and GIS systems.
Captures Real-time Latitude, Longitude, and Altitude with high-accuracy GPS providers.
Automatically fetches and embeds a Google Map preview of the current location onto the photo.
Converts coordinates into human-readable addresses (City, State, Country) automatically.
Built on Google's modern CameraX API for smooth hardware abstraction and stability.
Modify font family, text size, color, and background transparency to match your branding.
Optimized image processing ensures minimal lag between capture and saving.
Handles complex Android 13+ location and camera permission flows out of the box.
Embed localized date and time stamps in multiple formats directly into the image pixels.
Choose between URI, File, or Bitmap outputs depending on your app's requirements.
Full support for both languages with idiomatic extensions for Kotlin users.
Select GPS priority, update intervals, and accuracy thresholds for enterprise-grade surveys.
Location caching ensures image tagging works even without internet connectivity.
Use only what you need: camera, location, overlays, or metadata injection.
Automatically handles Activity & Fragment lifecycle changes without memory leaks.
Fully compatible with Android 10+ scoped storage and MediaStore guidelines.
Clean APIs allow mocking of location and camera for unit and UI testing.
Capture proof-based images for land, utility, and infrastructure surveys.
Attach verified location data to real-estate and housing inspections.
Ensure location authenticity for compliance, audits, and verification apps.
Log timestamped, geotagged delivery images with zero manual effort.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven( url = "https://jitpack.io")
}
}
dependencies {
implementation "com.github.dangiashish:GeoTagImage:1.2.3"
}
<!-- Add inside application tag -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
class MainActivity : AppCompatActivity(), PermissionCallback {
private var gtiUri: Uri? = null
private lateinit var geoTagImage: GeoTagImage
private lateinit var cameraLauncher: ActivityResultLauncher<Uri>
private lateinit var permissionLauncher: ActivityResultLauncher<Array<String>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
}
}
permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val allGranted = permissions.all { it.value }
if (allGranted) onPermissionGranted()
else onPermissionDenied()
}
cameraLauncher =
registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) {
gtiUri = geoTagImage.processCapturedImage()
previewCapturedImage()
}
}
geoTagImage = GeoTagImage(this, permissionLauncher, cameraLauncher)
geoTagImage.requestCameraAndLocationPermissions()
binding.ivCamera.setOnClickListener {
geoTagImage.launchCamera(
onImageCaptured = { uri ->
gtiUri = uri
previewCapturedImage()
},
onFailure = {
Toast.makeText(mContext, it, Toast.LENGTH_SHORT).show()
}
)
}
geoTagImage.setTextSize(30f)
geoTagImage.setBackgroundRadius(5f)
geoTagImage.setBackgroundColor(Color.parseColor("#66000000"))
geoTagImage.setTextColor(Color.WHITE)
geoTagImage.setAuthorName("Ashish")
geoTagImage.showAuthorName(true)
geoTagImage.showAppName(true)
geoTagImage.setLabel("Clicked By")
geoTagImage.setCameraAspectRatio(GeoTagImage.Ratio_4X3)
private fun previewCapturedImage() {
gtiUri?.let { uri ->
val bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, uri))
else
MediaStore.Images.Media.getBitmap(contentResolver, uri)
binding.ivImage.setImageBitmap(bitmap)
}
}
override fun onPermissionGranted() {
}
override fun onPermissionDenied() {
geoTagImage.requestCameraAndLocationPermissions()
}
// Kotlin Usage
val geoTagImage = GeoTagImage(context, permissionLauncher, cameraLauncher)
geoTagImage.launchCamera(
onImageCaptured = { uri ->
// Logic after image is tagged
},
onFailure = { exception ->
Log.e("GTI", exception.message.toString())
}
)