Search code examples
swiftvaporswift-nio

Swift Vapor 4 upload , validate , resize an image file


I am trying to post a photo to the vapor 4 server. I am sending a Team name as a string and an image as data.

struct SendTeam: Content {
    var name: String
    var img: Data
}

I want to upload the photo after validating its size to be not more than 1MB, and mimetype is of type image like (jpg, jpeg, png), then resize that image to 300px*300px and finally save it to the public\uploads directory.

I am not able to figure out how to do that.

Here is my code.

func create(req: Request) async throws -> SendTeam {
    let team = try req.content.decode(SendTeam.self)
    
    let path = req.application.directory.publicDirectory + "originals/" + team.name + "-\(UUID())"
    
    try await req.fileio.writeFile(.init(data: team.img), at: path)
    
    if team.name.count < 4 || team.name.count > 20 {
        throw Abort(.badRequest, reason: "wrong name")
    }
    
    return team
}

Code should work on ubuntu server VPS cloud instance as well.


Solution

  • After Two Days of Testing, I am able to do that using SwiftGD, So I came up with this .. hope it is useful.

    Image Validation

    // Do not forget to decode the image to File type Not Data type
    let img = team.img
    
    if img.data.readableBytes > 1000000  {
        errors.append( "error ... image size should not exceed 1 mb")
    }
    
    if !["png", "jpeg", "jpg"].contains(img.extension?.lowercased()) {
        errors.append("extension is not acceptable")
    }
    
        let imageNewNameAndExtension = "\(UUID())"+".\(img.extension!.lowercased())"
    

    The upload an resize part

    // The upload Path
            let path = req.application.directory.publicDirectory + "uploads/" + imageNewNameAndExtension
    // The path to save the resized img
            let newPath = req.application.directory.publicDirectory + "uploads/teams/" + imageNewNameAndExtension
            
            // SwiftNIO File handle
            let handle = try await req.application.fileio.openFile(path: path,mode: .write,flags:.allowFileCreation(posixMode:0x744),eventLoop: req.eventLoop).get()
            
            // Save the file to the server
        req.application.fileio.write(fileHandle:handle,buffer:img.data,eventLoop: req.eventLoop).whenSuccess { _ in
    // SwiftGD part to resize the image
                let url = URL(fileURLWithPath: path)
                let newUrl = URL(fileURLWithPath: newPath)
                let image = Image(url: url)
                if let im = image {
                    if let mg = im.resizedTo(width: 250, height: 250){
                        mg.write(to: newUrl)
                    }
                }
                
                try? handle.close()
            }