I am using the Android.gms.maps class to create a custom renderer google map in my Xamarin Forms app, for android phones. I am looking to add an image to my map using GroundOverlayOptions
GroundOverlayOptions newarkMap = new GroundOverlayOptions()
.InvokeImage(BitmapDescriptorFactory.FromResource(/*My image?*/))
.position(e.Point, 8600f, 6500f);
map.AddGroundOverlay(newarkMap);
I need the images resource ID in the commented section of my code. How do I find out an images' resource ID? Is there an alternative way to do it?
Using BitmapDescriptorFactory you have multiple options available to how you obtain the BitmapDescriptor
FromResource
FromAsset
FromPath
FromBitmap
Couple of examples:
To use the FromResource, the image must be within your Resource tree, assumably within the Drawable subfolder, Xamarin will generate an id descriptor for you in the form of Resource.Drawable.XXXXX and that will be an integer constant:
var overlayOption = new GroundOverlayOptions()
.InvokeImage(BitmapDescriptorFactory.FromResource(Resource.Drawable.overlayface2))
.Position(e.Point, 5000f, 5000f);
FromAsset loads the image from the "Assets" subfolder:
var overlayOption = new GroundOverlayOptions()
.InvokeImage(BitmapDescriptorFactory.FromAsset("OverlayFace.png"))
.Position(e.Point, 5000f, 5000f);
FromPath loads the image from an arbitrary path, so you could load an image you downloaded and stored in the app's cache directory, or an image stored on an sdcard, etc...
var overlayOption3 = new GroundOverlayOptions()
.InvokeImage(BitmapDescriptorFactory.FromPath("/mnt/sdcard/Download/OverlayFace.png"))
.Position(e.Point, 5000f, 5000f);
Note: The largest problem people run into is not setting the size of the image correctly, it is in kilometers. not pixels, not miles, etc...
Note: Also for speed, keep your image sizes in the power of 2, otherwise the the map library will have to transform it into a power of 2 image everytime it loads the overlay (memory and performance hit)
Related
I'm migrating an app from Xamarin.Forms to MAUI. Everything is going surprisingly smoothly so far!
There are a small number of images added as SVG resources to the app that are displaying at fixed locations in the app (ie defined in the XAML). The app generates views in a SkiaSharp Canvas from large amounts of downloaded content and that content includes images downloaded from the cloud which are rendering fine (as SKBitmap from the file stream).
A few of the image references in the downloaded content are for the SVG resources that are being included in the app. I have determined a way to get the stream for the resource images in iOS but I cannot find any way to do this in Android.
In iOS:
var imageStream = await FileSystem.OpenAppPackageFileAsync(resourceName + ".png");
This throws a 'FileNotFoundException' when running on Android...
What I've found DOES work in Android:
#if ANDROID
// The only reference I can find that actually loads the image in any way
var drawable = MainApplication.Current.GetDrawable(resourceId);
height = drawable?.IntrinsicHeight ?? 0;
width = drawable?.IntrinsicWidth ?? 0;
#endif
However the Drawable returned (native Android type) has no way that I can find of converting into a Stream and I can't find any way in SkiaSharp libraries to just dump the Drawable onto the SKCanvas?
Diving into the packages generated I can see that the iOS IPA package has the SVGs saved as PNGs in the root of the package (likely why I can load them using OpenAppPackageFileAsync) while in the Android APK the images are split out into /res/drawable-XXXXXXX folders (where XXXXXXX is hdpi / ldrti / xhdpi / etc for the different device resolutions).
I am using following image in VrPanoramaView
When i load it in the view, it looks like this.
But i want it to move the image to left side dynamically before opening the image, like this.
I can move the image with finger, but i want it to set its angle at the loading time.
This is my code.
VrPanoramaView.Options options = new VrPanoramaView.Options();
InputStream inputStream = null;
AssetManager assetManager = getAssets();
inputStream = assetManager.open("test_2"+ ".jpg");
options.inputType = VrPanoramaView.Options.TYPE_MONO;
mVrPanoramaView.loadImageFromBitmap(BitmapFactory.decodeStream(inputStream), options);
mVrPanoramaView.setStereoModeButtonEnabled(false);
mVrPanoramaView.setInfoButtonEnabled(false);
mVrPanoramaView.setPureTouchTracking(true);
mVrPanoramaView.setFullscreenButtonEnabled(true);
I tried mVrPanoramaView.setPivotX(100);, but it does not make any impact. I need to know how to translate image in panorama view with using any hand gesture.
I am using GoogleVrSDK
implementation 'com.google.vr:sdk-base:1.160.0'
implementation 'com.google.vr:sdk-panowidget:1.170.0'
I think, you should switch to Video360:
There are more signs this component is not under development any more.
Set initial angle of VrPanoramaView
There are no plans to add more functionality to the VrView widgets.
But you more complex controls for a 360 media player, consider using
the Video360 sample as a starting point. See #510 for more info.
VR View for Android
Warning: These components were removed in v1.190 of the GVR SDK for
Android. The Video360 sample should be used as a basis for creating
360 photo and video viewers. If you still want to use these widgets,
you will need to use SDK v1.180 or earlier.
I am figuring out the way to load the mbtiles from mapbox using nutiteq SDK. I know how to load the mbtiles offline using this code
// 1. Create tile data source from mbtiles file
MBTilesTileDataSource tileDataSource = new MBTilesTileDataSource("/sdcard/estonia_ntvt.mbtiles");
// 2. Load vector tile styleset
UnsignedCharVector styleBytes = AssetUtils.loadBytes("osmbright.zip");
MBVectorTileStyleSet vectorTileStyleSet = new MBVectorTileStyleSet(styleBytes);
// 3. Create vector tile decoder using the styleset
VectorTileDecoder vectorTileDecoder = new MBVectorTileDecoder(vectorTileStyleSet);
// 4. Create vector tile layer, using previously created data source and decoder
TileLayer vectorTileLayer = new VectorTileLayer(tileDataSource, vectorTileDecoder);
// 5. Add vector tile layer
mapView.getLayers().add(vectorTileLayer);
Is there a way to load it directly from mapbox mbtiles url using Nutiteq SDK?
What do you mean by "mapbox mbtiles url", can you give an example? By mbtiles you mean offline packages?
I can think of following MapBox URLs:
a. For MapBox as online raster source see https://developer.nutiteq.com/guides/raster-tile-sources
b. For MapBox as online vector source you need to define also styling, and it needs a bit more coding:
// load style file from assets. Nutiteq style is quite well compatible with MapBox Streets,
// even though NT vector tiles are a bit different
UnsignedCharVector styleBytes = AssetUtils.loadBytes("nutibright-v2.zip");
if (styleBytes != null){
// Create style set
MBVectorTileStyleSet vectorTileStyleSet = new MBVectorTileStyleSet(styleBytes);
MBVectorTileDecoder vectorTileDecoder = new MBVectorTileDecoder(vectorTileStyleSet);
// Create tile data source and layer for vector tiles
TileDataSource vectorTileDataSource = new HTTPTileDataSource(0, 14, "http://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v5/{zoom}/{x}/{y}.vector.pbf?access_token=pk...YOUR-MAPBOX-KEY");
VectorTileLayer baseLayer = new VectorTileLayer(vectorTileDataSource, vectorTileDecoder);
// add layer to map
mapView.getLayers().add(baseLayer);
}
I am trying to customize my marker with a .png file. It is copied under drawable as gsw.png.
The code (in MapActivity.java) shows the thumbnail of the icon when I place it in the code as R.drawable.gsw However, I get the error, "error cannot find symbol variable gsw". setUpMap() is called to set up the map with all the markers.
I see this has been solved for people by cleaning up, restarting eclipse/Android Studio etc. It does not work for me. Can anyone help?
Code in MapActivity.java
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
mMap.addMarker(new MarkerOptions().position(new LatLng(37.497836, -121.9216775)).title("Title"));
mMap.addMarker(new MarkerOptions()
.position(new LatLng(18.500486, 73.866899))
.title("Pune")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.gsw)));
}
You've written the code correct. If you are using android studio, create 4 folders with names as given below under your project's "YourProjectName\app\src\main\res" folder (Better do it manually on your Project's path, not inside the console):
"drawable-ldpi"
"drawable-mdpi"
"drawable-hdpi"
"drawable-xhdpi"
"drawable-xxhdpi"
Now copy paste your customized marker icon (.png only) to each of those folders(its better if you make different sizes for each folders depending upon the resolution). Save and run your project, It'd definitely work.
If you like to customize your markers more, you can go through these links link1 , link 2
Android won't load PNGs this way -- don't ask me why. One option is to save the PNG as a BMP, but maybe you don't want to do this because you're concerned about cross-compatibility with another application. Whatever your reason, I found this code to be very useful:
Bitmap img = BitmapFactory.decodeResource(getResources(),R.drawable.your_drawable);
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(img);
marker.icon(bitmapDescriptor);
I tried to rename using the refactor option, but it did not work. However, encouraged by ztan's suggestion, I opened the PNG file in Paint and saved it as a bitmap. Then, I deleted the PNG in drawable using the refactor option, and copied the new BMP. It now works fine.
I want to generate a PDF File from a View using the PdfDocument android class introduced in KitKat. I managed to do it, and the file is so far generated ok, ending up having a correct PDF. The only problem is the file is huge, 12Mb for just one page. Is there a way to reduce the File size?
The code I am using to generate the PDF is:
public static File generateDocument(Activity activity, String fileName, ViewGroup container) throws IOException{
File f = new File(activity.getExternalFilesDir(null), fileName);
PdfDocument document = new PdfDocument();
try{
for(int i=0;i<container.getChildCount();i++){
View v = container.getChildAt(i);
PdfDocument.PageInfo.Builder pageBuilder = new PdfDocument.PageInfo.Builder(v.getWidth(), v.getHeight(), i);
Page page = document.startPage(pageBuilder.create());
v.draw(page.getCanvas());
document.finishPage(page);
}
document.writeTo(new FileOutputStream(f));
} finally{
if(document!=null){
document.close();
}
}
return f;
}
In case anyone is still looking for a solution... I was working on a project to generate PDF from images and not satisfied with the file size generated by both Android's PdfDocument and 3rd party AndroidPdfWriter APW.
After some trials I ended up using Apache's PdfBox, which gave me a PDF file (A4 size with a single 1960x1080 image) for around 80K, while it's usually 2~3M with PdfDocument or AndroidPdfWriter.
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
// Define a content stream for adding to the PDF
contentStream = new PDPageContentStream(document, page);
Bitmap bimap = _get_your_bitmap_();
// Here you have great control of the compression rate and DPI on your image.
// Update 2017/11/22: The DPI param actually is useless as of current version v1.8.9.1 if you take a look into the source code. Compression rate is enough to achieve a much smaller file size.
PDImageXObject ximage = JPEGFactory.createFromImage(document, bitmap, 0.75, 72);
// You may want to call PDPage.getCropBox() in order to place your image
// somewhere inside this page rect with (x, y) and (width, height).
contentStream.drawImage(ximage, 0, 0);
// Make sure that the content stream is closed:
contentStream.close();
document.save(_your_file_path_);
document.close();
=====
btw. I guess the reason why they generate a huge file size is because they don't compress the image data while writing to PDF file. If you take a look into AndroidPdfWriter's XObjectImage.deflateImageData() method you will see it's using java.util.zip.Deflater.NO_COMPRESSION option to write the image data which is kind of horrible if you've got a picture with size 1960x1080. If you change the options to e.g. Deflater.BEST_COMPRESSION you get much smaller file size however it takes up to 3-4 seconds for me to handle one single page which is not acceptable.
There are a few main things that increases the size of a PDF file:
hi-resolution pictures (where lo-res would suffice)
embedded fonts (where content would still be readable "good enough" without them)
PDF content not required any more for the current version/view (older version of certain objects)
embedded ICC profiles
embedded third-party files (using the PDF as a container)
embedded job tickets (for printing)
embedded Javascript
and a few more
Try using iText. Following links give a basice idea for iText in android.
http://technotransit.wordpress.com/2011/06/17/using-itext-in-android/
http://www.mysamplecode.com/2013/05/android-itext-pdf-bluetooth-printer.html
https://stackoverflow.com/a/21025162/3110609
Using PDFDocument, be sure to downscale your images prior to drawing them in the canvas.
When drawing to the screen, this is enough to scale the bitmap :
canvas.drawBitmap(bmp, src, dst, paint);
However, when using the canvas from PdfDocument.Page.getCanvas, this canvas will not downscale the bitmap, it will just squeeze it into a smaller zone. Instead you should do something like this:
// Scale bitmap : filter = false since we are always downSampling
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp, dstWidth, dstHeight,
false); // filter=false if downscaling, true if upscaling
canvas.drawBitmap(scaledBitmap, null, dst, paint);
scaledBitmap.recycle();
This is embedded in Android so it is much easier than using a third-party library. (The above was tested on a Marshmallow platform)
This seems to just be a bug in PdfDocument. The PDF file I created with PdfDocument was 5.6 megabytes. The same document generated through the iOS equivalent was 500K. If I take the Android PDF and run it through Adobe Acrobat's pdf optimization, without compressing any images, the 5.6MB file becomes 350K. They look identical, and I applied no compression in Adobe Acrobat.
In the actual PDF code, the Android image object dictionary is this
<</Type /XObject
/Subtype /Image
/Width 1224
/Height 1584
/ColorSpace /DeviceRGB
/BitsPerComponent 8
/Length 5816448
>>
The PDF from iOS has this dict
<< /Length 8 0 R
/Type /XObject
/Subtype /Image
/Width 1224
/Height 1584
/ColorSpace /DeviceRGB
/SMask 9 0 R
/BitsPerComponent 8
/Filter /FlateDecode >>
I think the problem is the lack of the FlateDecode filter in the Android version. When I run it through the Adobe Acrobat PDF optimizer, it gets the FlateDecode filter.