commit 7cfcb30c2f3ffc4e71df1445c99f2a9444d2cb86
parent eb52a606f9aa6d5317e2b9adc37dc92d79ca11c6
Author: Leah (ctucx) <leah@ctu.cx>
Date: Sat, 13 Mar 2021 16:01:44 +0100
parent eb52a606f9aa6d5317e2b9adc37dc92d79ca11c6
Author: Leah (ctucx) <leah@ctu.cx>
Date: Sat, 13 Mar 2021 16:01:44 +0100
rename to nimjpg
7 files changed, 141 insertions(+), 139 deletions(-)
diff --git a/.gitignore b/.gitignore @@ -4,4 +4,6 @@ test_c.o test_c get_metadata.o get_metadata -exif.o- \ No newline at end of file +exif.o +example +example_sync+ \ No newline at end of file
diff --git a/example.nim b/example.nim @@ -1,5 +1,5 @@ import os -import jpgnim +import nimjpg import asyncdispatch import asyncfile import json
diff --git a/example_sync.nim b/example_sync.nim @@ -1,5 +1,5 @@ import os -import jpgnim +import nimjpg import asyncdispatch import asyncfile import json
diff --git a/jpgnim.nim b/jpgnim.nim @@ -1,122 +0,0 @@ -import os -import streams -import strutils -import asyncfile -import asyncdispatch -import exifnim/libexif -import exifnim/helpers -import tables -import parseutils -import options - -import utils - -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 SofData* = object - components*: uint8 - precision*: uint8 - height*: uint16 - width*: uint16 - -type JpgInfo* = object - exifData*: Option[Table[string, string]] - sofData*: Option[SofData] - -proc getSectionSize(file: Stream | AsyncFile): Future[uint16] {.multisync.} = - # FIXME consider endianness - var size: uint16 - let val = toHex(file.read(2).await) - discard parseHex(val, size) - echo val - return size - uint16(2) - -proc skipSection(file: Stream | AsyncFile): Future[int] {.multisync.} = - let size = int64(file.getSectionSize().await) - debug("skipping ", size) - file.setFilePos(file.getFilePos() + size) - -proc expect(file: Stream | AsyncFile, expected: string): Future[int] {.multisync.} = - let byte = file.read(1).await - if byte != expected: - error("expected ", toHex(expected),", got ", toHex(byte)) - -proc process_sof*(file: Stream | AsyncFile): Future[SofData] {.multisync.} = - discard parseHex(toHex(file.read(1).await), result.precision) - discard parseHex(toHex(file.read(2).await), result.height) - discard parseHex(toHex(file.read(2).await), result.width) - discard parseHex(toHex(file.read(1).await), result.components) - -proc collect_jpg*(file: Stream | AsyncFile): Future[JpgInfo] {.multisync,gcsafe.} = - var done = false - var byte: string - - discard file.expect(MARKER_START).await - discard file.expect(SOI).await - - while not done: - discard file.expect(MARKER_START).await - - let marker = file.read(1).await - - case marker: - of "": - error("unexpected end of file") - of SOS: - # Beginning of compressed data - done = true - of EOI: - # No compressed data? Okay... - done = true - of EXIF: - debug "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)) - let ed_table = ed.collect_exif_data() - if result.exifData.isNone: - result.exifData = some(ed_table) - debug ed_table - of JFIF: - debug "found JFIF" - discard file.skipSection().await - else: - if toHex(marker).startsWith("C"): - debug "found SOF" - let section_start = file.getFilePos() + 2 - let section_end = section_start + int64(file.getSectionSize().await) - let sd = file.process_sof().await - if result.sofData.isNone: - result.sofData = some(sd) - debug sd - file.setFilePos(section_end) - continue - - debug("unknown section: ", toHex(marker)) - discard file.skipSection().await - -proc collect_jpg*(file: File): JpgInfo = - let stream = newFileStream(file) - result = collect_jpg(stream) - stream.close()
diff --git a/jpgnim.nimble b/jpgnim.nimble @@ -1,13 +0,0 @@ -# Package - -version = "0.1.0" -author = "ctucx, Milan" -description = "Read jpg headers" -license = "GPL-3.0" -srcDir = "./" -bin = @["example", "example_sync"] -installFiles = @["jpgnim.nim", "utils.nim"] - -# Dependencies -requires "nim >= 1.4" -requires "https://cgit.ctu.cx/exifnim/#main"
diff --git a/nimjpg.nim b/nimjpg.nim @@ -0,0 +1,122 @@ +import os +import streams +import strutils +import asyncfile +import asyncdispatch +import nimexif/libexif +import nimexif/helpers +import tables +import parseutils +import options + +import utils + +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 SofData* = object + components*: uint8 + precision*: uint8 + height*: uint16 + width*: uint16 + +type JpgInfo* = object + exifData*: Option[Table[string, string]] + sofData*: Option[SofData] + +proc getSectionSize(file: Stream | AsyncFile): Future[uint16] {.multisync.} = + # FIXME consider endianness + var size: uint16 + let val = toHex(file.read(2).await) + discard parseHex(val, size) + echo val + return size - uint16(2) + +proc skipSection(file: Stream | AsyncFile): Future[int] {.multisync.} = + let size = int64(file.getSectionSize().await) + debug("skipping ", size) + file.setFilePos(file.getFilePos() + size) + +proc expect(file: Stream | AsyncFile, expected: string): Future[int] {.multisync.} = + let byte = file.read(1).await + if byte != expected: + error("expected ", toHex(expected),", got ", toHex(byte)) + +proc process_sof*(file: Stream | AsyncFile): Future[SofData] {.multisync.} = + discard parseHex(toHex(file.read(1).await), result.precision) + discard parseHex(toHex(file.read(2).await), result.height) + discard parseHex(toHex(file.read(2).await), result.width) + discard parseHex(toHex(file.read(1).await), result.components) + +proc collect_jpg*(file: Stream | AsyncFile): Future[JpgInfo] {.multisync,gcsafe.} = + var done = false + var byte: string + + discard file.expect(MARKER_START).await + discard file.expect(SOI).await + + while not done: + discard file.expect(MARKER_START).await + + let marker = file.read(1).await + + case marker: + of "": + error("unexpected end of file") + of SOS: + # Beginning of compressed data + done = true + of EOI: + # No compressed data? Okay... + done = true + of EXIF: + debug "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)) + let ed_table = ed.collect_exif_data() + if result.exifData.isNone: + result.exifData = some(ed_table) + debug ed_table + of JFIF: + debug "found JFIF" + discard file.skipSection().await + else: + if toHex(marker).startsWith("C"): + debug "found SOF" + let section_start = file.getFilePos() + 2 + let section_end = section_start + int64(file.getSectionSize().await) + let sd = file.process_sof().await + if result.sofData.isNone: + result.sofData = some(sd) + debug sd + file.setFilePos(section_end) + continue + + debug("unknown section: ", toHex(marker)) + discard file.skipSection().await + +proc collect_jpg*(file: File): JpgInfo = + let stream = newFileStream(file) + result = collect_jpg(stream) + stream.close()
diff --git a/nimjpg.nimble b/nimjpg.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "ctucx, Milan" +description = "Read jpg headers" +license = "GPL-3.0" +srcDir = "./" +bin = @["example", "example_sync"] +installFiles = @["nimjpg.nim", "utils.nim"] + +# Dependencies +requires "nim >= 1.4" +requires "https://cgit.ctu.cx/nimexif"