Skip to content

Instantly share code, notes, and snippets.

@ashwani-rathee
Created March 3, 2023 15:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ashwani-rathee/b38b11cb9f020315baf142e6cf246f20 to your computer and use it in GitHub Desktop.
Save ashwani-rathee/b38b11cb9f020315baf142e6cf246f20 to your computer and use it in GitHub Desktop.
LibExif Issue
using Test,TestImages
using JpegTurbo
include("../lib/LibExif.jl")
include("../src/utils.jl")
include("../src/read.jl")
FILE_BYTE_ORDER = LibExif.EXIF_BYTE_ORDER_INTEL
function init_tag(exif, ifd, tag)
exif1 = unsafe_load(exif)
entry = LibExif.exif_content_get_entry(exif1.ifd[ifd], tag)
if entry == C_NULL
entry = LibExif.exif_entry_new()
entry.tag = tag
LibExif.exif_content_add_entry(exif1.ifd[ifd], entry)
LibExif.exif_entry_initialize(entry, tag)
LibExif.exif_entry_unref(entry)
end
return entry
end
function set_value(entry, tagv)
if entry.tag in [
LibExif.EXIF_TAG_COMPRESSION,
LibExif.EXIF_TAG_COLOR_SPACE,
LibExif.EXIF_TAG_SUBJECT_DISTANCE_RANGE,
LibExif.EXIF_TAG_ORIENTATION,
LibExif.EXIF_TAG_METERING_MODE,
LibExif.EXIF_TAG_SENSING_METHOD,
LibExif.EXIF_TAG_FLASH,
LibExif.EXIF_TAG_YCBCR_POSITIONING,
LibExif.EXIF_TAG_RESOLUTION_UNIT,
LibExif.EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT,
LibExif.EXIF_TAG_PLANAR_CONFIGURATION,
LibExif.EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
LibExif.EXIF_TAG_CUSTOM_RENDERED,
LibExif.EXIF_TAG_EXPOSURE_MODE,
LibExif.EXIF_TAG_WHITE_BALANCE,
LibExif.EXIF_TAG_SCENE_CAPTURE_TYPE,
LibExif.EXIF_TAG_GAIN_CONTROL,
LibExif.EXIF_TAG_SATURATION,
LibExif.EXIF_TAG_CONTRAST,
LibExif.EXIF_TAG_SHARPNESS
]
LibExif.exif_set_short(
entry.data,
LibExif.EXIF_BYTE_ORDER_INTEL,
TagsDict[entry.tag][tagv],
)
elseif entry.tag == LibExif.EXIF_TAG_FLASH_PIX_VERSION
data = Dict{String,String}(
"FlashPix Version 1.0" => "0100\0",
"FlashPix Version 1.01" => "0101\0",
"Unknown FlashPix Version" => "0000\0",
)
unsafe_copyto!(entry.data, pointer(Vector{UInt8}(data[tagv])), 5)
elseif (entry.tag in [LibExif.EXIF_TAG_MAKE, LibExif.EXIF_TAG_ARTIST, LibExif.EXIF_TAG_MODEL])
unsafe_copyto!(entry.data, pointer(Vector{UInt8}(tagv * "\0")), length(tagv) + 1)
elseif entry.tag in [
LibExif.EXIF_TAG_PIXEL_Y_DIMENSION,
LibExif.EXIF_TAG_PIXEL_X_DIMENSION,
LibExif.EXIF_TAG_X_RESOLUTION,
LibExif.EXIF_TAG_Y_RESOLUTION,
LibExif.EXIF_TAG_IMAGE_WIDTH,
LibExif.EXIF_TAG_IMAGE_LENGTH,
]
LibExif.exif_set_long(entry.data, FILE_BYTE_ORDER, parse(Cuint, tagv))
elseif entry.tag in [
LibExif.EXIF_TAG_EXPOSURE_TIME,
LibExif.EXIF_TAG_COMPRESSED_BITS_PER_PIXEL,
LibExif.EXIF_TAG_APERTURE_VALUE,
LibExif.EXIF_TAG_MAX_APERTURE_VALUE,
LibExif.EXIF_TAG_FOCAL_LENGTH,
LibExif.EXIF_TAG_FOCAL_PLANE_X_RESOLUTION,
LibExif.EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION,
]
p = rationalize(parse(Float32, tagv);tol=0.1)
LibExif.exif_set_rational(entry.data,FILE_BYTE_ORDER, LibExif.ExifRational(p.num, p.den))
elseif entry.tag in [LibExif.EXIF_TAG_SHUTTER_SPEED_VALUE, LibExif.EXIF_TAG_EXPOSURE_BIAS_VALUE]
p = Rational(parse(Float32, tagv))
LibExif.exif_set_srational(entry.data, FILE_BYTE_ORDER, LibExif.ExifSRational(p.num, p.den))
elseif entry.tag == LibExif.EXIF_TAG_FNUMBER
p = Rational(parse(Float32, split(tagv, "/")[2]))
LibExif.exif_set_rational(entry.data, FILE_BYTE_ORDER, LibExif.ExifRational(p.num, p.den))
else
println("Tag Not Supported")
end
end
function set_value1(entry, tagv)
@info "Entry:" entry
# @info entry.format entry.tag
if unsafe_load(entry.format) == LibExif.EXIF_FORMAT_SHORT
# if(entry.tag in keys(TagsDict))
# LibExif.exif_set_short(entry.data, LibExif.EXIF_BYTE_ORDER_INTEL, TagsDict[entry.tag][tagv])
# else
# LibExif.exif_set_long(entry.data, FILE_BYTE_ORDER, parse(Cuint, tagv))
# end
elseif unsafe_load(entry.format) == LibExif.EXIF_FORMAT_LONG
# LibExif.exif_set_long(entry.data, FILE_BYTE_ORDER, parse(Cuint, tagv))
elseif unsafe_load(entry.format) == LibExif.EXIF_FORMAT_ASCII
# unsafe_copyto!(unsafe_load(entry.data), pointer(Vector{UInt8}(tagv * "\0")), length(tagv) + 1)
elseif unsafe_load(entry.format) == LibExif.EXIF_FORMAT_RATIONAL
# @info "Rational Case:"
# p = rationalize(parse(Float32, tagv);tol=0.1)
# LibExif.exif_set_rational(entry.data,FILE_BYTE_ORDER, LibExif.ExifRational(p.num, p.den))
elseif unsafe_load(entry.format) == LibExif.EXIF_FORMAT_SRATIONAL
# p = Rational(parse(Float32, tagv))
# LibExif.exif_set_srational(entry.data, FILE_BYTE_ORDER, LibExif.ExifSRational(p.num, p.den))
else
# if unsafe_load(entry).format == LibExif.EXIF_FORMAT_UNDEFINED
@info "Undefined case: " tagv length(tagv)
@info "Value:" entry.size entry.components entry.format
unsafe_copyto!(entry.size, pointer(Vector{UInt32}([7])), 1)
unsafe_copyto!(entry.components, pointer(Vector{UInt32}([7])), 1)
unsafe_copyto!(entry.format, pointer(Vector{Main.LibExif.ExifFormat}([LibExif.EXIF_FORMAT_ASCII])), 1)
# entry1 = unsafe_load(entry)
# entry.size =7;
# entry.components = 7;
# entry.format = LibExif.EXIF_FORMAT_ASCII;
# @show entry.data
# mem = LibExif.exif_mem_new_default();
# len = length(tagv)+1;
# buf = LibExif.exif_mem_alloc(mem, len);
# @info "Buf: " buf
# unsafe_copyto!(buf, pointer(Vector{UInt8}(tagv * "\0")), length(tagv) + 1)
# # @info "Important:" Int(unsafe_load(buf))
# # # "EXIF_TAG_SUBJECT_AREA" => "36866", # undefined
# # # unsafe_copyto!(entry.data, pointer(Vector{UInt8}(tagv * "\0")), length(tagv)+1)
# # # unsafe_copyto!(entry.data, pointer(Vector{UInt8}(tagv * "\0")), length(tagv) + 1)
# # unsafe_copyto!(entry.data, Ref(buf), length(tagv) + 1)
# @info "Pointer to info:" pointer(Vector{UInt8}(tagv * "\0"))
# unsafe_copyto!(entry.data, pointer(Vector{UInt8}(tagv * "\0")), length(tagv)+1)
# @show pointer(buf)
# b = unsafe_load(entry.data)
# b = buf
# # @info "Length of tag: " length(tagv) + 1
# entry.size =7;
# entry.components = 7;
# entry.format = LibExif.EXIF_FORMAT_ASCII;
# @show unsafe_load(entry.data)
# unsafe_copyto!(b, pointer(Vector{UInt8}(tagv * "\0")), length(tagv) + 1)
mem = LibExif.exif_mem_new_default()
len = sizeof(tagv)+1 # +1 for null byte
buf = convert(Ptr{UInt8}, LibExif.exif_mem_alloc(mem, len))
unsafe_copyto!(buf, pointer(tagv), sizeof(tagv))
unsafe_store!(buf, 0x0, len)
# unsafe_copyto!(entry.data, buf, 1)
@show entry.data buf
entry.data = buf
@show entry.data buf
@info "After entry.data = buf :" Int(unsafe_load(entry.data)) Int(unsafe_load(buf))
end
end
function create_exif_data(tags)
exif = LibExif.exif_data_new()
LibExif.exif_data_set_option(exif, LibExif.EXIF_DATA_OPTION_FOLLOW_SPECIFICATION)
LibExif.exif_data_set_data_type(exif, LibExif.EXIF_DATA_TYPE_COMPRESSED)
LibExif.exif_data_set_byte_order(exif, LibExif.EXIF_BYTE_ORDER_INTEL)
LibExif.exif_data_fix(exif)
keys1 = keys(tags)
for i in keys1
key = normalize_exif_flag(i)
x = LibExif.EXIF_DATA_TYPE_UNCOMPRESSED_CHUNKY
# indentify which ifds tag goes in
ifds = [
LibExif.EXIF_IFD_0,
LibExif.EXIF_IFD_1,
LibExif.EXIF_IFD_EXIF,
LibExif.EXIF_IFD_GPS,
LibExif.EXIF_IFD_INTEROPERABILITY,
LibExif.EXIF_IFD_COUNT,
]
A = [LibExif.exif_tag_get_support_level_in_ifd(key, i, x) for i in ifds]
ifd = findfirst(==(LibExif.EXIF_SUPPORT_LEVEL_MANDATORY), A)
if ifd === nothing
ifd = findfirst(==(LibExif.EXIF_SUPPORT_LEVEL_OPTIONAL), A)
end
if key == LibExif.EXIF_TAG_YCBCR_POSITIONING
ifd = 1
end
if key in [LibExif.EXIF_TAG_PIXEL_X_DIMENSION, LibExif.EXIF_TAG_PIXEL_Y_DIMENSION]
ifd = 3
end
if ifd === nothing || issupported(i) == false
@info "Tag not supported currently or No Appropriate IFD found " key
continue
end
entry1 = init_tag(exif, ifd, key)
# entry = unsafe_load(entry1)
@info key issupported(i) findfirst(==(LibExif.EXIF_SUPPORT_LEVEL_OPTIONAL), A) findfirst(==(LibExif.EXIF_SUPPORT_LEVEL_MANDATORY), A) ifd
set_value1(entry1, tags[i])
@show entry1.parent
@info "Exif:" unsafe_load(entry1)
end
return exif
end
function write_tags(filepath::AbstractString; img::AbstractArray, tags::Dict{String,String})
# restricting filetype to .jpeg and .jpg
if (!(split(filepath,".")[2] in ["jpeg", "jpg"]))
throw(DomainError("Currently only jpeg and jpg files are supported for EXIF write operation."))
end
data = jpeg_encode(img)
exif = create_exif_data(tags)
LibExif.exif_data_dump(exif);
exif_header = Vector{Cuchar}([0xff, 0xd8, 0xff, 0xe1])
exif_data = Ref{Ptr{Cuchar}}()
exif_data_len = Cuint(length(exif_data))
ref_exif_data_len = Ref(exif_data_len)
LibExif.exif_data_save_data(exif, exif_data, ref_exif_data_len)
groups_vec = unsafe_wrap(Array, exif_data[], 5000)
len = findfirst([0xff], groups_vec)[1]
groups_vec = groups_vec[1:max(len, 1)]
open(filepath, "w") do file
write(file, exif_header) # done
write(file, UInt8((len + 2) >> 8))
write(file, UInt8((len + 2) & 0xff))
write(file, groups_vec)
write(file, data[3:end])
end
end
img = testimage("mandrill")
tags = Dict{String, String}(
# "EXIF_TAG_INTEROPERABILITY_INDEX" => "R98"
# EXIF_TAG_INTEROPERABILITY_VERSION = 2
# EXIF_TAG_NEW_SUBFILE_TYPE = 254
# "EXIF_TAG_IMAGE_WIDTH" => "100", # WORK
# "EXIF_TAG_IMAGE_LENGTH" => "100", # WORK
# "EXIF_TAG_BITS_PER_SAMPLE" => "258",
# "EXIF_TAG_COMPRESSION" => "Uncompressed", # WORK
# "EXIF_TAG_PHOTOMETRIC_INTERPRETATION" => "RGB", # WORK
# "EXIF_TAG_FILL_ORDER" => "266"
# "EXIF_TAG_DOCUMENT_NAME" => "docname", # NOT in EXIF 2.2
# "EXIF_TAG_IMAGE_DESCRIPTION" => "270", # WORK
# "EXIF_TAG_MAKE" => "Canon", # WORK
# "EXIF_TAG_MODEL" => "272" # WORK
# "EXIF_TAG_STRIP_OFFSETS" => "273" # format undefined: Not used in JPEG
# "EXIF_TAG_ORIENTATION" => "Top-left" # WORK
# "EXIF_TAG_SAMPLES_PER_PIXEL" => "8" # WORK
# "EXIF_TAG_ROWS_PER_STRIP" => "278" # format undefined
# "EXIF_TAG_STRIP_BYTE_COUNTS" => "279" # format undefined
# "EXIF_TAG_X_RESOLUTION" => "100", # WORK
# "EXIF_TAG_Y_RESOLUTION" => "100", # WORK
# "EXIF_TAG_PLANAR_CONFIGURATION" => "Planar format" # WORK
# "EXIF_TAG_RESOLUTION_UNIT" => "Inch" # WORK
# "EXIF_TAG_TRANSFER_FUNCTION" => "301" # format undefined
# "EXIF_TAG_SOFTWARE" => "305", # WORK
# "EXIF_TAG_DATE_TIME" => "306", # WORK
"EXIF_TAG_ARTIST" => "315", # WORK
# "EXIF_TAG_WHITE_POINT" => "318" # WORK
# "EXIF_TAG_PRIMARY_CHROMATICITIES" => "319" # WORK
# "EXIF_TAG_SUB_IFDS" => "330" # support issues
# "EXIF_TAG_TRANSFER_RANGE" => "342" # support issues
# "EXIF_TAG_JPEG_PROC" => "512" # support issues
# "EXIF_TAG_JPEG_INTERCHANGE_FORMAT" => "513", # support issues
# "EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH" => "514", # support issues
# "EXIF_TAG_YCBCR_COEFFICIENTS" => "529", # support issues
# "EXIF_TAG_YCBCR_SUB_SAMPLING" => "530" # support issues
# "EXIF_TAG_YCBCR_POSITIONING" => "Co-sited", # WORK
# "EXIF_TAG_REFERENCE_BLACK_WHITE" => "532", # WORK
# "EXIF_TAG_XML_PACKET" => "700" # support issues
# "EXIF_TAG_RELATED_IMAGE_FILE_FORMAT" => "4096", # support issues
# "EXIF_TAG_RELATED_IMAGE_WIDTH" => "4097", # support issues
# "EXIF_TAG_RELATED_IMAGE_LENGTH" => "4098", # support issues
# "EXIF_TAG_IMAGE_DEPTH" => "32997" # support issues
# "EXIF_TAG_CFA_REPEAT_PATTERN_DIM" => "33421", # support issues
# "EXIF_TAG_CFA_PATTERN" => "33421", # support issues
# "EXIF_TAG_BATTERY_LEVEL" => "33421", # support issues
# "EXIF_TAG_COPYRIGHT"=> "33421", # WORK
# "EXIF_TAG_EXPOSURE_TIME" => "33421", # WORK
# "EXIF_TAG_FNUMBER" => "33421", # WORK
# "EXIF_TAG_IPTC_NAA" => "33421", # support issues
# "EXIF_TAG_IMAGE_RESOURCES" => "33421", # support issues
# "EXIF_TAG_EXIF_IFD_POINTER" => "33421", # support issues
# "EXIF_TAG_INTER_COLOR_PROFILE" => "33421", # support issues
# "EXIF_TAG_EXPOSURE_PROGRAM" => "34850", # WORK
# "EXIF_TAG_SPECTRAL_SENSITIVITY" => "34850", # undefined
# "EXIF_TAG_GPS_INFO_IFD_POINTER" => "34850", # support
# "EXIF_TAG_ISO_SPEED_RATINGS" => "34850", # WORK
# "EXIF_TAG_OECF" => "34850", # undefined format
# "EXIF_TAG_TIME_ZONE_OFFSET" => "34850", # support
# "EXIF_TAG_SENSITIVITY_TYPE" => "34850", # WORK
# "EXIF_TAG_STANDARD_OUTPUT_SENSITIVITY" => "34850", # undefined
# "EXIF_TAG_RECOMMENDED_EXPOSURE_INDEX" => "34850", #undefined
# "EXIF_TAG_ISO_SPEED" => "34850", # undefined format
# "EXIF_TAG_ISO_SPEEDLatitudeYYY" => "34850", # undefined format
# "EXIF_TAG_ISO_SPEEDLatitudeZZZ" => "34850", #undefined format
# "EXIF_TAG_EXIF_VERSION" => "34850", # undefined format
# "EXIF_TAG_DATE_TIME_ORIGINAL" => "36867", # works
# "EXIF_TAG_DATE_TIME_DIGITIZED" => "36867", # undefined
# "EXIF_TAG_OFFSET_TIME" => "36867", # undefined
# "EXIF_TAG_OFFSET_TIME_ORIGINAL" => "36867", # undefined
# "EXIF_TAG_OFFSET_TIME_DIGITIZED" => "36867", # undefined
# "EXIF_TAG_COMPONENTS_CONFIGURATION" => "36867", # support issue
# "EXIF_TAG_COMPRESSED_BITS_PER_PIXEL" => "36867", # support issue
# "EXIF_TAG_SHUTTER_SPEED_VALUE" => "36867", # work
# "EXIF_TAG_APERTURE_VALUE" => "36867", # work
# "EXIF_TAG_BRIGHTNESS_VALUE" => "36867", # work
# "EXIF_TAG_EXPOSURE_BIAS_VALUE" => "36867", # work
# "EXIF_TAG_MAX_APERTURE_VALUE" => "36867", # work
# "EXIF_TAG_SUBJECT_DISTANCE" => "36867", # work
"EXIF_TAG_FOCAL_LENGTH" => "36867", # work
"EXIF_TAG_SUBJECT_AREA" => "36866", # undefined
# "EXIF_TAG_TIFF_EP_STANDARD_ID" => "36867", # support issues
# "EXIF_TAG_MAKER_NOTE" => "36867", #undefined
# "EXIF_TAG_USER_COMMENT" => "36867", # undefined
# "EXIF_TAG_SUB_SEC_TIME" => "36867", # read only error
# "EXIF_TAG_SUB_SEC_TIME_ORIGINAL" => "36867", # read only error
# "EXIF_TAG_SUB_SEC_TIME_DIGITIZED" => "36867", # read only
# "EXIF_TAG_XP_TITLE" => "36867", # undefined
# "EXIF_TAG_XP_COMMENT" => "36867", # undefined
# "EXIF_TAG_XP_AUTHOR" => "36867", # undefined
# "EXIF_TAG_XP_KEYWORDS" => "36867", # undefined
# "EXIF_TAG_XP_SUBJECT" => "36867", #undefined
# "EXIF_TAG_FLASH_PIX_VERSION" => "36867", # undefined
# "EXIF_TAG_COLOR_SPACE" => "36867", # work
# "EXIF_TAG_PIXEL_X_DIMENSION" => "36867", # work
# "EXIF_TAG_PIXEL_Y_DIMENSION" => "36867", # work
# "EXIF_TAG_RELATED_SOUND_FILE" => "36867", # undefined
# "EXIF_TAG_INTEROPERABILITY_IFD_POINTER" => "36867", # support issues
# "EXIF_TAG_FLASH_ENERGY" => "36867", # work
# "EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE" => "36867", # undefined
# "EXIF_TAG_FOCAL_PLANE_X_RESOLUTION" => "36867", # WORK
# "EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION" => "36867", # WORK
# "EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT" => "36867", # WORK
# "EXIF_TAG_SUBJECT_LOCATION" => "36867", # work
# "EXIF_TAG_EXPOSURE_INDEX" => "36867", # work
# "EXIF_TAG_SENSING_METHOD" => "36867", # WORK
# "EXIF_TAG_FILE_SOURCE" => "36867", # undefined
# "EXIF_TAG_SCENE_TYPE" => "41729", # undefined
# "EXIF_TAG_NEW_CFA_PATTERN" => "41729", # undefined
# "EXIF_TAG_CUSTOM_RENDERED" => "41729", # work
# "EXIF_TAG_EXPOSURE_MODE" => "41729", # work
# "EXIF_TAG_WHITE_BALANCE" => "41729", # work
# "EXIF_TAG_DIGITAL_ZOOM_RATIO" => "41729", # work
# "EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM" => "41729", # work
# "EXIF_TAG_SCENE_CAPTURE_TYPE" => "41729", # work
# "EXIF_TAG_GAIN_CONTROL" => "41729", # work
# "EXIF_TAG_CONTRAST" => "41729", # work
# "EXIF_TAG_SATURATION" => "41729", # work
# "EXIF_TAG_SHARPNESS" => "41729", # work
# "EXIF_TAG_DEVICE_SETTING_DESCRIPTION" => "41729", # undefined
# "EXIF_TAG_SUBJECT_DISTANCE_RANGE" => "41729", # work
# "EXIF_TAG_IMAGE_UNIQUE_ID" => "41729", # undefined
# "EXIF_TAG_CAMERA_OWNER_NAME" => "41729", # undefined
# "EXIF_TAG_BODY_SERIAL_NUMBER" => "41729", # undefined
# "EXIF_TAG_LENS_SPECIFICATION" => "41729", # undefined
# "EXIF_TAG_LENS_MAKE" => "41729", # undefined
# "EXIF_TAG_LENS_MODEL" => "41729", # undefined
# "EXIF_TAG_LENS_SERIAL_NUMBER" => "41729", # undefined
# "EXIF_TAG_COMPOSITE_IMAGE" => "41729", # undefined
# "EXIF_TAG_SOURCE_IMAGE_NUMBER_OF_COMPOSITE_IMAGE"=> "41729", # undefined
# "EXIF_TAG_SOURCE_EXPOSURE_TIMES_OF_COMPOSITE_IMAGE" => "41729", # undefined
# "EXIF_TAG_GAMMA" => "41729", #undefined
# "EXIF_TAG_PRINT_IMAGE_MATCHING" => "41729", # support issues
# "EXIF_TAG_PADDING" => "41729", # undefined
)
write_tags("test.jpg"; img, tags=tags)
@test read_tags("test.jpg") == tags
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment