### Construct EXIF Header Source: https://context7.com/dsoprea/go-exif/llms.txt Shows how to build a raw EXIF header using specific byte orders and IFD offsets. This is useful for creating EXIF data structures from scratch. ```go package main import ( "fmt" "encoding/binary" "github.com/dsoprea/go-exif/v3" ) func main() { // Build EXIF header with big-endian byte order // First IFD at standard offset 0x08 headerBytes, err := exif.BuildExifHeader( binary.BigEndian, exif.ExifDefaultFirstIfdOffset) if err != nil { panic(err) } // Verify by parsing back header, err := exif.ParseExifHeader(headerBytes) if err != nil { panic(err) } fmt.Printf("Header: %v\n", header) fmt.Printf("Header bytes: % x\n", headerBytes) } ``` -------------------------------- ### Work with GPS Coordinates in Degrees/Minutes/Seconds - Go Source: https://context7.com/dsoprea/go-exif/llms.txt Demonstrates how to create GPS coordinates from rational values (degrees, minutes, seconds) and convert them to decimal degrees using the go-exif library. It also shows how to convert coordinates back to their raw rational format. ```go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { // Create GPS coordinates from rational values // Latitude: 26° 35' 12" N latRationals := []exifcommon.Rational{ {Numerator: 26, Denominator: 1}, {Numerator: 35, Denominator: 1}, {Numerator: 12, Denominator: 1}, } latitude, err := exif.NewGpsDegreesFromRationals("N", latRationals) if err != nil { panic(err) } fmt.Printf("Latitude: %s\n", latitude.String()) fmt.Printf("Decimal: %.6f\n", latitude.Decimal()) // Longitude: 80° 3' 14" W lonRationals := []exifcommon.Rational{ {Numerator: 80, Denominator: 1}, {Numerator: 3, Denominator: 1}, {Numerator: 14, Denominator: 1}, } longitude, err := exif.NewGpsDegreesFromRationals("W", lonRationals) if err != nil { panic(err) } fmt.Printf("Longitude: %s\n", longitude.String()) fmt.Printf("Decimal: %.6f\n", longitude.Decimal()) // Convert back to rationals for writing rawLat := latitude.Raw() fmt.Printf("Raw rationals: %v\n", rawLat) } ``` -------------------------------- ### BuildExifHeader - Create EXIF Header Source: https://context7.com/dsoprea/go-exif/llms.txt Explains how to construct the initial EXIF header bytes, specifying byte order and the offset to the first IFD. This is useful when creating EXIF data from scratch. ```APIDOC ## BuildExifHeader - Create EXIF Header ### Description Constructs the EXIF header bytes with the specified byte order and first IFD offset. Used when building EXIF data from scratch. ### Method POST (Conceptual - This is a library function, not a direct HTTP endpoint) ### Endpoint N/A ### Parameters N/A (This is a Go function call) ### Request Example ```go // Build EXIF header with big-endian byte order // First IFD at standard offset 0x08 headerBytes, err := exif.BuildExifHeader( binary.BigEndian, exif.ExifDefaultFirstIfdOffset) ``` ### Response #### Success Response (200) - **headerBytes** ([]byte) - The generated EXIF header bytes. #### Response Example ``` [0x4d 0x4d 0x00 0x2a 0x00 0x00 0x00 0x08] ``` ``` -------------------------------- ### Add Child IFDs (EXIF, GPS) with go-exif Source: https://context7.com/dsoprea/go-exif/llms.txt Illustrates how to construct a new EXIF structure by adding child IFDs, specifically for EXIF and GPS information. It shows the creation of individual IFD builders, adding standard tags to them, and then linking them as children to a root IFD. Finally, it encodes the complete EXIF structure. This is useful for creating new EXIF data from scratch or adding specific metadata groups. ```go package main import ( "fmt" "encoding/binary" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() byteOrder := binary.LittleEndian // Create root IFD rootIb := exif.NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, byteOrder) // Add basic camera info rootIb.AddStandardWithName("Make", "TestCamera") rootIb.AddStandardWithName("Model", "TC-100") // Create EXIF sub-IFD exifIb := exif.NewIfdBuilder(im, ti, exifcommon.IfdExifStandardIfdIdentity, byteOrder) // Add EXIF-specific tags exifIb.AddStandardWithName("DateTimeOriginal", "2023:06:15 14:30:00") exifIb.AddStandardWithName("ExposureTime", []exifcommon.Rational{{1, 125}}) exifIb.AddStandardWithName("FNumber", []exifcommon.Rational{{28, 10}}) exifIb.AddStandardWithName("ISOSpeedRatings", []uint16{400}) // Add EXIF IFD as child of root IFD err = rootIb.AddChildIb(exifIb) if err != nil { panic(err) } // Create GPS sub-IFD gpsIb := exif.NewIfdBuilder(im, ti, exifcommon.IfdGpsInfoStandardIfdIdentity, byteOrder) // Add GPS version gpsIb.AddStandardWithName("GPSVersionID", []byte{2, 3, 0, 0}) // Add latitude (26.586667 N) gpsIb.AddStandardWithName("GPSLatitudeRef", "N") gpsIb.AddStandardWithName("GPSLatitude", []exifcommon.Rational{ {26, 1}, {35, 1}, {12, 1}, }) // Add longitude (80.053889 W) gpsIb.AddStandardWithName("GPSLongitudeRef", "W") gpsIb.AddStandardWithName("GPSLongitude", []exifcommon.Rational{ {80, 1}, {3, 1}, {14, 1}, }) // Add GPS IFD as child err = rootIb.AddChildIb(gpsIb) if err != nil { panic(err) } // Encode complete EXIF structure ibe := exif.NewIfdByteEncoder() exifData, err := ibe.EncodeToExif(rootIb) if err != nil { panic(err) } fmt.Printf("Created EXIF with child IFDs: %d bytes\n", len(exifData)) // Output: Created EXIF with child IFDs: 298 bytes } ``` -------------------------------- ### Create and Modify EXIF Data with IfdBuilder Source: https://context7.com/dsoprea/go-exif/llms.txt Demonstrates how to create an IFD builder using the go-exif library to construct or modify EXIF data. This allows for adding, updating, or removing tags. It requires the go-exif/v3 and its common package. The output is the encoded EXIF byte data. ```go package main import ( "fmt" "encoding/binary" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() // Create a new IFD builder for the root IFD ib := exif.NewIfdBuilder( im, ti, exifcommon.IfdStandardIfdIdentity, binary.LittleEndian) // Add standard tags using tag names err = ib.AddStandardWithName("Make", "MyCamera") if err != nil { panic(err) } err = ib.AddStandardWithName("Model", "Model X") if err != nil { panic(err) } err = ib.AddStandardWithName("DateTime", "2023:06:15 10:30:00") if err != nil { panic(err) } // Add orientation tag by ID err = ib.AddStandard(0x0112, []uint16{1}) // Orientation = Normal if err != nil { panic(err) } // Encode to EXIF bytes ibe := exif.NewIfdByteEncoder() exifData, err := ibe.EncodeToExif(ib) if err != nil { panic(err) } fmt.Printf("Created EXIF data: %d bytes\n", len(exifData)) } ``` -------------------------------- ### Lookup and Register EXIF Tags Source: https://context7.com/dsoprea/go-exif/llms.txt Explains how to use the TagIndex to retrieve tag information by ID or name, and how to register custom tags for specific IFD paths. ```go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { // Create tag index (auto-loads standard tags) ti := exif.NewTagIndex() // Look up tag by ID tag, err := ti.Get(exifcommon.IfdStandardIfdIdentity, 0x010f) if err != nil { panic(err) } fmt.Printf("Tag 0x010f: %s (supports %v)\n", tag.Name, tag.SupportedTypes) // Look up tag by name tag, err = ti.GetWithName(exifcommon.IfdExifStandardIfdIdentity, "ExposureTime") if err != nil { panic(err) } fmt.Printf("ExposureTime: ID=0x%04x\n", tag.Id) // Register a custom tag customTag := &exif.IndexedTag{ Id: 0x9999, Name: "MyCustomTag", IfdPath: "IFD", SupportedTypes: []exifcommon.TagTypePrimitive{exifcommon.TypeASCII}, } err = ti.Add(customTag) if err != nil { panic(err) } // Enable universal search (find tags in any IFD) ti.SetUniversalSearch(true) fmt.Println("Tag index configured") } ``` -------------------------------- ### Set Thumbnail in EXIF IFD Source: https://context7.com/dsoprea/go-exif/llms.txt Demonstrates how to create an IFD structure, add standard tags, and attach a JPEG thumbnail to the second IFD (IFD1). It requires the go-exif library and a valid thumbnail file. ```go package main import ( "fmt" "io/ioutil" "encoding/binary" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() byteOrder := binary.LittleEndian // Create root IFD (IFD0) ifd0 := exif.NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity, byteOrder) ifd0.AddStandardWithName("Make", "TestCamera") ifd0.AddStandardWithName("Model", "TC-100") // Create IFD1 for thumbnail ifd1 := exif.NewIfdBuilder(im, ti, exifcommon.IfdStandardIfdIdentity.NewSibling(1), byteOrder) // Add compression tag (6 = JPEG compression) ifd1.AddStandard(0x0103, []uint16{6}) // Read thumbnail image data thumbnailData, err := ioutil.ReadFile("thumbnail.jpg") if err != nil { panic(err) } // Set the thumbnail err = ifd1.SetThumbnail(thumbnailData) if err != nil { panic(err) } // Link IFD1 to IFD0 err = ifd0.SetNextIb(ifd1) if err != nil { panic(err) } // Encode EXIF with thumbnail ibe := exif.NewIfdByteEncoder() exifData, err := ibe.EncodeToExif(ifd0) if err != nil { panic(err) } fmt.Printf("Created EXIF with thumbnail: %d bytes\n", len(exifData)) } ``` -------------------------------- ### Enumerate Tags with Callback Function (Go) Source: https://context7.com/dsoprea/go-exif/llms.txt Recursively visits all tags within the EXIF data, executing a provided callback function for each tag encountered. This method is suitable for streaming access or when memory efficiency is a concern, as it avoids loading all data at once. It depends on the go-exif library. ```Go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { panic(err) } im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() // Define visitor callback visitor := func(ite *exif.IfdTagEntry) error { tagId := ite.TagId() ifdPath := ite.IfdPath() // Get formatted value value, err := ite.FormatFirst() if err != nil { return nil // Skip unparseable tags } fmt.Printf("[%s] 0x%04x: %s = %s\n", ifdPath, tagId, ite.TagName(), value) return nil } // Visit all tags _, furthestOffset, err := exif.Visit( exifcommon.IfdStandardIfdIdentity, im, ti, rawExif, visitor, nil) if err != nil { panic(err) } fmt.Printf("Furthest offset in EXIF: %d bytes\n", furthestOffset) // Output: // [IFD] 0x010f: Make = Canon // [IFD] 0x0110: Model = Canon EOS 5D Mark III // [IFD/Exif] 0x829a: ExposureTime = 1/640 // ... } ``` -------------------------------- ### Modify Existing EXIF Data with go-exif Source: https://context7.com/dsoprea/go-exif/llms.txt Demonstrates how to create an IFD builder from existing EXIF data, modify specific tags (like 'Artist'), and delete others (like 'Copyright'). It then encodes the modified data back into EXIF format. This is useful for updating metadata in existing images without re-encoding the entire image. ```go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { panic(err) } im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() // Parse existing EXIF _, index, err := exif.Collect(im, ti, rawExif) if err != nil { panic(err) } // Create builder from existing IFD chain rootIb := exif.NewIfdBuilderFromExistingChain(index.RootIfd) // Update an existing tag (Set will add or replace) err = rootIb.SetStandardWithName("Artist", "John Doe") if err != nil { panic(err) } // Delete a tag err = rootIb.DeleteFirst(0x8298) // Copyright tag if err != nil && err != exif.ErrTagEntryNotFound { panic(err) } // Encode modified EXIF ibe := exif.NewIfdByteEncoder() newExifData, err := ibe.EncodeToExif(rootIb) if err != nil { panic(err) } fmt.Printf("Modified EXIF data: %d bytes\n", len(newExifData)) } ``` -------------------------------- ### Parse All IFDs and Tags into Index Structure (Go) Source: https://context7.com/dsoprea/go-exif/llms.txt Parses the entire EXIF data block of an image and constructs an index of all IFDs and their tags. This allows for convenient lookups by IFD path and tag ID. It requires the go-exif library and its common package. ```Go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { panic(err) } // Create IFD mapping and tag index im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() // Collect all IFDs and tags _, index, err := exif.Collect(im, ti, rawExif) if err != nil { panic(err) } // Access root IFD rootIfd := index.RootIfd fmt.Printf("Root IFD has %d entries\n", len(rootIfd.Entries())) // Iterate through tags for _, entry := range rootIfd.Entries() { tagName := entry.TagName() value, err := entry.Format() if err != nil { continue } fmt.Printf("Tag: %s = %s\n", tagName, value) } // Access specific IFD by path exifIfd, found := index.Lookup["IFD/Exif"] if found { fmt.Printf("Exif IFD has %d entries\n", len(exifIfd.Entries())) } // Output: // Root IFD has 11 entries // Tag: Make = Canon // Tag: Model = Canon EOS 5D Mark III // ... } ``` -------------------------------- ### Extract EXIF Data from File using Go Source: https://context7.com/dsoprea/go-exif/llms.txt This Go code snippet demonstrates how to extract raw EXIF data from a JPEG file using the `SearchFileAndExtractExif` function. It handles cases where no EXIF data is found and panics on other errors. The output shows the number of bytes of EXIF data found. ```go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { // Extract raw EXIF bytes from a JPEG file rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { if err == exif.ErrNoExif { fmt.Println("No EXIF data found in file") return } panic(err) } fmt.Printf("Found EXIF data: %d bytes\n", len(rawExif)) // Output: Found EXIF data: 32935 bytes } ``` -------------------------------- ### ExifReadSeeker - Data Layer Abstraction - Go Source: https://context7.com/dsoprea/go-exif/llms.txt Illustrates how to use ExifReadSeeker to abstract the data layer for reading EXIF data from different sources, such as byte slices and io.ReadSeeker interfaces. This enables flexible handling of EXIF data from files or memory. ```go package main import ( "fmt" "os" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { // Method 1: Create from byte slice rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { panic(err) } ebsFromBytes := exif.NewExifReadSeekerWithBytes(rawExif) // Method 2: Create from io.ReadSeeker f, err := os.Open("/path/to/image.jpg") if err != nil { panic(err) } defer f.Close() ebsFromFile := exif.NewExifReadSeeker(f) // Both can be used with IfdEnumerate im, _ := exifcommon.NewIfdMappingWithStandard() ti := exif.NewTagIndex() header, _ := exif.ParseExifHeader(rawExif) ie := exif.NewIfdEnumerate(im, ti, ebsFromBytes, header.ByteOrder) // Collect IFDs index, err := ie.Collect(header.FirstIfdOffset) if err != nil { panic(err) } fmt.Printf("Found %d IFDs\n", len(index.Ifds)) _ = ebsFromFile // Can be used similarly } ``` -------------------------------- ### Extract EXIF Data from io.Reader using Go Source: https://context7.com/dsoprea/go-exif/llms.txt This Go code snippet demonstrates extracting EXIF data from an `io.Reader` interface using `SearchAndExtractExifWithReader`. This method is suitable for streaming data, such as from network connections or other I/O sources, without needing to load the entire image into memory. ```go package main import ( "fmt" "os" "github.com/dsoprea/go-exif/v3" ) func main() { f, err := os.Open("/path/to/image.jpg") if err != nil { panic(err) } defer f.Close() // Extract EXIF using io.Reader interface rawExif, err := exif.SearchAndExtractExifWithReader(f) if err != nil { panic(err) } fmt.Printf("Found EXIF data: %d bytes\n", len(rawExif)) } ``` -------------------------------- ### Parse EXIF Header Information using Go Source: https://context7.com/dsoprea/go-exif/llms.txt This Go code snippet illustrates how to parse the EXIF header from raw EXIF data using `ParseExifHeader`. It determines the byte order (endianness) and the offset to the first Image File Directory (IFD). This is a foundational step for deeper EXIF data analysis. ```go package main import ( "fmt" "encoding/binary" "github.com/dsoprea/go-exif/v3" ) func main() { rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { panic(err) } // Parse the EXIF header header, err := exif.ParseExifHeader(rawExif) if err != nil { panic(err) } fmt.Printf("Byte Order: %v\n", header.ByteOrder) fmt.Printf("First IFD Offset: 0x%04x\n", header.FirstIfdOffset) // Output: // Byte Order: LittleEndian // First IFD Offset: 0x0008 } ``` -------------------------------- ### Extract EXIF Data from Byte Slice using Go Source: https://context7.com/dsoprea/go-exif/llms.txt This Go code snippet shows how to extract EXIF data from an in-memory byte slice using `SearchAndExtractExif`. It first reads an image file into a byte slice and then processes it. This is useful when image data is already loaded into memory. ```go package main import ( "fmt" "io/ioutil" "github.com/dsoprea/go-exif/v3" ) func main() { // Read image file into memory imageData, err := ioutil.ReadFile("/path/to/image.jpg") if err != nil { panic(err) } // Extract EXIF from byte slice rawExif, err := exif.SearchAndExtractExif(imageData) if err != nil { if err == exif.ErrNoExif { fmt.Println("No EXIF data found") return } panic(err) } fmt.Printf("Extracted %d bytes of EXIF data\n", len(rawExif)) } ``` -------------------------------- ### Find Specific EXIF Tag by Name (Go) Source: https://context7.com/dsoprea/go-exif/llms.txt Searches within a given IFD for a tag that matches a specified name. This function typically returns a single tag entry if found, or an error if the tag does not exist. It's useful for directly accessing known EXIF fields. Requires the go-exif library. ```Go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { panic(err) } im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() _, index, err := exif.Collect(im, ti, rawExif) if err != nil { panic(err) } rootIfd := index.RootIfd // Find the "Make" tag results, err := rootIfd.FindTagWithName("Make") if err != nil { if err == exif.ErrTagNotFound { fmt.Println("Make tag not found") return } panic(err) } // Get the value value, err := results[0].Value() if err != nil { panic(err) } fmt.Printf("Camera Make: %s\n", value.(string)) // Output: Camera Make: Canon } ``` -------------------------------- ### TagIndex - Tag Lookup and Registration Source: https://context7.com/dsoprea/go-exif/llms.txt Details the functionality of the TagIndex, which allows for looking up EXIF tags by their ID or name, and also supports registering custom tags. ```APIDOC ## TagIndex - Tag Lookup and Registration ### Description Provides tag lookup by ID or name and supports registration of custom tags. ### Method GET/POST (Conceptual - This is a library class/methods, not direct HTTP endpoints) ### Endpoint N/A ### Parameters N/A (This is a Go class/methods) ### Request Example ```go // Create tag index (auto-loads standard tags) ti := exif.NewTagIndex() // Look up tag by ID tag, err := ti.Get(exifcommon.IfdStandardIfdIdentity, 0x010f) // Register a custom tag customTag := &exif.IndexedTag{ Id: 0x9999, Name: "MyCustomTag", IfdPath: "IFD", SupportedTypes: []exifcommon.TagTypePrimitive{exifcommon.TypeASCII}, } err = ti.Add(customTag) ``` ### Response #### Success Response (200) - **tag** (*exif.IndexedTag) - The found tag information. - **err** (error) - Nil on success. #### Response Example ``` Tag 0x010f: Make (supports [ASCII]) ExposureTime: ID=0x829a Tag index configured ``` ``` -------------------------------- ### IfdBuilder.SetThumbnail - Add Thumbnail to EXIF Source: https://context7.com/dsoprea/go-exif/llms.txt Demonstrates how to add thumbnail data to an EXIF IFD (Image File Directory). The thumbnail is typically set on IFD1 and linked to IFD0. ```APIDOC ## IfdBuilder.SetThumbnail - Add Thumbnail to EXIF ### Description Sets thumbnail data in the IFD. The thumbnail should be set on the second IFD (IFD1) in the chain. ### Method POST (Conceptual - This is a library function, not a direct HTTP endpoint) ### Endpoint N/A ### Parameters N/A (This is a Go function call) ### Request Example ```go // Assuming thumbnailData is a byte slice containing the thumbnail image err := ifd1.SetThumbnail(thumbnailData) ``` ### Response #### Success Response (0) No explicit return value on success, error is nil. #### Response Example N/A ``` -------------------------------- ### Extract GPS Coordinates from EXIF Source: https://context7.com/dsoprea/go-exif/llms.txt Parses GPS information from the GPS IFD of an image's EXIF data. It returns a structured GpsInfo object containing latitude, longitude, altitude, and timestamp. Dependencies include the go-exif/v3 library. Input is an image file path, and output is formatted GPS data. ```go package main import ( "fmt" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { rawExif, err := exif.SearchFileAndExtractExif("/path/to/geotagged-image.jpg") if err != nil { panic(err) } im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() _, index, err := exif.Collect(im, ti, rawExif) if err != nil { panic(err) } // Get the GPS IFD gpsIfd, found := index.Lookup["IFD/GPSInfo"] if !found { fmt.Println("No GPS IFD found") return } // Parse GPS information gpsInfo, err := gpsIfd.GpsInfo() if err != nil { if err == exif.ErrNoGpsTags { fmt.Println("No GPS coordinates in this image") return } panic(err) } // Access GPS data fmt.Printf("Latitude: %.6f\n", gpsInfo.Latitude.Decimal()) fmt.Printf("Longitude: %.6f\n", gpsInfo.Longitude.Decimal()) fmt.Printf("Altitude: %d meters\n", gpsInfo.Altitude) fmt.Printf("Timestamp: %s\n", gpsInfo.Timestamp) // Get S2 Cell ID for geospatial indexing cellId := gpsInfo.S2CellId() fmt.Printf("S2 Cell ID: %d\n", cellId) } ``` -------------------------------- ### Extract Embedded Thumbnail from EXIF Source: https://context7.com/dsoprea/go-exif/llms.txt Extracts the thumbnail image embedded within an image's EXIF data, typically stored in IFD1. This function requires the go-exif/v3 library. It takes an image file path as input and outputs the raw thumbnail data, which can then be saved to a file. ```go package main import ( "fmt" "io/ioutil" "github.com/dsoprea/go-exif/v3" "github.com/dsoprea/go-exif/v3/common" ) func main() { rawExif, err := exif.SearchFileAndExtractExif("/path/to/image.jpg") if err != nil { panic(err) } im, err := exifcommon.NewIfdMappingWithStandard() if err != nil { panic(err) } ti := exif.NewTagIndex() _, index, err := exif.Collect(im, ti, rawExif) if err != nil { panic(err) } // Get IFD1 which contains the thumbnail ifd1, found := index.Lookup["IFD1"] if !found { fmt.Println("No IFD1 found") return } // Extract thumbnail thumbnailData, err := ifd1.Thumbnail() if err != nil { if err == exif.ErrNoThumbnail { fmt.Println("No thumbnail in this image") return } panic(err) } // Save thumbnail to file err = ioutil.WriteFile("thumbnail.jpg", thumbnailData, 0644) if err != nil { panic(err) } fmt.Printf("Saved thumbnail: %d bytes\n", len(thumbnailData)) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.