Vuforia - Unity low image quality - c#

I am using Vuforia with Unity for an Android AR app. I made it to take a screenshot of a specific area of the screen with the click of a button. It reads pixels in that specific area when the button is clicked.
The problem is, the resulting image is blurry/ low resolution. How can I increase the quality of the image?
I tried changing "Camera Device Mode" to "MODE_OPTIMIZE_QUALITY" and increasing "Number Divisions" in "Video Background" setting. But nothing happens. I also tried removing ARCore and changing "ARCore Requirement" to "DONT_USE" mode.
This is the code to take a snapshot :
yield return new WaitForEndOfFrame();
//Get the corners of RectTransform rect and store it in a array vector
Vector3[] corners = new Vector3[4];
_objToScreenshot.GetWorldCorners(corners);
//Remove 100 and you will get error
int width = ((int)corners[3].x - (int)corners[0].x) - 100;
int height = (int)corners[1].y - (int)corners[0].y;
var startX = corners[0].x;
var startY = corners[0].y;
//Make a temporary texture and read pixels from it
Texture2D ss = new Texture2D(width, height, TextureFormat.RGB24, false);
ss.ReadPixels(new Rect(startX, startY, width, height), 0, 0);
ss.Apply();
//Save the screenshot to disk
byte[] byteArray = ss.EncodeToPNG();
string savePath = Application.persistentDataPath + "/" + System.DateTime.Now.ToString("HH-mm-ss dd,MM, yyyy") + ".png";
System.IO.File.WriteAllBytes(savePath, byteArray);
//Debug.Log("Screenshot Path : " + savePath);
// Destroy texture to avoid memory leaks
Destroy(ss);

Related

Texture2D to get Rect Transform properties of the Image

If any of you had dealt with the same problem could you please tell me the solution.
User can upload his own image from phone gallery to the UI Image, then he can move it, scale it, rotate it, mirror it. After such manipulations he can save the Texture2D of this Image to the persistentDataPath with the following code. But the problem is that no matter which rotation, position or scale properties the UI Image has, Texture2D will still remain default which is 0pos, 0rotation and scale 1 (which actually has logic cause the texture is the same as I only changed the rect transform of the image.
public void SaveClick()
{
CropSprite();
SaveSprite();
}
private Texture2D output;
public void CropSprite()
{
Texture2D MaskTexture = MaskImage.sprite.texture;
//for this part MaskImage is the parent of the Image which is used to actually mask Image with which user is manipulating edits
//attached the image for better understanding what is mask and what is editable area
Texture2D originalTextureTexture = TextureMarble.sprite.texture;
Texture2D TextureTexture = Resize(originalTextureTexture,250,250);
//I rescale editable texture to the size of the mask one, otherwise big size images will be saved incorrectly
output = new Texture2D(TextureTexture.width,TextureTexture.height);
for (int i = 0; i < TextureTexture.width; i++)
{
for (int j = 0; j < TextureTexture.height; j++)
{
if (MaskTexture.GetPixel(i, j).a != 0)
output.SetPixel(i, j, TextureTexture.GetPixel(i, j));
else
output.SetPixel(i, j, new Color(1f, 1f, 1f, 0f));
}
}
//save only the part of editable texture which is overlapping mask image
output.Apply();
}
Texture2D Resize(Texture2D texture2D,int targetX,int targetY)
{
RenderTexture rt=new RenderTexture(targetX, targetY,24);
RenderTexture.active = rt;
Graphics.Blit(texture2D,rt);
Texture2D result=new Texture2D(targetX,targetY);
result.ReadPixels(new Rect(0,0,targetX,targetY),0,0);
result.Apply();
return result;
}
public void SaveSprite()
{
byte[] bytesToSave = output.EncodeToPNG();
File.WriteAllBytes(Application.persistentDataPath + "/yourTexture1.png",bytesToSave);
}
not necessary but for those of you who didn't understand what is mask in my case
So how to save Texture2D with the rect transform properties of the Image?

How to get Username and User Profile Picture from Facebook API in unity engine?

I want to implement a user login in my unity game but I am unable to get the user profile picture from their Facebook id. The username is showing but not the profile picture. It is showing blank. I am also not getting any errors!
The sprite of the image is changing but not displaying on the screen.
Here is the code:
void DealWithFbMenus(bool isLoggedIn)
{
if (isLoggedIn)
{
FB.API("/me?fields=first_name", HttpMethod.GET, DisplayUsername);
FB.API("/me/picture?type=med", HttpMethod.GET, DisplayProfilePic);
}
}
void DisplayUsername(IResult result)
{
if (result.Error == null)
{
string name = "" + result.ResultDictionary["first_name"];
FB_userName.text = name;
Debug.Log("" + name);
}
else
{
Debug.Log(result.Error);
}
}
void DisplayProfilePic(IGraphResult result)
{
if (result.Error == null)
{
Debug.Log("Profile Pic");
FB_userDp.sprite = Sprite.Create(result.Texture, new Rect(0, 0, 128, 128), new Vector2());
}
else
{
Debug.Log(result.Error);
}
}
Sprite.Create takes
rect Rectangular section of the texture to use for the sprite.
I suspect that your hard coded 128 x 128 pixels is just a section and not the entire texture depending on the actual image dimensions of the picture.
And it also takes
pivot Sprite's pivot point relative to its graphic rectangle.
You are using new Vector2() which means the bottom left corner. In general for profile pictures I would rather assume that the pivot should be the center of the texture and use
Vector2.one * 0.5f
or
new Vector2(0.5f, 0.5f)
So asuming the download itself actually works and as you say you don't get errors you would probbaly rather use e.g.
FB_userDp.sprite = Sprite.Create(result.Texture, new Rect(0, 0, result.Texture.width, result.Texture.height), Vector2.one * 0.5f);
or if your goal is to use a square section no matter the dimenions you could use
var size = Mathf.Min(result.Texture.width, result.Texture.height);
FB_userDp.sprite = Sprite.Create(result.Texture, new Rect(0, 0, size, size), Vector2.one * 0.5f);

Capture everything inside a rect in unity

I have a rect, which has inside of it a portion of my UI, I want to take a 'screenshot' of everything inside of that rect and put it into a .jpeg file.
I have absolutely no idea how I can do this, and if it's even possible. Unfortunately, I couldn't find anything on the internet.
What you need to do is use a RenderTexture
Create a RenderTexture Unity Object in the editor
Create a Camera that sees exactly what you want in your screenshot.
Cameras in Unity have an option called Target Texture. Put your RenderTexture in this field. The result is that the camera will render in this texture instead of on the screen. See the Manual for detailed examples.
Make a script that has access to your RenderTexture Object. This script create a Texture2D using Texture2D.ReadPixels. This allows to create a Texture2D object from the texture.
Use Texture2D.EncodeToJpg to save your Texture2D in a file
You need this:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class TakeScreenshotAndSave : MonoBehaviour
{
//Object To Screenshot
[SerializeField] private RectTransform _objToScreenshot;
//Assign the button to take screenshot on clicking
[SerializeField] private Button _takeScreenshotButton;
void Start()
{
_takeScreenshotButton.onClick.AddListener(OnClickTakeScreenshotAndSaveButton);
}
private void OnClickTakeScreenshotAndSaveButton()
{
StartCoroutine(TakeSnapShotAndSave());
}
//Using a Coroutine instead of normal method
public IEnumerator TakeSnapShotAndSave()
{
//Code will throw error at runtime if this is removed
yield return new WaitForEndOfFrame();
//Get the corners of RectTransform rect and store it in a array vector
Vector3[] corners = new Vector3[4];
_objToScreenshot.GetWorldCorners(corners);
//Remove 100 and you will get error
int width = ((int)corners[3].x - (int)corners[0].x) - 100;
int height = (int)corners[1].y - (int)corners[0].y;
var startX = corners[0].x;
var startY = corners[0].y;
//Make a temporary texture and read pixels from it
Texture2D ss = new Texture2D(width, height, TextureFormat.RGB24, false);
ss.ReadPixels(new Rect(startX, startY, width, height), 0, 0);
ss.Apply();
Debug.Log("Start X : " + startX + " Start Y : " + startY);
Debug.Log("Screen Width : " + Screen.width + " Screen Height : " +
Screen.height);
Debug.Log("Texture Width : " + width + " Texture Height : " + height);
//Save the screenshot to disk
byte[] byteArray = ss.EncodeToPNG();
string savePath = Application.persistentDataPath + "/ScreenshotSave.png";
System.IO.File.WriteAllBytes(savePath, byteArray);
Debug.Log("Screenshot Path : " + savePath);
// Destroy texture to avoid memory leaks
Destroy(ss);
}
}

WriteableBitmap.Pixels in Windows Phone 8.1

I am writing a Windows Phone 8.1 (WINRT) App. I am using fileopenpicker to choose a picture from gallery and then i display it in my app. But i want that user can crop this image before getting displayed on app.
In windows phone 8, we used Photochooser task having width property and cropping options automatically used to come.
Now I am trying to use this :
Windows Phone 8.0: Image Crop With Rectangle
But there is no WriteableBitmap.Pixels in Windows Phone 8.1. What to use instead of WriteableBitmap.Pixels?
// Create a new WriteableBitmap. The size of the bitmap is the size of the cropping rectangle
// drawn by the user, multiplied by the image size ratio.
WB_CroppedImage = new WriteableBitmap((int)(widthRatio * Math.Abs(Point2.X - Point1.X)), (int)(heightRatio * Math.Abs(Point2.Y - Point1.Y)));
// Calculate the offset of the cropped image. This is the distance, in pixels, to the top left corner
// of the cropping rectangle, multiplied by the image size ratio.
int xoffset = (int)(((Point1.X < Point2.X) ? Point1.X : Point2.X) * widthRatio);
int yoffset = (int)(((Point1.Y < Point2.Y) ? Point1.Y : Point2.X) * heightRatio);
// Copy the pixels from the targeted region of the source image into the target image,
// using the calculated offset
if (WB_CroppedImage.Pixels.Length > 0)
{
for (int i = 0; i < WB_CroppedImage.Pixels.Length; i++)
{
int x = (int)((i % WB_CroppedImage.PixelWidth) + xoffset);
int y = (int)((i / WB_CroppedImage.PixelWidth) + yoffset);
WB_CroppedImage.Pixels[i] = WB_CapturedImage.Pixels[y * WB_CapturedImage.PixelWidth + x];
}
// Set the source of the image control to the new cropped bitmap
FinalCroppedImage.Source = WB_CroppedImage;
}
else
{
FinalCroppedImage.Source = null;
}
You should take a look at BitmapEncoder and BitmapDecoder classes.
Also you probably will be able to use BitmapBounds to crop your image - set 'X' and 'Y' along with 'Width' and 'Height'.
I think the code may look like this (but I've not tested it):
StorageFile destination; // your destination file
using (var sourceStream = await sourceFile.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder bmpDecoder = await BitmapDecoder.CreateAsync(sourceStream);
// here you scale your image if needed and crop by setting X, Y, Width and Height
BitmapTransform bmpTransform = new BitmapTransform() { ScaledHeight = scaledHeight, ScaledWidth = scaledWidth, InterpolationMode = BitmapInterpolationMode.Cubic, Bounds = new BitmapBounds { X = topLeftX, Y = topLeftY Width = desiredSizeW, Height = desiredSizeH } };
PixelDataProvider pixelData = await bmpDecoder.GetPixelDataAsync(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, bmpTransform, ExifOrientationMode.RespectExifOrientation, ColorManagementMode.DoNotColorManage);
using (var destFileStream = await destination.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder bmpEncoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, destFileStream);
// here you need to set height and width - take from above
bmpEncoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, desiredSizeW, desiredSizeH, 300, 300, pixelData.DetachPixelData());
await bmpEncoder.FlushAsync();
}
}
Of course you don't need to save the edited picture to StorageFile - I've used it as an example, you can write to stream and then set your image source.

MonoTouch: Memory leak when drawing PDF on a custom graphics context

I have an app that's basically a fancy PDF reader. I download a PDF from the internet and generate thumbnails for that PDF. However, it seems that when I generate these thumbnails a lot of memory is being allocated (checked using Instruments), sometimes parts of this is collected by the GC but in the end, my app gives up. I've had memory usage of up to 38Mb when generating thumbnails for a single PDF (100x100 thumbs, ~60 pages).
I generate one thumbnail at a time, store it and then repeat the process, so under any circumstance there should only be one thumbnail in memory (while generating them, at least). My code for generating thumbnails looks like this:
public UIImage GetPageThumbnail(int pageNumber, SizeF size)
{
//If using retina display, make sure to scale-up the thumbnail as well.
size.Width = size.Width * UIScreen.MainScreen.Scale;
size.Height = size.Height * UIScreen.MainScreen.Scale;
UIGraphics.BeginImageContext(size);
CGContext tempContext = UIGraphics.GetCurrentContext();
CGPDFPage page = Document.GetPage(pageNumber);
RectangleF drawArea = new RectangleF(new PointF(0f, 0f), size);
CGAffineTransform transform = page.GetDrawingTransform( CGPDFBox.Crop, drawArea, 180, true); //fit PDF to context
transform.xx = -transform.xx; // }
transform.x0 = 0; // }flip horizontally
//Console.WriteLine("XX: " + transform.xx + ", YX:" + transform.yx + ", XY:" + transform.xy + ", YY:" + transform.yy + ", X0:" + transform.x0 + ", Y0:" + transform.y0);
tempContext.ConcatCTM(transform);
tempContext.DrawPDFPage (page);
UIImage returnImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return returnImage;
}
I've tried explicitly disposing the context and PDF page, but that had no effect (actually it seemed worse, but take that with a pinch of salt).
I've seen some posts about memory leakage with MonoTouch and PDF (basically this post), but that's pretty old. I'm using the newest MonoTouch (5.0.2).
Not sure where the problem in your code is, but here's my code for generating thumbs of PDF pages. It is working flawlessly. Maybe it helps you. I think your issue might be what you are doing with the returned image when you're don.
public static UIImageView GetLowResPagePreview (CGPDFPage oPdfPage, RectangleF oTargetRect)
{
RectangleF oOriginalPdfPageRect = oPdfPage.GetBoxRect (CGPDFBox.Media);
RectangleF oPdfPageRect = PdfViewerHelpers.RotateRectangle( oPdfPage.GetBoxRect (CGPDFBox.Media), oPdfPage.RotationAngle);
// Create a low res image representation of the PDF page to display before the TiledPDFView
// renders its content.
int iWidth = Convert.ToInt32 ( oPdfPageRect.Size.Width );
int iHeight = Convert.ToInt32 ( oPdfPageRect.Size.Height );
CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB();
CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedLast);
// First fill the background with white.
oContext.SetFillColor (1.0f, 1.0f, 1.0f, 1.0f);
oContext.FillRect (oOriginalPdfPageRect);
// Scale the context so that the PDF page is rendered
// at the correct size for the zoom level.
oContext.ConcatCTM ( oPdfPage.GetDrawingTransform ( CGPDFBox.Media, oPdfPageRect, 0, true ) );
oContext.DrawPDFPage (oPdfPage);
CGImage oImage = oContext.ToImage();
UIImage oBackgroundImage = UIImage.FromImage( oImage );
oContext.Dispose();
oImage.Dispose ();
oColorSpace.Dispose ();
UIImageView oBackgroundImageView = new UIImageView (oBackgroundImage);
oBackgroundImageView.Frame = new RectangleF (new PointF (0, 0), oPdfPageRect.Size);
oBackgroundImageView.ContentMode = UIViewContentMode.ScaleToFill;
oBackgroundImageView.UserInteractionEnabled = false;
oBackgroundImageView.AutoresizingMask = UIViewAutoresizing.None;
return oBackgroundImageView;
}

Categories

Resources