commit 5637b7d5aaccda626b7b274bfb72a69324bb4720
parent 0d87f77c176d9b73346c865972704a1addfe74ed
Author: Milan Pässler <milan@petabyte.dev>
Date: Sat, 13 Mar 2021 11:35:46 +0100
parent 0d87f77c176d9b73346c865972704a1addfe74ed
Author: Milan Pässler <milan@petabyte.dev>
Date: Sat, 13 Mar 2021 11:35:46 +0100
jpg: pass exif data to libexif
2 files changed, 97 insertions(+), 9 deletions(-)
diff --git a/exif.nim b/exif.nim @@ -2,7 +2,6 @@ import asyncdispatch import libexif import tables -var ed {.threadvar.}: ptr ExifData var buf {.threadvar.}: cstring # MUST be called once per thread @@ -12,14 +11,8 @@ proc init_exif*() = proc deinit_exif*() = dealloc(buf) -proc collect_exif*(path: string): Future[Table[string, string]] {.gcsafe,async.} = - result = initTable[string, string]() - - ed = exif_data_new_from_file(path) - - if ed == nil: - # ERROR - quit(0) +proc collect_exif*(ed: ptr ExifData): Table[string, string] {.gcsafe.} = + #result = initTable[string, string]() proc process_entries(entry: ptr ExifEntry , callback_data: pointer) {.cdecl.} = let name = exif_tag_get_name(entry.tag)
diff --git a/jpg.nim b/jpg.nim @@ -0,0 +1,95 @@ +import os +import strutils +import asyncfile +import asyncdispatch +import libexif +import exif +import tables +import parseutils + +var buf {.threadvar.}: pointer + +# MUST be called once per thread +proc init_jpg*() = + init_exif() + buf = alloc(65536) + +proc deinit_jpg*() = + deinit_exif() + dealloc(buf) + +const + MARKER_START = parseHexStr("FF") + + # 0xCn SOFn + + SOS = parseHexStr("DA") # Start Of Scan (begins compressed data) + SOI = parseHexStr("D8") # Start Of Image (beginning of datastream) + EOI = parseHexStr("D9") # End Of Image (end of datastream) + + EXIF = parseHexStr("E1") + JFIF = parseHexStr("E0") + +type JpgInfo* = object + exifInfo*: Table[string, string] + resolution*: tuple[x: int, y: int] + +proc getSectionSize(file: AsyncFile): Future[uint16] {.async.} = + # FIXME consider endianness + var size: uint16 + let val = toHex(file.read(2).await) + discard parseHex(val, size) + return size - uint16(2) + +proc skipSection(file: AsyncFile): Future[void] {.async.} = + let size = int64(file.getSectionSize().await) + echo("skipping ", size) + file.setFilePos(file.getFilePos() + size) + +proc expect(file: AsyncFile, expected: string): Future[void] {.async.} = + let byte = file.read(1).await + if byte != expected: + echo("expected ", toHex(expected),", got ", toHex(byte)) + quit(1) + +proc collect_jpg*(file: AsyncFile): Future[JpgInfo] {.gcsafe,async.} = + var done = false + var byte: string + + file.expect(MARKER_START).await + file.expect(SOI).await + + while not done: + file.expect(MARKER_START).await + + let marker = file.read(1).await + + case marker: + of "": + echo("unexpected end of file") + quit(1) + of SOS: + # Beginning of compressed data + done = true + of EOI: + # No compressed data? Okay... + done = true + of EXIF: + echo "found EXIF" + let size = int(file.getSectionSize().await) + discard file.readBuffer(buf, size).await + let ed = exif_data_new_from_data(cast[ptr[cuchar]](buf), cuint(size)) + echo ed.collect_exif() + of JFIF: + echo "found JFIF" + file.skipSection().await + else: + if toHex(marker).startsWith("C"): + echo "found SOF" + file.skipSection().await + continue + + echo("unknown section: ", toHex(marker)) + file.skipSection().await + + return JpgInfo(exifInfo: initTable[string, string](), resolution: (0, 0))