Skip to content

Commit

Permalink
add an empty photo row and edit by drag & drop to support both single…
Browse files Browse the repository at this point in the history
… photo and live photo paired with mov
  • Loading branch information
banjun committed Sep 16, 2020
1 parent b1dd858 commit dde3ff1
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 17 deletions.
61 changes: 45 additions & 16 deletions WatchFaceDumper/ImageItemRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ import AppKit
import Ikemen

final class ImageItemRowView: NSTableRowView {
private let titleLabel = NSTextField(labelWithString: "")
private let imageView = NSImageView() {
$0.imageFrameStyle = .photo
$0.isEditable = true
}
private var imageViewAspectConstraint: NSLayoutConstraint? {
didSet {
oldValue?.isActive = false
imageViewAspectConstraint?.isActive = true
}
}
private let movieView = EditableAVPlayerView()
var imageDidChange: ((NSImage?) -> Void)?
var movieDidChange: ((Data?) -> Void)?
Expand All @@ -15,38 +22,60 @@ final class ImageItemRowView: NSTableRowView {
var movie: Data?
}

var item: ImageItem {
didSet {
reloadItem()
}
}

init(item: ImageItem) {
self.item = item
super.init(frame: .zero)

let autolayout = northLayoutFormat([:], [
"size": NSTextField(labelWithString: item.image.map {"\(Int($0.size.width))×\(Int($0.size.height))"} ?? "no image"),
"title": titleLabel,
"image": imageView {
$0.target = self
$0.action = #selector(imageViewDidChangeValue(_:))
$0.image = item.image
if let image = item.image {
$0.widthAnchor.constraint(equalTo: $0.heightAnchor, multiplier: image.size.width / image.size.height).isActive = true
}
},
"movie": item.movie.map { data in
movieView {
$0.controlsStyle = .minimal
$0.data = data
$0.dataDidChange = { [weak self] data in
self?.movieDidChange?(data)
}
"movie": movieView { movieView in
movieView.dataDidChange = { [weak self] data in
self?.item.movie = data
self?.movieDidChange?(data)
}
} ?? NSView(),
},
])
autolayout("H:|-[size]|") // typically "384x480" (38mm)
autolayout("H:|-[title]-|") // typically "384x480" (38mm)
autolayout("H:|-[image]-[movie(image)]|")
autolayout("V:|-[size]-[image(240)]-|")
autolayout("V:|-[size]-[movie(image)]-|")
autolayout("V:|-[title]-[image(240)]-|")
autolayout("V:|-[title]-[movie(image)]-|")

reloadItem()
}

required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}

private func reloadItem() {
titleLabel.stringValue = [
item.image.map {"\(Int($0.size.width))×\(Int($0.size.height))"} ?? "no image",
item.movie != nil ? "Live Photo" : "Single (not a Live Photo)"
].joined(separator: ", ")

if imageView.image != item.image {
imageView.image = item.image
}
imageViewAspectConstraint = item.image.map { image in
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: image.size.width / image.size.height)
}

if movieView.data != item.movie {
movieView.data = item.movie
}
movieView.controlsStyle = item.movie != nil ? .minimal : .none
}

@IBAction func imageViewDidChangeValue(_ sender: Any?) {
item.image = imageView.image
imageDidChange?(imageView.image)
}
}
44 changes: 43 additions & 1 deletion WatchFaceDumper/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ final class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDa
let jpeg = image?.tiffRepresentation.flatMap {NSBitmapImageRep(data: $0)}?.representation(using: .jpeg, properties: [.compressionFactor: 0.95])
watchface.resources.files[imageURL] = jpeg
// TODO: resize
watchface.resources.images.imageList[row].cropX = 0
watchface.resources.images.imageList[row].cropY = 0
watchface.resources.images.imageList[row].cropW = Double(image?.size.width ?? 0)
watchface.resources.images.imageList[row].cropH = Double(image?.size.height ?? 0)
watchface.resources.images.imageList[row].originalCropX = 0
watchface.resources.images.imageList[row].originalCropY = 0
watchface.resources.images.imageList[row].originalCropW = Double(image?.size.width ?? 0)
watchface.resources.images.imageList[row].originalCropH = Double(image?.size.height ?? 0)
}
self.reloadDocument()
}
Expand All @@ -128,16 +136,50 @@ final class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDa
let irisVideoURL = watchface.resources.images.imageList[row].irisVideoURL
watchface.resources.files[irisVideoURL] = movie
watchface.resources.images.imageList[row].isIris = movie != nil
watchface.resources.images.imageList[row].irisDuration = 2.3
watchface.resources.images.imageList[row].irisStillDisplayTime = 1.4
// TODO: re-compress: should be less than 3 secs?
// TODO: update duration metadata

}
self.reloadDocument()
}
}
}

@IBAction func addImage(_ sender: Any?) {
NSLog("%@", "not yet implemented")
document.watchface = document.watchface { watchface in
// TODO: get image and compress
let imageData: Data? = Data()
let movieData: Data? = nil

let filenameBase = UUID().uuidString

let item = Watchface.Resources.Metadata.Item(
topAnalysis: .init(bgBrightness: 0, bgHue: 0, bgSaturation: 0, coloredText: false, complexBackground: false, shadowBrightness: 0, shadowHue: 0, shadowSaturation: 0, textBrightness: 0, textHue: 0, textSaturation: 0),
leftAnalysis: .init(bgBrightness: 0, bgHue: 0, bgSaturation: 0, coloredText: false, complexBackground: false, shadowBrightness: 0, shadowHue: 0, shadowSaturation: 0, textBrightness: 0, textHue: 0, textSaturation: 0),
bottomAnalysis: .init(bgBrightness: 0, bgHue: 0, bgSaturation: 0, coloredText: false, complexBackground: false, shadowBrightness: 0, shadowHue: 0, shadowSaturation: 0, textBrightness: 0, textHue: 0, textSaturation: 0),
rightAnalysis: .init(bgBrightness: 0, bgHue: 0, bgSaturation: 0, coloredText: false, complexBackground: false, shadowBrightness: 0, shadowHue: 0, shadowSaturation: 0, textBrightness: 0, textHue: 0, textSaturation: 0),
imageURL: "\(filenameBase).jpg",
irisDuration: 0,
irisStillDisplayTime: 0,
irisVideoURL: "\(filenameBase).mov",
isIris: movieData != nil,
localIdentifier: "",
modificationDate: Date(),
cropH: 0,
cropW: 0,
cropX: 0,
cropY: 0,
originalCropH: 0,
originalCropW: 0,
originalCropX: 0,
originalCropY: 0)
watchface.resources.images.imageList.append(item)
watchface.resources.files[item.imageURL] = imageData
watchface.resources.files[item.irisVideoURL] = movieData
}
reloadDocument()
}

@IBAction func removeImage(_ sender: Any?) {
Expand Down

0 comments on commit dde3ff1

Please sign in to comment.