There's a lot of similar questions on here, but i couldn't find an answer that's help me in solving this problem.
What I want to do is upload an image with Alamofire with parameters
and the image itself should be part of the parameters.
For example the parameters should be like this:
["user_id": 1, "picture": 'and here will be the image that i want to upload']
in the response i will be getting the image as a link like this:
"/uploads/members/'user_id'/images/member_'user_id'/28121284ase2.jpg"
something similar to that.
Also the image should be ' jpg, png and not more than 5MB '.
I'm new to uploading images w\ API so I don't what to do exactly.
I tried every solution I could find in here and google but no luck so far. Any help would be appreciated.
I'm going to assume that you have an instance of UIImage to start with, you'll have to encode it to base64 and send it to your backend as you would any other String parameter. This should help :
extension UIImage {
func toBase64() -> String? {
guard let imageRectoData = jpeg(.low) else {
return nil
}
return imageRectoData.base64EncodedString()
}
enum JPEGQuality: CGFloat {
case lowest = 0
case low = 0.25
case medium = 0.5
case high = 0.75
case highest = 1
}
/// Returns the data for the specified image in JPEG format.
/// If the image object’s underlying image data has been purged, calling this function forces that data to be reloaded into memory.
/// - returns: A data object containing the JPEG data, or nil if there was a problem generating the data. This function may return nil if the image has no data or if the underlying CGImageRef contains data in an unsupported bitmap format.
func jpeg(_ jpegQuality: JPEGQuality) -> Data? {
return jpegData(compressionQuality: jpegQuality.rawValue)
}
}
You can do that by using multipart/form-data request.
your question is relative to this one: Upload image with multipart form-data iOS in Swift
Related
I'm trying to cache UIImage that images come from service(I'm using Alamofire). Service sends me a base64 string and I'm converting base64 to data then print in tableviewcell with
cell.imageview.image = UIImage(data: imageDatas[indexPath.row])
I searched lots of libraries like Kingfisher , AlamofireImage but they are caching URL image can't find anyway to cache image with base64 string.So I find a similar example and try this :
private let cache = NSCache<NSNumber, UIImage>()
private let utilityQueue = DispatchQueue.global(qos: .utility)
private func loadImage(data : Data , completion: #escaping (UIImage?) -> ()) {
utilityQueue.async {
let image = imageDataDecodingClass.imageDataDecoding(imageData: data)
DispatchQueue.main.async {
completion(image)
}
}
}
in cell :
let itemNumber = indexPath.section * 2 + 1
let imageData = (showcaseDatas[indexPath.section * 2 + 1].Document?.Document!)!
if let cachedImage = self.cache.object(forKey: NSNumber(value: itemNumber)) {
cell.showcaseImage.image = cachedImage
} else {
cell.addSubview(progressHUDimage)
self.loadImage(data: imageData, completion: {ret in
cell.showcaseImage.image = ret
self.cache.setObject(cell.showcaseImage.image!, forKey: NSNumber(value: itemNumber))
progressHUDimage.removeFromSuperview()
})
}
Its caching image perfectly but when I scroll tableview ,CPU increased a lot (%70-90) thats why tableview is not smoothing.
So , my question is , How can I cache base64 string image in tableviewcell with smoothing and without CPU increased ? Thanks
If you are caching base64 String or Data there will be always a hit in decoding them as an image. The only way it would be caching the UIImage itself, but this will come with trade off of memory depending on the size of your images.
I can only give you few advices:
Use NSCache (it seems that you are already using it)
Resize your images on another thread to have a perfect fit on the size that you are rendering on screen and cache them only after they have been resized
Be sure that the performance hit you are seeing is not due to other reasons
Cache images by using their index path if you are using for cells
Create your NSCache with a memory limit and a number of element limit
You can also try to create 2 caches, one for ready to go already decode images and the other one as a fallback with Data object.
The fact that your Data objects are small it doesn't means that also images are, it really depends on the compression that has been used to save the image representation.
There are also more advance technique using memory mapping on physical memory.
I've created a Service file in order to handle all of my networking within the Weather Application that I am fine tuning. Within this service file, I use protocols, in order to return the retrieved data from GET requests to the appropriate View Controller.
During my code refactoring, and for the sake of learning, rather than using URLSessions, I decided I wanted to learn how to use Alamofire.
One of my GET requests retrieves an image of either a (sun, cloud, rain cloud, etc.), depending on the weather of a certain city (this is an example of the URL I am submitting my GET request to: http://openweathermap.org/img/wn/03n#2x.png.
Before I imported Alomofire, I would GET the bytes of this image, and render the bytes within UIImage like so:
self.weatherIcon.image = UIImage(data: result)
This worked just fine. But now, when using Alamofire for my request, the challenge I am having is that I'm unable to convert AFDataResponse to type Data, in order to then be rendered to UIImage.
Below you may see my GET Request.
AF.request(myUrl).responseData{response in
debugPrint(reponse)
self.delegate3?.iconServiceDelegateDidFinishWithData(result: response)
}
The response is of type AFDataResponse.
Therefore, when trying to write:
self.weatherIcon.image = UIImage(data: result)
I get an error saying,
Cannot convert value of type 'AFDataResponse (aka 'DataResponse<Data, AFError') to expected argument type 'Data'.
Any help would be much appreciated from the community.
Thanks.
Simple answer:
Create a variable of type Data and assign response.data to this variable.
AF.request(myUrl).responseData{ response in
debugPrint(response)
var imgData : Data //create variable of type data
imgData = Data(response.data!) // access the data through response.data
self.delegate3?.iconServiceDelegateDidFinishWithData(result: imgData)
}
There are many ways to do this. You can access the data directly, as you originally suggested (though I would treat it as an Optional rather than force unwrapping, as it'll crash otherwise).
.responseData { response in
let image = response.data.map(UIImage.init(data:)) // Creates UIImage?
}
You can transform the Result value to maintain any Error you receive.
.responseData { response in
let image = response.result.map(UIImage.init(data:)) // Creates Result<UIImage, AFError>
}
Or you can map the entire DataResponse.
.responseData { response in
let imageResponse = response.map(UIImage.init(data:)) // Creates DataResponse<UIImage, AFError>
}
This might be an amateur question, but although I have searched Stack Overflow extensibly, I haven't been able to get an answer for my specific problem.
I was successful in creating a GIF file from an array of images by following a Github example:
func createGIF(with images: [NSImage], name: NSURL, loopCount: Int = 0, frameDelay: Double) {
let destinationURL = name
let destinationGIF = CGImageDestinationCreateWithURL(destinationURL, kUTTypeGIF, images.count, nil)!
// This dictionary controls the delay between frames
// If you don't specify this, CGImage will apply a default delay
let properties = [
(kCGImagePropertyGIFDictionary as String): [(kCGImagePropertyGIFDelayTime as String): frameDelay]
]
for img in images {
// Convert an NSImage to CGImage, fitting within the specified rect
let cgImage = img.CGImageForProposedRect(nil, context: nil, hints: nil)!
// Add the frame to the GIF image
CGImageDestinationAddImage(destinationGIF, cgImage, properties)
}
// Write the GIF file to disk
CGImageDestinationFinalize(destinationGIF)
}
Now, I would like to turn the actual GIF into NSData so I can upload it to Firebase, and be able to retrieve it on another device.
To achieve my goal, I have two options: Either to find how to use the code above to extract the GIF created (which seems to directly be created when creating the file), or to use the images on the function's parameters to create a new GIF but keep it on NSData format.
Does anybody have any ideas on how to do this?
Since nobody went ahead for over six months I will just put the answer from #Sachin Vas' comment here:
You can get the data using NSData(contentsOf: URL)
I'm writing an iOS app with a Parse backend, and amongst other things it will list blog entries.
Each blog entry has an associated image, but I don't want to fetch the image object for each entry and then have to fetch the image file for each of those. So I wrote a cloud function that would combine the two steps and return the raw image data with a single request.
Here's the cloud code:
var imageFile = image.get("photoFile");
Parse.Cloud.httpRequest({ url: imageFile.url()
}).then(function(dataResponse){
response.success(dataResponse.buffer);
});
When I do this, I get back an array of integers, and I don't know where to go from here to get a UIImage. Here's the iOS code I have so far:
PFCloud.callFunctionInBackground(latestImageCloudFunctionName, withParameters: parameters) { (imageData, error) -> Void in
if let data = imageData {
//imageData is of the type [Int]
}
}
Is the image base64 encoded here? How do I get an NSData object from this that will create a UIImage?
I'm using MonoTouch and I have a UIImage (displayed in a UIImageView and it looks good) and I'm trying to convert it to NSData, but AsJPEG and AsPNG returns null. What can be the problem?
My code looks like this:
NSError err;
NSData imageData = CroppedImageView.Image.AsJPEG(); // imageData is null!
if (!imageData.Save ("tmp.png", true, out err)) {
Console.WriteLine("Saving of file failed: " + err.Description);
}
The AsJPEG method calls UIImageJPEGRepresentation and its return value is documented as:
A data object containing the JPEG data, or nil if there was a problem generating the data. This function may return nil if the image has no data or if the underlying CGImageRef contains data in an unsupported bitmap format.
The is similar to many API in iOS (and OSX) where exception are not commonly used (and null is used to report some kind of error).
Anyway you should check your image dimensions and properties - they might give you an hint at something that would not translate into a JPEG bitmap.
Also since the NSData can represent a very large amount of memory you should try to limit it's life, e.g.:
using (NSData imageData = CroppedImageView.Image.AsJPEG ()) {
NSError err;
if (!imageData.Save ("tmp.jpg", true, out err)) {
Console.WriteLine("Saving of file failed: " + err.Description);
}
}
It looks like you are writing to a file in the current directory of the app, this is readonly.
You should use:
var path = System.IO.Path.GetTempFilename();
or
var path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "tmp.png");
Like you would do on other platforms, and use a file from there.
You can also use Environment.SpecialFolder.MyDocuments.
The AsJPEG returned null because the image size was too big (it was taken with an iPhone 5). After I Scaled it down by 2, it generates the data properly.