I can't seem to get the url, from the PlacePhotoMetadata object. Debugger shows that there is an URL there but I can't seem to access it.
How do you access the URL in the object?
val placeId = "ChIJa147K9HX3IAR-lwiGIQv9i4"
val photoMetadataResponse = mGeoDataClient.getPlacePhotos(placeId)
photoMetadataResponse.addOnCompleteListener { task ->
// Get the list of photos
val photos = task.result
// Get the PlacePhotoMetadataBuffer (metadata for all of the photos)
val photoMetadataBuffer = photos.photoMetadata
// Get the first photo in the list
for (photo in photoMetadataBuffer) {
// Get the attribution text
val attribution = photo.attributions
}
}
You can't. Take a look at the documentation for PlacePhotoMetadata. There are methods to download a bitmap of the image, but no methods that return the URL.
To get the photo you should do something like this:
// this is your for-loop:
photoMetadataBuffer.forEach { photo ->
photo.getPhoto(client).setResultCallback({ result ->
// do whatever you want here:
showPhotoWithAttribution(photo.attributions, result.getBitmap())
})
}
Note that replacing a for-loop with a forEach call has no real advantage, it just makes your code look cleaner.
Related
I want to upload multiple images to Firebase Storage and get the URL of each one. I use a task for this. So far everything works. But how can I only read out the list with the URLs when the task forEach is finished? It is currently the case that the list is only output in the log, it is empty, and then it is jumped to forEach:
Tasks.whenAllSuccess<UploadTask>(tasks).addOnSuccessListener {
val downloadUrls = mutableListOf<String>()
tasks.forEach {
it.result.metadata!!.reference!!.downloadUrl.addOnSuccessListener { snap->
downloadUrls.add(snap.toString())
Log.e("Downloadable Image URL",snap.toString())
}
}
//The list here is empty
Log.d("List with URLs",downloadUrls.toString())
progressDialog.dismiss()
}
By the time you're calling:
Log.d("List with URLs",downloadUrls.toString())
The operation of adding files to Storage isn't completed yet. So that's the reason why you get an empty list. If you want to see the content of the downloadUrls list, you have to use that log statement only when the operations are 100% complete. Now, since you're using Kotlin, I recommend you use Kotlin Coroutines. So your code can be written as simple as:
val downloadUrls = mutableListOf<String>()
val listOfTasks = Tasks.whenAllSuccess<UploadTask>(tasks).await()
listOfTasks.forEach {
val downloadUrl = it.result.metadata!!.reference!!.downloadUrl.await()
downloadUrls.add(downloadUrl)
}
Log.d("List with URLs",downloadUrls.toString())
I am using Person Object to build chat app notifications like Gmail. So I have created the person object. But i want to set icon from a image URL coming from server an not from drawable resource. I am using Coil library for loading images . The below code is working fine,
By default the android generates the icon with the first letter passed to the title.
So, How can i show the image coming from server as a URL in icon with best practice of memory and resource usages. Below is my Person object.
Here is the Official link of Person.
And this is what I referred to Notification Messaging style tutorial
val senderPerson: Person = Person.Builder().also {person->
person.setKey(message.getSenderKey(prefs))
person.setName(message.getNotificationTitle())
person.setImportant(true)
//****HERE I WANT TO SET IMAGE FROM URL******
// person.setIcon(IconCompat.createWithResource(this, R.drawable.placeholder_transaparent))
}.build()
You'd load the image URL asynchronously using the Coil Request, and return the fetched icon in a closure.
Coil returns a drawable, and you can get Icon from a Drawable through a Bitmap using IconCompat.createWithBitmap((drawable as BitmapDrawable).bitmap):
private fun asyncLoadIcon(imageUrl: String?, setIcon: (IconCompat?) -> Unit) {
if (imageUrl.isNullOrEmpty())
setIcon(null)
else {
// using COIL to load the image
val request = ImageRequest.Builder(this)
.data(imageUrl)
.target { drawable ->
setIcon(IconCompat.createWithBitmap((drawable as BitmapDrawable).bitmap)) // // Return the fetched icon from the URL
}
.listener(object : ImageRequest.Listener { // Return null icon if the URL is wrong
override fun onError(request: ImageRequest, result: ErrorResult) {
setIcon(null)
}
})
.build()
imageLoader.enqueue(request)
}
}
This code returns a null icon if the URL is wrong or if it's empty/null.
Then build the notification message with that function:
asyncLoadIcon("https://my_icon_url.png") { // set the icon url
val person = Person.Builder().apply {
setName("John Doe")
setIcon(it)
}.build()
// Build the notification with the person
.....
}
For some enhancements, you'd enable caching, and disable hardware bitmaps; but I do recommend other libraries like Glide and Picasso.
.memoryCachePolicy(CachePolicy.ENABLED)
.diskCachePolicy(CachePolicy.ENABLED)
.allowHardware(false) // Disable hardware bitmaps
I'm new to wowza and is working on a project to live stream video captured from an Android device. I need to attach an image(dynamic one) to the video stream so that the users watching the stream can view it. The code I have tried is given below(as from the example source code from wowza):
// Read in a PNG file from the app resources as a bitmap
Bitmap overlayBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.overlay_logo);
// Initialize a bitmap renderer with the bitmap
mWZBitmap = new WZBitmap(overlayBitmap);
// Place the bitmap at top left of the display
mWZBitmap.setPosition(WZBitmap.LEFT, WZBitmap.TOP);
// Scale the bitmap initially to 75% of the display surface width
mWZBitmap.setScale(0.75f, WZBitmap.SURFACE_WIDTH);
// Register the bitmap renderer with the GoCoder camera preview view as a frame listener
mWZCameraView.registerFrameRenderer(mWZBitmap);
This works fine, but I don't want to show the image at the broadcasting end, the image should be visible only at the receiving end. Is there anyway to get this done?
I managed to get this done by registeringFrameRenderer and setting the bitmap inside onWZVideoFrameRendererDraw.
Code snippet is as given below(Kotlin):
private fun attachImageToBroadcast(scoreValue: ScoreUpdate) {
bitmap = getBitMap(scoreValue)
// Initialize a bitmap renderer with the bitmap
mWZBitmap = WZBitmap(bitmap)
// Position the bitmap in the display
mWZBitmap!!.setPosition(WZBitmap.LEFT, WZBitmap.TOP)
// Scale the bitmap initially
mWZBitmap!!.setScale(0.37f, WZBitmap.FRAME_WIDTH)
mWZBitmap!!.isVisible = false // as i dont want to show it initially
mWZCameraView!!.registerFrameRenderer(mWZBitmap)
mWZCameraView!!.registerFrameRenderer(VideoFrameRenderer())
}
private inner class VideoFrameRenderer : WZRenderAPI.VideoFrameRenderer {
override fun onWZVideoFrameRendererRelease(p0: WZGLES.EglEnv?) {
}
override fun onWZVideoFrameRendererDraw(p0: WZGLES.EglEnv?, framSize: WZSize?, p2: Int) {
mWZBitmap!!.setBitmap(bitmap) // note that the bitmap value gets changed once I get the new values
//I have implemented some flags and conditions to check whether a new value has been obtained and only if these values are satisfied, the setBitmap is called. Otherwise, as it is called continuously, flickering can occur in the screen
}
override fun isWZVideoFrameRendererActive(): Boolean {
return true
}
override fun onWZVideoFrameRendererInit(p0: WZGLES.EglEnv?) {
}
}
In iOS, we can implement WZVideoSink protocol to achieve this.
First, we need to update the scoreView with the latest score and then convert the view to an image.
Then we can embed this image to the captured frame using WZVideoSink protocol method.
A sample code is given below.
// MARK: - WZVideoSink Protocol
func videoFrameWasCaptured(_ imageBuffer: CVImageBuffer, framePresentationTime: CMTime, frameDuration: CMTime) {
if self.goCoder != nil && self.goCoder!.isStreaming {
let frameImage = CIImage(cvImageBuffer: imageBuffer)
var addCIImage: CIImage = CIImage()
if let scoreImage = self.getViewAsImage() {
// scoreImage is the image you want to embed.
addCIImage = CIImage(cgImage: scoreImage.cgImage!)
}
let filter = CIFilter(name: "CISourceOverCompositing")
filter?.setDefaults()
filter?.setValue(addCIImage, forKey: kCIInputImageKey)
filter?.setValue(frameImage, forKey: kCIInputBackgroundImageKey)
if let outputImage: CIImage = filter?.value(forKey: kCIOutputImageKey) as? CIImage {
let context = CIContext(options: nil)
context.render(outputImage, to: imageBuffer)
} else {
let context = CIContext(options: nil)
context.render(frameImage, to: imageBuffer)
}
}
}
func getViewAsImage() -> UIImage {
// convert scoreView to image
UIGraphicsBeginImageContextWithOptions(self.scoreView.bounds.size, false, 0.0)
self.scoreView.layer.render(in: UIGraphicsGetCurrentContext()!)
let scoreImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return scoreImage
}
I have developed an app to take a photo from the phone camera. But now I need to store the image to the phone memory into a folder created by me.
I have tried this:
var filename = Titanium.Filesystem.resourcesDirectory + "/newImageFile.jpg";
var imageFile = Titanium.Filesystem.getFile(filename);
imageFile.write(capturedImg);
But it does not apear in the gallery. How can I store the image to the phone memory and how can I create a costume folder in the phone memory to store the image?
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
NSData *imageData = [info objectForKey:UIImagePickerControllerOriginalImage];
if(picker.sourceType==UIImagePickerControllerSourceTypeCamera)
{
//to save camera roll
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:nil];
}
}
This will save image in camera roll which is taken by you
This Will Create Photo Album and save into this album.
I came up with this singleton class to handle it:
import Photos
class CustomPhotoAlbum {
static let albumName = "Titanium"
static let sharedInstance = CustomPhotoAlbum()
var assetCollection: PHAssetCollection!
init() {
func fetchAssetCollectionForAlbum() -> PHAssetCollection! {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", CustomPhotoAlbum.albumName)
let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
if let firstObject: AnyObject = collection.firstObject {
return collection.firstObject as! PHAssetCollection
}
return nil
}
if let assetCollection = fetchAssetCollectionForAlbum() {
self.assetCollection = assetCollection
return
}
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(CustomPhotoAlbum.albumName)
}) { success, _ in
if success {
self.assetCollection = fetchAssetCollectionForAlbum()
}
}
}
func saveImage(image: UIImage) {
if assetCollection == nil {
return // If there was an error upstream, skip the save.
}
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection)
albumChangeRequest.addAssets([assetPlaceholder])
}, completionHandler: nil)
}
}
When you first instantiate the class, the custom album will be created if it doesn't already exist. You can save an image like this:
CustomPhotoAlbum.sharedInstance.saveImage(image)
NOTE: The CustomPhotoAlbum class assumes the app already has permission to access the Photo Library. Dealing with the permissions is a bit outside the scope of this question/answer. So make sure PHPhotoLibrary.authorizationStatus() == .Authorize before you use it. And request authorization if necessary.
I'm trying to get a photo from known placeID location ("ChIJqaUj8fBLzEwRZ5UY3sHGz90").
I'm using the code below (from the google guide)
PlacePhotoMetadataResult result = Places.GeoDataApi.getPlacePhotos(mGoogleApiClient, placeId).await();
if (result.getStatus().isSuccess()) {
PlacePhotoMetadataBuffer photoMetadataBuffer = result.getPhotoMetadata();
if (photoMetadataBuffer.getCount() > 0 && !isCancelled()) {
// Get the first bitmap and its attributions.
PlacePhotoMetadata photo = photoMetadataBuffer.get(0);
CharSequence attribution = photo.getAttributions();
// Load a scaled bitmap for this photo.
Bitmap image = photo.getScaledPhoto(mGoogleApiClient, mWidth, mHeight).await()
.getBitmap();
attributedPhoto = new AttributedPhoto(attribution, image);
}
// Release the PlacePhotoMetadataBuffer.
photoMetadataBuffer.release();
}
the result.getStatus returns a success, but PhotoMetadataBuffer is returned empty (photoMetadataBuffer.getCount = 0).
Has anyone successfully got an image using this method?
It looks like there aren't any photos associated with this place at the moment. If you try another place id that has associated photos, you should get some results. For example, try this place id:
ChIJN1t_tDeuEmsRUsoyG83frY4