Slide 29
Slide 29 text
photoStats
#!/usr/bin/env kscript
@file:DependsOn("com.drewnoakes:metadata-extractor:2.12.0")
import PhotoStats.LensRange
import com.drew.imaging.ImageMetadataReader
import com.drew.metadata.Metadata
import java.io.File
typealias LensRange = Pair
data class Lens(
val name: String,
val range: LensRange
)
val lenses = listOf(LensRange(17, 40), LensRange(24, 105), LensRange(24, 70), LensRange(70, 200))
fun appendFiles(dir: File, filesList: MutableList) {
filesList.addAll(
dir.listFiles()
.filter { !it.isDirectory && it.isSupported() }
)
dir.listFiles()
.filter { it.isDirectory && it.listFiles().isNotEmpty()}
.forEach { appendFiles(it, filesList) }
}
fun File.focalLength(): Int? {
val metadata: Metadata = ImageMetadataReader.readMetadata(this)
return metadata.directories
.filter { it.name.contains("exif", true) }
.firstOrNull { it.tags.find { tag -> tag.tagName == "Focal Length 35" || tag.tagName == "Focal Length" } != null }
?.let { directory ->
(directory.tags.firstOrNull { it.tagName == "Focal Length 35" }
?: directory.tags.first { it.tagName == "Focal Length" })
.let { it.description.substringBefore(" ").toInt() }
}
}
val supportedExtensions = listOf("jpg", "jpeg", "cr2", "dng")
fun File.isSupported(): Boolean = supportedExtensions.find { it.equals(this.extension, true) } != null
val allFiles = ArrayList()
val paths = if (args.isNotEmpty()) args.toList() else listOf("./")
paths.forEach {
val currentDir = File(it)
if (currentDir.exists() && currentDir.isDirectory) {
println("Scanning ${currentDir.absolutePath}")
appendFiles(currentDir, allFiles)
}
}
val focals = allFiles.map { it.focalLength() }
.filterNotNull()
.sorted()
val total = focals.size
println("Total pictures: $total")
lenses.forEach { lensRange ->
val matching = focals.filter { it >= lensRange.first && it <= lensRange.second }.size
println("Covered by ${lensRange.first}-${lensRange.second}: $matching (${(matching.toFloat() / total.toFloat() * 100).toInt()}%)")
}