Skip to content

Commit

Permalink
edit README
Browse files Browse the repository at this point in the history
  • Loading branch information
maning00 committed Nov 9, 2021
1 parent 17419e7 commit a4a9ae5
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 20 deletions.
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
# StickerMator
StickerMator is a SwiftUI based iOS app to add stickers to photos, it can use different sticker packs and users can make their own sticker packs.
StickerMator is a SwiftUI based iOS app that runs with iPhone and iPad. using this app you can add stickers to your photos, image manipulation of stickers, and make your own sticker packs. It is a free app and you can use it for free. This project is also part of my Swift learning track.
<div align="center">
<img src="https://dsc.cloud/8532ed/skm-1.jpeg" height="500px" alt="skm-1" >
<img src="https://dsc.cloud/8532ed/skm-2.jpeg" height="500px" alt="skm-2" >
<img src="https://dsc.cloud/8532ed/skm-1.jpg" height="230px" alt="skm-1" >
<img src="https://dsc.cloud/8532ed/skm-2.jpg" height="230px" alt="skm-2" >
</div>

## Features
- **Sticker Maker**: A simple sticker editing tool that allows users to select images from photo albums for processing. CoreML-based image segmentation enables automatic background removal for sticker creation. In addition, a variety of filters are provided for users to freely choose to adjust.
- **Sticker Maker**: A simple sticker editing tool that allows you to select images from photo albums for processing. CoreML-based image segmentation enables automatic background removal for sticker creation. In addition, a variety of filters are provided for you to freely choose to adjust.
<div align="center">
<img src="https://dsc.cloud/8532ed/skm-3.PNG" height="240px" alt="skm-3" >
<img src="https://dsc.cloud/8532ed/skm-4.PNG" height="240px" alt="skm-4" >
</div>
<div align="center">
<img src="https://dsc.cloud/8532ed/skm-5.PNG" height="400px" alt="skm-5" >
<img src="https://dsc.cloud/8532ed/IMG_0150.PNG" height="240px" alt="skm-5" >
<img src="https://dsc.cloud/8532ed/skm-5.PNG" height="240px" alt="skm-5" >
</div>

- **Sticker Packs**: Users can customize their own sticker packs, manage them at will, add and delete.
- **Sticker Packs**: You can customize your own sticker packs, manage them at will, add and delete.
<div align="center">
<img src="https://dsc.cloud/8532ed/skm-6.PNG" height="240px" alt="skm-6" >
<img src="https://dsc.cloud/8532ed/skm-7.PNG" height="240px" alt="skm-7" >
</div>

- **Multi-Touch support**: Stickers and images in StickerMator can be resized with smooth multi-touch gestures.
- **skm file format**: With Apple's document API, StickerMator created the **skm** file format, which is a simple format for storing user data and sticker packs. Files can also be saved to iCloud.
- **CoreML**: CoreML is a powerful machine learning framework that makes it easy to apply machine learning techniques to apps, StickerMator uses CoreML's DeepLab V3 model for image processing to quickly acquire target areas and use the CoreImage API for image background removal, this makes sticker editing even more powerful.

- **Gesture support**: You can freely use different gestures to make adjustments to images or stickers, such as zooming using two fingers, moving and adjusting stickers and images.

- **Document-based interface**: With Apple's document API, StickerMator can store files locally or in iCloud using Document Manager, StickerMator also created the **skm** file format, which is a simple format for storing user data and sticker packs.

## Requirements
- **iOS 15.0** or later
- **Swift 5**
- **Xcode 13**

## Known Issues
- **Zoom anchor point**: When the overall scaling is performed, the scaling anchor points of the sticker and the background image will have inconsistent problems, and displacement will occur between the sticker and the background image when scaling. To solve this problem, you need to fix the scaling anchor points of the sticker and the background image.
- **Save to photo albums**: Still haven't found a better way to save as an image, when trying to use UIHostingController to read the View and render it with UIGraphicsImageRenderer, the position of the background image and the sticker will be wrong, this problem is to be solved.


## See also
- [CS193p - Developing Apps for iOS](https://cs193p.sites.stanford.edu/)
Expand Down
21 changes: 21 additions & 0 deletions StickerMator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
FB6A0614272F7CF4000DBA59 /* Sources */,
FB6A0615272F7CF4000DBA59 /* Frameworks */,
FB6A0616272F7CF4000DBA59 /* Resources */,
FBCAA99A273A0858004C26E5 /* ShellScript */,
);
buildRules = (
);
Expand Down Expand Up @@ -206,6 +207,26 @@
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
FBCAA99A273A0858004C26E5 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n";
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
FB6A0614272F7CF4000DBA59 /* Sources */ = {
isa = PBXSourcesBuildPhase;
Expand Down
10 changes: 10 additions & 0 deletions StickerMator/Camera.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@ import SwiftUI

// UIKit => Coordinator => SwiftUI

/// An camera image picker, pick image from camera.
///
/// The Camera struct uses Coordinator to build a bridge between SwiftUI and UIKit.
struct Camera: UIViewControllerRepresentable {

/// An image handler receives UIImage and process
var imageHandleFunc: (UIImage?) -> Void

func makeUIViewController(context: Context) -> UIImagePickerController {

/// An UIImagePickerController created and set options.
///
/// Here, allowsEditing is ``true``, user can crop image.
/// sourceType is set to ``.camera``, the image will be captured from the camera.
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.sourceType = .camera
Expand Down
24 changes: 14 additions & 10 deletions StickerMator/Helpers/Helper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ struct UndoButton: View {

/// A button with animation.
struct AnimatedActionButton: View {
var title: String? = nil
var systemImage: String? = nil
var title: String?
var systemImage: String?
let action: () -> Void
var labelFont: Font? = nil
var labelFont: Font?

var body: some View {
Button {
Expand Down Expand Up @@ -89,14 +89,15 @@ func getDocumentsDirectory() -> URL {
struct IconAboveTextButton: View {

var title: String
var systemImage: String? = nil
var textFont: Font? = nil
var iconSize: CGFloat? = nil
var systemImage: String?
var textFont: Font?
var iconSize: CGFloat?
let action: () -> Void

var body: some View {
VStack(spacing: 5) {
AnimatedActionButton(title: "", systemImage: systemImage, action: action, labelFont: .system(size: iconSize ?? 40))
AnimatedActionButton(title: "", systemImage: systemImage,
action: action, labelFont: .system(size: iconSize ?? 40))
Text(title).font(textFont)
}

Expand All @@ -105,7 +106,8 @@ struct IconAboveTextButton: View {

/// A function to append filename to path
func getSavedImage(named: String) -> String? {
if let dir = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
if let dir = try? FileManager.default.url(for: .documentDirectory,
in: .userDomainMask, appropriateFor: nil, create: false) {
return URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(named).path
}
return nil
Expand Down Expand Up @@ -147,7 +149,7 @@ extension Array where Element == NSItemProvider {
func loadObjects<T>(ofType theType: T.Type, firstOnly: Bool = false,
using load: @escaping (T) -> Void) -> Bool where T: NSItemProviderReading {
if let provider = first(where: { $0.canLoadObject(ofClass: theType) }) {
provider.loadObject(ofClass: theType) { object, error in
provider.loadObject(ofClass: theType) { object, _ in
if let value = object as? T {
DispatchQueue.main.async {
load(value)
Expand All @@ -161,7 +163,7 @@ extension Array where Element == NSItemProvider {
func loadObjects<T>(ofType theType: T.Type, firstOnly: Bool = false,
using load: @escaping (T) -> Void) -> Bool where T: _ObjectiveCBridgeable, T._ObjectiveCType: NSItemProviderReading {
if let provider = first(where: { $0.canLoadObject(ofClass: theType) }) {
let _ = provider.loadObject(ofClass: theType) { object, error in
let _ = provider.loadObject(ofClass: theType) { object, _ in
if let value = object {
DispatchQueue.main.async {
load(value)
Expand Down Expand Up @@ -257,6 +259,8 @@ extension View {

extension View {
/// A method convers the view to an UIImage.
///
/// This method is temporarily unused.
func saveAsImage(mainImage: UIImage?) -> UIImage {
let controller = UIHostingController(rootView: self)
var targetSize = CGSize(width: 1000, height: 1000)
Expand Down
9 changes: 9 additions & 0 deletions StickerMator/ImagePicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@ import SwiftUI

// UIKit => Coordinator => SwiftUI

/// An image picker, pick image from photo library.
///
/// ImagePicker uses Coordinator to build a bridge between SwiftUI and UIKit.
struct ImagePicker: UIViewControllerRepresentable {

/// An image handler receives UIImage and process
var imageHandleFunc: (UIImage?) -> Void

func makeUIViewController(context: Context) -> UIImagePickerController {

/// An UIImagePickerController created and set options.
///
/// Here, allowsEditing is ``true``, user can crop image.
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = context.coordinator
Expand Down
10 changes: 10 additions & 0 deletions StickerMator/ImageSaver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,21 @@

import UIKit

/// A class saves UIImage to photo album.
///
class ImageSaver: NSObject {
func saveToAlbum(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveError), nil)
}

/// completionSelector for ``UIImageWriteToSavedPhotosAlbum``
///
/// This method conform to the following signature:
/// ````
/// (void)image:(UIImage *)image
/// didFinishSavingWithError:(NSError *)error
/// contextInfo:(void *)contextInfo;
/// ````
@objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
logger.error("Save Image Error: \(error.localizedDescription)")
Expand Down
2 changes: 1 addition & 1 deletion StickerMator/StickerBottomBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct StickerBottomBar: View {
}

@State private var chosenIndex = 0
@State private var stickersetToEdit: StickerPack? = nil
@State private var stickersetToEdit: StickerPack?
@State private var managing = false
@State private var showEditor = false

Expand Down
3 changes: 2 additions & 1 deletion StickerMator/StickerMatorViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ class StickerMatorViewModel: ReferenceFileDocument {
/// - zoomScale: The zoom ratio of the main interface when adding stickers.
/// - undoManager: UndoManager.
///
/// In order to avoid the original image being too large, a zoom factor is added to this function, and the shortest side of the image is fixed to 200.
/// In order to avoid the original image being too large, a zoom factor is added to this function,
/// and the shortest side of the image is fixed to 200.
func addSticker (image: UIImage, at location: CGPoint, zoomScale: CGFloat, undoManager: UndoManager?) {
if let data = image.pngData() {
let factor = min(image.size.width, image.size.height) / 200
Expand Down

0 comments on commit a4a9ae5

Please sign in to comment.