Skip to content

Commit

Permalink
Support for AVIF & JXL
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanOltmann committed Jan 20, 2024
1 parent cae43d7 commit 917db69
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 15 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ kotlin {
val wasmJsMain by getting

commonMain.dependencies {
api("com.ashampoo:kim:0.9.3")
api("com.ashampoo:kim:0.10")
}

commonTest.dependencies {
Expand Down
54 changes: 43 additions & 11 deletions app/src/commonMain/kotlin/HtmlGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ import com.ashampoo.kim.common.toUInt8
import com.ashampoo.kim.format.ImageMetadata
import com.ashampoo.kim.format.bmff.BoxReader
import com.ashampoo.kim.format.bmff.BoxType
import com.ashampoo.kim.format.bmff.boxes.MetaBox
import com.ashampoo.kim.format.bmff.box.ExifBox
import com.ashampoo.kim.format.bmff.box.MetaBox
import com.ashampoo.kim.format.jpeg.JpegConstants
import com.ashampoo.kim.format.jpeg.JpegSegmentAnalyzer
import com.ashampoo.kim.format.png.PngChunkType
import com.ashampoo.kim.format.png.PngConstants
import com.ashampoo.kim.format.png.PngImageParser
import com.ashampoo.kim.format.tiff.TiffDirectory
import com.ashampoo.kim.format.tiff.TiffReader
import com.ashampoo.kim.format.tiff.constants.TiffConstants
import com.ashampoo.kim.format.tiff.constant.TiffConstants
import com.ashampoo.kim.input.ByteArrayByteReader
import com.ashampoo.kim.model.ImageFormat

Expand Down Expand Up @@ -168,10 +169,19 @@ fun generateHexHtml(bytes: ByteArray): String {
val format = ImageFormat.detect(bytes) ?: return "Image format was not recognized."

return when (format) {
ImageFormat.JPEG -> generateHtmlFromSlices(bytes, createJpegSlices(bytes))
ImageFormat.TIFF -> generateHtmlFromSlices(bytes, createTiffSlices(bytes, exifBytes = false))
ImageFormat.PNG -> generateHtmlFromSlices(bytes, createPngSlices(bytes))
ImageFormat.HEIC -> generateHtmlFromSlices(bytes, createBaseMediaFileFormatSlices(bytes))

ImageFormat.JPEG ->
generateHtmlFromSlices(bytes, createJpegSlices(bytes))

ImageFormat.TIFF ->
generateHtmlFromSlices(bytes, createTiffSlices(bytes, exifBytes = false))

ImageFormat.PNG ->
generateHtmlFromSlices(bytes, createPngSlices(bytes))

ImageFormat.HEIC, ImageFormat.AVIF, ImageFormat.JXL ->
generateHtmlFromSlices(bytes, createBaseMediaFileFormatSlices(bytes))

else -> "HEX view for $format is not (yet) supported."
}
}
Expand Down Expand Up @@ -526,7 +536,7 @@ private fun createBaseMediaFileFormatSlices(bytes: ByteArray): List<LabeledSlice

val boxes = BoxReader.readBoxes(
byteReader = ByteArrayByteReader(bytes),
stopAfterMetaBox = false,
stopAfterMetadataRead = false,
offsetShift = 0
)

Expand Down Expand Up @@ -629,9 +639,34 @@ private fun createBaseMediaFileFormatSlices(bytes: ByteArray): List<LabeledSlice
}
}

} else if (box.type == BoxType.EXIF) {

box as ExifBox

slices.add(
LabeledSlice(
range = box.offset.toInt() until box.offset.toInt() + 8,
label = "Box" + SPACE + "Exif" + SPACE + "header",
separatorLineType = if (box.offset > 0)
SeparatorLineType.BOLD
else
SeparatorLineType.NONE,
snipAfterLineCount = 3
)
)

slices.addAll(
createTiffSlices(
bytes = box.exifBytes,
startPosition = box.offset.toInt() + 8,
endPosition = box.offset.toInt() + box.length.toInt(),
exifBytes = true
)
)

} else {

val boxRange = box.offset.toInt() until box.offset.toInt() + box.length.toInt()
val boxRange = box.offset.toInt() until box.offset.toInt() + box.length.toInt()

slices.add(
LabeledSlice(
Expand All @@ -650,9 +685,6 @@ private fun createBaseMediaFileFormatSlices(bytes: ByteArray): List<LabeledSlice
/* For safety sort in offset order. */
slices.sortBy { it.range.first }

for (slice in slices)
println(slice)

return slices
}

Expand Down
20 changes: 20 additions & 0 deletions app/src/jvmTest/kotlin/HtmlGeneratorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,24 @@ class HtmlGeneratorTest {
fail("HTML photo_5_hex.html differs.")
}
}

@Test
fun testGenerateHexHtmlJxl() {

val imageBytes = Path("src/jvmTest/resources/photo_6.jxl").readBytes()

val actualHtml = generateHexHtml(imageBytes)

val expectedHtml = Path("src/jvmTest/resources/photo_6_hex.html")
.readBytes()
.decodeToString()

if (expectedHtml != actualHtml) {

Path("build/photo_6_hex.html")
.writeText(actualHtml)

fail("HTML photo_6_hex.html differs.")
}
}
}
Binary file added app/src/jvmTest/resources/photo_6.jxl
Binary file not shown.
36 changes: 36 additions & 0 deletions app/src/jvmTest/resources/photo_6_hex.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<div class="hex-box" style="font-family: monospace;">
00000000&nbsp;|&nbsp;00&nbsp;00&nbsp;00&nbsp;0C&nbsp;4A&nbsp;58&nbsp;4C&nbsp;20&nbsp;&nbsp;0D&nbsp;0A&nbsp;87&nbsp;0A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;....JXL&nbsp;....&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;Box&nbsp;JXL &nbsp;[12&nbsp;bytes]<br>
<hr style="height:2px;margin:1px;padding:0;border-width:0;color:#dddddd;background-color:#dddddd">
00000012&nbsp;|&nbsp;00&nbsp;00&nbsp;00&nbsp;14&nbsp;66&nbsp;74&nbsp;79&nbsp;70&nbsp;&nbsp;6A&nbsp;78&nbsp;6C&nbsp;20&nbsp;00&nbsp;00&nbsp;00&nbsp;00&nbsp;|&nbsp;....ftypjxl&nbsp;....&nbsp;|&nbsp;Box&nbsp;ftyp&nbsp;[20&nbsp;bytes]<br>
00000028&nbsp;|&nbsp;6A&nbsp;78&nbsp;6C&nbsp;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;jxl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<br>
<hr style="height:2px;margin:1px;padding:0;border-width:0;color:#dddddd;background-color:#dddddd">
00000032&nbsp;|&nbsp;00&nbsp;00&nbsp;02&nbsp;4C&nbsp;6A&nbsp;78&nbsp;6C&nbsp;70&nbsp;&nbsp;00&nbsp;00&nbsp;00&nbsp;00&nbsp;FF&nbsp;0A&nbsp;BA&nbsp;34&nbsp;|&nbsp;...Ljxlp.......4&nbsp;|&nbsp;Box&nbsp;jxlp&nbsp;[588&nbsp;bytes]<br>
00000048&nbsp;|&nbsp;05&nbsp;21&nbsp;9C&nbsp;6D&nbsp;0D&nbsp;28&nbsp;25&nbsp;00&nbsp;&nbsp;21&nbsp;08&nbsp;A0&nbsp;20&nbsp;A2&nbsp;02&nbsp;21&nbsp;0A&nbsp;|&nbsp;.!.m.(%.!..&nbsp;..!.&nbsp;|&nbsp;<br>
00000064&nbsp;|&nbsp;84&nbsp;09&nbsp;98&nbsp;06&nbsp;26&nbsp;81&nbsp;A9&nbsp;00&nbsp;&nbsp;34&nbsp;74&nbsp;A4&nbsp;43&nbsp;72&nbsp;96&nbsp;F8&nbsp;79&nbsp;|&nbsp;....&amp;...4t.Cr..y&nbsp;|&nbsp;<br>
00000079&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ ... snip 524 bytes ... ]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
00000604&nbsp;|&nbsp;4C&nbsp;1F&nbsp;19&nbsp;CB&nbsp;4A&nbsp;69&nbsp;01&nbsp;E0&nbsp;&nbsp;0B&nbsp;BD&nbsp;1A&nbsp;0A&nbsp;3B&nbsp;9A&nbsp;FB&nbsp;01&nbsp;|&nbsp;L...Ji......;...&nbsp;|&nbsp;<br>
<hr style="height:2px;margin:1px;padding:0;border-width:0;color:#dddddd;background-color:#dddddd">
00000620&nbsp;|&nbsp;00&nbsp;00&nbsp;2D&nbsp;5D&nbsp;6A&nbsp;62&nbsp;72&nbsp;64&nbsp;&nbsp;C2&nbsp;56&nbsp;0C&nbsp;DD&nbsp;6D&nbsp;03&nbsp;08&nbsp;82&nbsp;|&nbsp;..-]jbrd.V..m...&nbsp;|&nbsp;Box&nbsp;jbrd&nbsp;[11613&nbsp;bytes]<br>
00000636&nbsp;|&nbsp;20&nbsp;B4&nbsp;4C&nbsp;98&nbsp;2F&nbsp;18&nbsp;B5&nbsp;84&nbsp;&nbsp;C5&nbsp;60&nbsp;D7&nbsp;19&nbsp;1C&nbsp;00&nbsp;42&nbsp;5D&nbsp;|&nbsp;&nbsp;.L./....`....B]&nbsp;|&nbsp;<br>
00000652&nbsp;|&nbsp;80&nbsp;00&nbsp;01&nbsp;0A&nbsp;84&nbsp;5C&nbsp;25&nbsp;00&nbsp;&nbsp;00&nbsp;20&nbsp;40&nbsp;8E&nbsp;CA&nbsp;16&nbsp;8C&nbsp;FF&nbsp;|&nbsp;.....\%..&nbsp;@.....&nbsp;|&nbsp;<br>
00000667&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ ... snip 11549 bytes ... ]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
00012217&nbsp;|&nbsp;31&nbsp;D9&nbsp;A2&nbsp;A2&nbsp;51&nbsp;5F&nbsp;03&nbsp;30&nbsp;&nbsp;65&nbsp;6C&nbsp;DD&nbsp;AD&nbsp;ED&nbsp;7E&nbsp;BF&nbsp;05&nbsp;|&nbsp;1...Q_.0el...~..&nbsp;|&nbsp;<br>
<hr style="height:2px;margin:1px;padding:0;border-width:0;color:#dddddd;background-color:#dddddd">
00012233&nbsp;|&nbsp;00&nbsp;00&nbsp;2F&nbsp;9C&nbsp;45&nbsp;78&nbsp;69&nbsp;66&nbsp;&nbsp;00&nbsp;00&nbsp;00&nbsp;00&nbsp;49&nbsp;49&nbsp;2A&nbsp;00&nbsp;|&nbsp;../.Exif....II*.&nbsp;|&nbsp;Box&nbsp;Exif&nbsp;[12188&nbsp;bytes]<br>
00012249&nbsp;|&nbsp;08&nbsp;00&nbsp;00&nbsp;00&nbsp;08&nbsp;00&nbsp;0F&nbsp;01&nbsp;&nbsp;02&nbsp;00&nbsp;05&nbsp;00&nbsp;00&nbsp;00&nbsp;6E&nbsp;00&nbsp;|&nbsp;..............n.&nbsp;|&nbsp;<br>
00012265&nbsp;|&nbsp;00&nbsp;00&nbsp;10&nbsp;01&nbsp;02&nbsp;00&nbsp;0A&nbsp;00&nbsp;&nbsp;00&nbsp;00&nbsp;74&nbsp;00&nbsp;00&nbsp;00&nbsp;1A&nbsp;01&nbsp;|&nbsp;..........t.....&nbsp;|&nbsp;<br>
00012280&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ ... snip 12124 bytes ... ]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
00024405&nbsp;|&nbsp;E9&nbsp;F1&nbsp;01&nbsp;00&nbsp;15&nbsp;15&nbsp;07&nbsp;7C&nbsp;&nbsp;81&nbsp;0C&nbsp;E2&nbsp;5F&nbsp;FF&nbsp;D1&nbsp;FF&nbsp;D9&nbsp;|&nbsp;.......|..._....&nbsp;|&nbsp;<br>
<hr style="height:2px;margin:1px;padding:0;border-width:0;color:#dddddd;background-color:#dddddd">
00024421&nbsp;|&nbsp;00&nbsp;00&nbsp;33&nbsp;97&nbsp;78&nbsp;6D&nbsp;6C&nbsp;20&nbsp;&nbsp;3C&nbsp;3F&nbsp;78&nbsp;70&nbsp;61&nbsp;63&nbsp;6B&nbsp;65&nbsp;|&nbsp;..3.xml&nbsp;&lt;?xpacke&nbsp;|&nbsp;Box&nbsp;xml &nbsp;[13207&nbsp;bytes]<br>
00024437&nbsp;|&nbsp;74&nbsp;20&nbsp;62&nbsp;65&nbsp;67&nbsp;69&nbsp;6E&nbsp;3D&nbsp;&nbsp;27&nbsp;EF&nbsp;BB&nbsp;BF&nbsp;27&nbsp;20&nbsp;69&nbsp;64&nbsp;|&nbsp;t&nbsp;begin='...'&nbsp;id&nbsp;|&nbsp;<br>
00024453&nbsp;|&nbsp;3D&nbsp;27&nbsp;57&nbsp;35&nbsp;4D&nbsp;30&nbsp;4D&nbsp;70&nbsp;&nbsp;43&nbsp;65&nbsp;68&nbsp;69&nbsp;48&nbsp;7A&nbsp;72&nbsp;65&nbsp;|&nbsp;='W5M0MpCehiHzre&nbsp;|&nbsp;<br>
00024468&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ ... snip 13143 bytes ... ]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
00037612&nbsp;|&nbsp;70&nbsp;61&nbsp;63&nbsp;6B&nbsp;65&nbsp;74&nbsp;20&nbsp;65&nbsp;&nbsp;6E&nbsp;64&nbsp;3D&nbsp;27&nbsp;77&nbsp;27&nbsp;3F&nbsp;3E&nbsp;|&nbsp;packet&nbsp;end='w'?&gt;&nbsp;|&nbsp;<br>
<hr style="height:2px;margin:1px;padding:0;border-width:0;color:#dddddd;background-color:#dddddd">
00037628&nbsp;|&nbsp;00&nbsp;0D&nbsp;42&nbsp;AD&nbsp;6A&nbsp;78&nbsp;6C&nbsp;70&nbsp;&nbsp;80&nbsp;00&nbsp;00&nbsp;01&nbsp;E0&nbsp;5B&nbsp;00&nbsp;10&nbsp;|&nbsp;..B.jxlp.....[..&nbsp;|&nbsp;Box&nbsp;jxlp&nbsp;[869037&nbsp;bytes]<br>
00037644&nbsp;|&nbsp;00&nbsp;98&nbsp;2B&nbsp;8E&nbsp;50&nbsp;A0&nbsp;A2&nbsp;1B&nbsp;&nbsp;10&nbsp;A9&nbsp;94&nbsp;60&nbsp;10&nbsp;6C&nbsp;90&nbsp;B0&nbsp;|&nbsp;..+.P......`.l..&nbsp;|&nbsp;<br>
00037660&nbsp;|&nbsp;50&nbsp;E4&nbsp;D0&nbsp;37&nbsp;11&nbsp;5F&nbsp;52&nbsp;D3&nbsp;&nbsp;54&nbsp;85&nbsp;1A&nbsp;EF&nbsp;58&nbsp;6D&nbsp;16&nbsp;90&nbsp;|&nbsp;P..7._R.T...Xm..&nbsp;|&nbsp;<br>
00037675&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ ... snip 868973 bytes ... ]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>
00906649&nbsp;|&nbsp;92&nbsp;A1&nbsp;73&nbsp;25&nbsp;99&nbsp;A2&nbsp;E2&nbsp;1D&nbsp;&nbsp;A9&nbsp;D6&nbsp;F9&nbsp;E9&nbsp;CA&nbsp;27&nbsp;35&nbsp;01&nbsp;|&nbsp;..s%.........'5.&nbsp;|&nbsp;<br>
</div>
2 changes: 1 addition & 1 deletion app/src/wasmJsMain/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import com.ashampoo.kim.Kim
import com.ashampoo.kim.format.tiff.constants.TiffTag
import com.ashampoo.kim.format.tiff.constant.TiffTag
import com.ashampoo.kim.model.TiffOrientation
import kotlinx.browser.document
import org.khronos.webgl.ArrayBuffer
Expand Down
9 changes: 7 additions & 2 deletions app/src/wasmJsMain/resources/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,18 @@ <h1>EXIF Viewer</h1>
</center>

<div id="dropbox">

<input id="fileInput" type="file">

<p>Drag & drop your file here<br>or click to select a file!</p>
</div>

<div style="font-size: medium; text-align: center;">
<p>JPG, PNG, TIFF & HEIC files are supported.<br>
Processing happens solely in your browser, no servers involved.</p>
<p>Processing happens solely in your browser.</p>
</div>

<div style="font-size: small; text-align: center;">
Supported formats: JPG, PNG, TIFF, HEIC, AVIF & JXL.
</div>

<div id="thumbnail-box" class="box">
Expand Down

0 comments on commit 917db69

Please sign in to comment.