Skip to content

Commit

Permalink
Merge branch '287-don-t-attempt-to-generate-cgimage-of-zero-size' int…
Browse files Browse the repository at this point in the history
…o 'release/23.3'

Resolve "Don't attempt to generate CGImage of zero size"

Closes #287

See merge request highlighter/app!258
  • Loading branch information
Arclite committed Oct 19, 2023
2 parents 947129c + 06634bb commit ac9c75d
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 22 deletions.
48 changes: 48 additions & 0 deletions Highlighter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@
0489081B24AD7B17005DDEF3 /* Editing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 049F92D722CDA3DB0090C9BC /* Editing.framework */; };
0493D2D624B6BAE400FF99F4 /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0493D2D524B6BAE400FF99F4 /* ColorPickerViewController.swift */; };
0493D2D824B6BD0000FF99F4 /* BrushStampFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0493D2D724B6BD0000FF99F4 /* BrushStampFactory.swift */; };
04956B372AE1215700881F69 /* CharacterObservationRedactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04956B362AE1215700881F69 /* CharacterObservationRedactionTests.swift */; };
04956B3A2AE125AD00881F69 /* ShapeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04956B392AE125AD00881F69 /* ShapeTests.swift */; };
04956B3C2AE12A0E00881F69 /* WordObservationRedactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04956B3B2AE12A0E00881F69 /* WordObservationRedactionTests.swift */; };
04956B3E2AE12D6C00881F69 /* TextObservationRedactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04956B3D2AE12D6C00881F69 /* TextObservationRedactionTests.swift */; };
04956B432AE134FC00881F69 /* UIBezierPathExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04956B422AE134FC00881F69 /* UIBezierPathExtensionsTests.swift */; };
04956B452AE1374100881F69 /* RestoredRedactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04956B442AE1374100881F69 /* RestoredRedactionTests.swift */; };
04975D1E26106D6800AA2771 /* PhotoEditingCanvasBrushStrokeView.h in Headers */ = {isa = PBXBuildFile; fileRef = 04A8A5EB2316589E006CE411 /* PhotoEditingCanvasBrushStrokeView.h */; settings = {ATTRIBUTES = (Public, ); }; };
04975D3726106D8700AA2771 /* PhotoEditingCanvasView.h in Headers */ = {isa = PBXBuildFile; fileRef = 04A8A5EF231659BA006CE411 /* PhotoEditingCanvasView.h */; settings = {ATTRIBUTES = (Public, ); }; };
04975D5826106DC100AA2771 /* PhotoEditingCanvasBrushStrokeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A8A5EC2316589E006CE411 /* PhotoEditingCanvasBrushStrokeView.m */; };
Expand Down Expand Up @@ -924,6 +930,12 @@
0493D2D524B6BAE400FF99F4 /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = "<group>"; };
0493D2D724B6BD0000FF99F4 /* BrushStampFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrushStampFactory.swift; sourceTree = "<group>"; };
04953B5724E2405500877800 /* PhotoEditingViewController+Desktop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhotoEditingViewController+Desktop.swift"; sourceTree = "<group>"; };
04956B362AE1215700881F69 /* CharacterObservationRedactionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterObservationRedactionTests.swift; sourceTree = "<group>"; };
04956B392AE125AD00881F69 /* ShapeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShapeTests.swift; sourceTree = "<group>"; };
04956B3B2AE12A0E00881F69 /* WordObservationRedactionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordObservationRedactionTests.swift; sourceTree = "<group>"; };
04956B3D2AE12D6C00881F69 /* TextObservationRedactionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextObservationRedactionTests.swift; sourceTree = "<group>"; };
04956B422AE134FC00881F69 /* UIBezierPathExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIBezierPathExtensionsTests.swift; sourceTree = "<group>"; };
04956B442AE1374100881F69 /* RestoredRedactionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoredRedactionTests.swift; sourceTree = "<group>"; };
04975D8826106F8B00AA2771 /* HighlighterToolBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlighterToolBarButtonItem.swift; sourceTree = "<group>"; };
049E1EB124BFEEE7009DE20D /* AlbumsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumsViewController.swift; sourceTree = "<group>"; };
049E1EB324BFEF09009DE20D /* AlbumsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumsList.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1943,6 +1955,33 @@
path = "Library Items";
sourceTree = "<group>";
};
04956B352AE120F700881F69 /* Redactions */ = {
isa = PBXGroup;
children = (
04956B362AE1215700881F69 /* CharacterObservationRedactionTests.swift */,
04956B3B2AE12A0E00881F69 /* WordObservationRedactionTests.swift */,
04956B3D2AE12D6C00881F69 /* TextObservationRedactionTests.swift */,
04956B442AE1374100881F69 /* RestoredRedactionTests.swift */,
);
path = Redactions;
sourceTree = "<group>";
};
04956B382AE1259F00881F69 /* Text Detection */ = {
isa = PBXGroup;
children = (
04956B392AE125AD00881F69 /* ShapeTests.swift */,
);
path = "Text Detection";
sourceTree = "<group>";
};
04956B412AE134F000881F69 /* Extensions */ = {
isa = PBXGroup;
children = (
04956B422AE134FC00881F69 /* UIBezierPathExtensionsTests.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
04975D8726106F6D00AA2771 /* Toolbar Items */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2034,6 +2073,9 @@
04B19923262410D5001A275B /* Tests */ = {
isa = PBXGroup;
children = (
04956B412AE134F000881F69 /* Extensions */,
04956B382AE1259F00881F69 /* Text Detection */,
04956B352AE120F700881F69 /* Redactions */,
043CC2462A05DA2E00DEE5B6 /* Editing.xctestplan */,
04B1994226241141001A275B /* Editing View */,
04B19926262410D5001A275B /* Info.plist */,
Expand Down Expand Up @@ -3490,9 +3532,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
04956B3A2AE125AD00881F69 /* ShapeTests.swift in Sources */,
04956B432AE134FC00881F69 /* UIBezierPathExtensionsTests.swift in Sources */,
04B199542624117A001A275B /* PhotoEditingWorkspaceViewTests.swift in Sources */,
04956B3C2AE12A0E00881F69 /* WordObservationRedactionTests.swift in Sources */,
043CC2EA2A0FA19200DEE5B6 /* BrushStampFactoryTests.swift in Sources */,
04956B452AE1374100881F69 /* RestoredRedactionTests.swift in Sources */,
04956B372AE1215700881F69 /* CharacterObservationRedactionTests.swift in Sources */,
04B199A726241697001A275B /* PhotoEditingViewTests.swift in Sources */,
04956B3E2AE12D6C00881F69 /* TextObservationRedactionTests.swift in Sources */,
04B1996C26241234001A275B /* TestHelpers.swift in Sources */,
04B199B02624177F001A275B /* PhotoEditingScrollViewTests.swift in Sources */,
);
Expand Down
30 changes: 22 additions & 8 deletions Modules/Legacy/Editing/Extensions/UIBezierPathExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ extension NSBezierPath.LineJoinStyle {
}

#elseif canImport(UIKit)
import SwiftUI
import UIKit

extension UIBezierPath {
Expand All @@ -126,19 +127,32 @@ extension UIBezierPath {
}

var shape: Shape? {
var ourPathElements = [CGPathElement]()
cgPath.applyWithBlock { elementPointer in
ourPathElements.append(elementPointer.pointee)
let path = Path(self.cgPath)
var elements = [Path.Element]()
path.forEach { element in
elements.append(element)
}

guard ourPathElements.count == 5 && ((ourPathElements.last?.type == .closeSubpath) ?? false) else { return nil }
let points = elements.compactMap(\.point)

return Shape(
bottomLeft: ourPathElements[1].points.pointee,
bottomRight: ourPathElements[2].points.pointee,
topLeft: ourPathElements[0].points.pointee,
topRight: ourPathElements[3].points.pointee
bottomLeft: points[1],
bottomRight: points[2],
topLeft: points[0],
topRight: points[3]
)
}
}

private extension Path.Element {
var point: CGPoint? {
switch self {
case .move(let to): return to
case .line(let to): return to
case .quadCurve: return nil
case .curve: return nil
case .closeSubpath: return nil
}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extension Redaction {
init?(_ characterObservations: [CharacterObservation], color: NSColor) {
guard characterObservations.count > 0 else { return nil }

self.parts = characterObservations.reduce(into: [UUID: [CharacterObservation]]()) { result, characterObservation in
let parts = characterObservations.reduce(into: [UUID: [CharacterObservation]]()) { result, characterObservation in
let textObservationUUID = characterObservation.textObservationUUID
var siblingObservations = result[textObservationUUID] ?? []
siblingObservations.append(characterObservation)
Expand All @@ -19,7 +19,7 @@ extension Redaction {
})
}.map(RedactionPart.shape)

self.color = color
self.init(color: color, parts: parts)
}
}

Expand All @@ -30,7 +30,7 @@ extension Redaction {
init?(_ characterObservations: [CharacterObservation], color: UIColor) {
guard characterObservations.count > 0 else { return nil }

self.parts = characterObservations.reduce(into: [UUID: [CharacterObservation]]()) { result, characterObservation in
let parts = characterObservations.reduce(into: [UUID: [CharacterObservation]]()) { result, characterObservation in
let textObservationUUID = characterObservation.textObservationUUID
var siblingObservations = result[textObservationUUID] ?? []
siblingObservations.append(characterObservation)
Expand All @@ -41,7 +41,7 @@ extension Redaction {
})
}.map(RedactionPart.shape)

self.color = color
self.init(color: color, parts: parts)
}
}
#endif
9 changes: 9 additions & 0 deletions Modules/Legacy/Editing/Redactions/Redaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ public struct Redaction: Equatable {
public let color: RedactionColor
public let parts: [RedactionPart]

init(color: RedactionColor, parts: [RedactionPart]) {
self.color = color
self.parts = parts.filter { part in
if case .shape(let shape) = part {
return shape.isNotEmpty
} else { return true }
}
}

public var paths: [RedactionPath] {
parts.map(\.path)
}
Expand Down
6 changes: 4 additions & 2 deletions Modules/Legacy/Editing/Redactions/RestoredRedaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ extension Redaction: Codable {
let colorData = try container.decode(Data.self, forKey: .color)
let pathsData = try container.decode([Data].self, forKey: .paths)

color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: colorData) ?? .black
let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: colorData) ?? .black
let paths = try pathsData.compactMap { try NSKeyedUnarchiver.unarchivedObject(ofClass: UIBezierPath.self, from: $0) }
parts = RedactionSerializer.parts(from: paths)
let parts = RedactionSerializer.parts(from: paths)

self.init(color: color, parts: parts)
}

public func encode(to encoder: Encoder) throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import AppKit
extension Redaction {
public init<ObservationType: TextObservation>(_ textObservation: ObservationType, color: NSColor) {
let shape = textObservation.bounds
self.parts = [.shape(shape)]

self.color = color
self.init(color: color, parts: [.shape(shape)])
}
}

Expand All @@ -19,9 +17,7 @@ import UIKit
extension Redaction {
public init<ObservationType: TextObservation>(_ textObservation: ObservationType, color: UIColor) {
let shape = textObservation.bounds
self.parts = [.shape(shape)]

self.color = color
self.init(color: color, parts: [.shape(shape)])
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import UIKit
#if canImport(UIKit)
extension Redaction {
init(_ wordObservations: [WordObservation], color: UIColor) {
self.parts = wordObservations.reduce(into: [UUID: [WordObservation]]()) { result, wordObservation in
let parts = wordObservations.reduce(into: [UUID: [WordObservation]]()) { result, wordObservation in
let textObservationUUID = wordObservation.textObservationUUID
var siblingObservations = result[textObservationUUID] ?? []
siblingObservations.append(wordObservation)
Expand All @@ -16,7 +16,8 @@ extension Redaction {
currentRect.union(wordObservation.bounds)
})
}.map(RedactionPart.shape)
self.color = color

self.init(color: color, parts: parts)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Created by Geoff Pado on 10/19/23.
// Copyright © 2023 Cocoatype, LLC. All rights reserved.

import XCTest

@testable import Editing

final class UIBezierPathExtensionsTests: XCTestCase {
func testCreatingShape() throws {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 0, y: 5))
path.addLine(to: CGPoint(x: 5, y: 5))
path.addLine(to: CGPoint(x: 5, y: 0))
path.close()

let shape = try XCTUnwrap(path.shape)
XCTAssertEqual(shape, TestHelpers.shape)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Created by Geoff Pado on 10/19/23.
// Copyright © 2023 Cocoatype, LLC. All rights reserved.

import XCTest

@testable import Editing

final class CharacterObservationRedactionTests: XCTestCase {
#if canImport(UIKit)
func testInitIgnoresEmptyShapes() throws {
let observation = CharacterObservation(bounds: TestHelpers.emptyShape, textObservationUUID: UUID())
let redaction = try XCTUnwrap(Redaction([observation], color: .black))

XCTAssertEqual(redaction.parts.count, 0)
}

func testInitIncludesNonEmptyShapes() throws {
let observation = CharacterObservation(bounds: TestHelpers.shape, textObservationUUID: UUID())
let redaction = try XCTUnwrap(Redaction([observation], color: .black))

XCTAssertEqual(redaction.parts.count, 1)
}
#endif
}
Loading

0 comments on commit ac9c75d

Please sign in to comment.