I have a static image of size 1024*768 with some logo on one side,
i want to have some text added to that image eg: Page 1, (on another side)
i got some code from
public override void ViewDidLoad ()
{
try {
base.ViewDidLoad ();
UIImage ii = new UIImage (Path.Combine (NSBundle.MainBundle.BundleUrl.ToString ().Replace ("%20", " ").Replace ("file://", ""), "images2.png"));
RectangleF wholeImageRect = new RectangleF (0, 0, ii.CGImage.Width, ii.CGImage.Height);
imageView = new UIImageView (wholeImageRect);
this.View.AddSubview (imageView);
imageView.Image = DrawVerticalText ("Trail Text", 100, 100);
Console.Write ("Switch to Simulator now to see ");
Console.WriteLine ("some stupid graphics tricks");
} catch (Exception ex) {
}
}
public static UIImage DrawVerticalText (string text, int width, int height)
{
try {
float centerX = width / 2;
float centerY = height / 2;
//Create the graphics context
byte[] mybyteArray;
CGImage tt = null;
UIImage ii = new UIImage (Path.Combine (NSBundle.MainBundle.BundleUrl.ToString ().Replace ("%20", " ").Replace ("file://", ""), "images2.png"));
using (NSData imagedata = ii.AsPNG ()) {
mybyteArray = new byte[imagedata.Length];
System.Runtime.InteropServices.Marshal.Copy (imagedata.Bytes, mybyteArray, 0, Convert.ToInt32 (imagedata.Length));
using (CGBitmapContext ctx = new CGBitmapContext (mybyteArray, width, height, 8, 4 * width, CGColorSpace.CreateDeviceRGB (), CGImageAlphaInfo.PremultipliedFirst)) {
//Set the font
ctx.SelectFont ("Arial", 16f, CGTextEncoding.MacRoman);
//Measure the text's width - This involves drawing an invisible string to calculate the X position difference
float start, end, textWidth;
//Get the texts current position
start = ctx.TextPosition.X;
//Set the drawing mode to invisible
ctx.SetTextDrawingMode (CGTextDrawingMode.Invisible);
//Draw the text at the current position
ctx.ShowText (text);
//Get the end position
end = ctx.TextPosition.X;
//Subtract start from end to get the text's width
textWidth = end - start;
//Set the fill color to blue
ctx.SetRGBFillColor (0f, 0f, 1f, 1f);
//Set the drawing mode back to something that will actually draw Fill for example
ctx.SetTextDrawingMode (CGTextDrawingMode.Fill);
//Set the text rotation to 90 degrees - Vertical from bottom to top.
ctx.TextMatrix = CGAffineTransform.MakeRotation ((float)(360 * 0.01745329f));
//Draw the text at the center of the image.
ctx.ShowTextAtPoint (2, 2, text);
tt = ctx.ToImage ();
}
}
//Return the image
return UIImage.FromImage (tt);
} catch (Exception ex) {
return new UIImage (Path.Combine (NSBundle.MainBundle.BundleUrl.ToString ().Replace ("%20", " ").Replace ("file://", ""), "images2.png"));
}
}
the output i am getting as following
As you can see it gets completely stretched in terms of width, i need this to be solved Any suggestions ???
At the same time the original image has nothing in the upper part, where as after processing it shows multi coloured layer, how to fix that ??
Why do you not draw your text directly to the image? Perhaps you can try this:
private static UIImage PutTextOnImage(UIImage image, string text, float x, float y)
{
UIGraphics.BeginImageContext(new CGSize(image.Size.Width, image.Size.Height));
using (CGContext context = UIGraphics.GetCurrentContext())
{
// Copy original image
var rect = new CGRect(0, 0, image.Size.Width, image.Size.Height);
context.SetFillColor(UIColor.Black.CGColor);
image.Draw(rect);
// Use ScaleCTM to correct upside-down imaging
context.ScaleCTM(1f, -1f);
// Set the fill color for the text
context.SetTextDrawingMode(CGTextDrawingMode.Fill);
context.SetFillColor(UIColor.FromRGB(255, 0, 0).CGColor);
// Draw the text with textSize
var textSize = 20f;
context.SelectFont("Arial", textSize, CGTextEncoding.MacRoman);
context.ShowTextAtPoint(x, y, text);
}
// Get the resulting image from context
var resultImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return resultImage;
}
The above method draws your text at coords x, y with given color and textsize. If you want it vertically you need to rotate the text with rotateCTM. keep in mind rotateCTM uses radius.
Add this to your using Context block (before DrawTextAtPoint):
var angle = 90;
var radius = 90 * (nfloat)Math.PI / 180;
context.RotateCTM(radius);
Related
I'm using the Vision framework to detect rectangular documents in a captured photo. Detecting and drawing a path around the document is working perfectly. I then want to crop the image to be only the detected document. I'm successfully cropping the image, but it seems the coordinates don't line up and the cropped image is only part of the detected document and the rest is just the desk behind the document. I'm using the following cropping code:
private UIImage CropImage(UIImage image, CGRect rect, float scale)
{
var drawRect = new CGRect(rect.X, rect.Y, rect.Size.Width, rect.Size.Height);
using (var cgImage = image.CGImage.WithImageInRect(drawRect))
{
var croppedImage = UIImage.FromImage(cgImage);
return croppedImage;
};
}
Using the following parameters:
image is the same UIImage that i successfully drew the rectangle path on.
rect is the VNRectangleObservation.BoundingBox. This is normalized so i'm scaling it using the image.size. it's the same scaling i do when drawing the rectangle path.
scale is 1f, but i'm currently ignoring this.
The cropped image generally seems to be the right size, but it is shifted up and to the left which cuts off the lower and right side of the document. Any help would be appreciated.
for anyone else that finds this, the issue seemed to be CGImage rotating when cropping the image which caused the VNRectangleObservation to not line up anymore. I used this article, Tracking and Altering Images, to get a working solution using CIFilter. Cropping code follows:
var ciFilter = CIFilter.FromName("CIPerspectiveCorrection");
if (ciFilter == null) continue;
var width = inputImage.Extent.Width;
var height = inputImage.Extent.Height;
var topLeft = new CGPoint(observation.TopLeft.X * width, observation.TopLeft.Y * height);
var topRight = new CGPoint(observation.TopRight.X * width, observation.TopRight.Y * height);
var bottomLeft = new CGPoint(observation.BottomLeft.X * width, observation.BottomLeft.Y * height);
var bottomRight = new CGPoint(observation.BottomRight.X * width, observation.BottomRight.Y * height);
ciFilter.SetValueForKey(new CIVector(topLeft), new NSString("inputTopLeft"));
ciFilter.SetValueForKey(new CIVector(topRight), new NSString("inputTopRight"));
ciFilter.SetValueForKey(new CIVector(bottomLeft), new NSString("inputBottomLeft"));
ciFilter.SetValueForKey(new CIVector(bottomRight), new NSString("inputBottomRight"));
var ciImage = inputImage.CreateByApplyingOrientation(CGImagePropertyOrientation.Up);
ciFilter.SetValueForKey(ciImage, CIFilterInputKey.Image);
var outputImage = ciFilter.OutputImage;
var uiImage = new UIImage(outputImage);
imageList.Add(uiImage);
imageList is a List<UImage> since i'm handling multiple detected rectangles.
observation is a single observation of type VNRectangleObservation.
The cropped image generally seems to be the right size, but it is shifted up and to the left which cuts off the lower and right side of the document.
From Apple documentation CGImageCreateWithImageInRect , there is a discussion about the cropped size .
CGImageCreateWithImageInRect performs the following tasks to create the subimage:
It calls the CGRectIntegral function to adjust the rect parameter to integral bounds.
It intersects the rect with a rectangle whose origin is (0,0) and size is equal to the size of the image specified by the image parameter.
It reads the pixels within the resulting rectangle, treating the first pixel within as the origin of the subimage.
If W and H are the width and height of image, respectively, then the point (0,0) corresponds to the first pixel of the image data. The point (W–1, 0) is the last pixel of the first row of the image data, while (0, H–1) is the first pixel of the last row of the image data and (W–1, H–1) is the last pixel of the last row of the image data.
Then you can check in your local project with an image (size is : 1920 * 1080) as follow:
UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 0, 1920, 1080), 1);
View.AddSubview(imageView);
The CropImage Method :
private UIImage CropImage(UIImage image, CGRect rect, float scale)
{
var drawRect = new CGRect(rect.X, rect.Y, rect.Size.Width, rect.Size.Height);
using (var cgImage = image.CGImage.WithImageInRect(drawRect))
{
if(null != cgImage)
{
var croppedImage = UIImage.FromImage(cgImage);
return croppedImage;
}
else
{
return image;
}
};
}
This will show the Original Size of Image :
Now you can modify the cropped size as follow :
UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 0, 1920, 100), 1);
View.AddSubview(imageView);
Here I set x = 0 , y = 0 , that means from (0,0) to start , and width is 1920 ,height is 100 . I just crop the height of the original Image . The effect as follow :
Then if you modify the x/y ,the cropped image will move to other area to crop .As follow:
UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 100, 1920, 100), 1);
View.AddSubview(imageView);
Then you will see it's different with the second effect :
So when cropping an image , you should understand the drawRect of image.CGImage.WithImageInRect(drawRect) clearly .
Note from doc :
Be sure to specify the subrectangle's coordinates relative to the original image's full size, even if the UIImageView shows only a scaled version.
I have an UIImage I would like to draw text on image. I would like it to look like this:
I am drawing text with this code:
private static UIImage DrawText(UIImage uiImage, string sText, UIColor textColor, int iFontSize)
{
nfloat fWidth = uiImage.Size.Width;
nfloat fHeight = uiImage.Size.Height;
using (CGBitmapContext ctx = new CGBitmapContext(IntPtr.Zero, (nint)fWidth, (nint)fHeight, 8, 4 * (nint)fWidth, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedFirst))
{
ctx.DrawImage(new CGRect(0, 0, (double)fWidth, (double)fHeight), uiImage.CGImage);
ctx.SelectFont("Helvetica", iFontSize, CGTextEncoding.MacRoman);
nfloat fRed, fGreen, fBlue, fAlpha;
textColor.GetRGBA(out fRed, out fGreen, out fBlue, out fAlpha);
ctx.SetFillColor(fRed, fGreen, fBlue, fAlpha);
ctx.SetTextDrawingMode(CGTextDrawingMode.Fill);
ctx.ShowTextAtPoint(fWidth / 4, fHeight / 10, sText);
return UIImage.FromImage(ctx.ToImage());
}
}
It draws text correctly. Problem is it doesn't have grey rectangle around it that fills space with grey. How can I accomplish this?
So I'm trying to figure out how to move UIImages that are drawn inside a CGRect up a cell on the screen using animateWithDuration, but I'm having trouble visualizing where to write the code as well as how to write it for a UIImage. I have an array of CGRects with content the UIImage drawn inside of it, and I want to move all of the images at the same time. Once they get to the top most cell, I want them to then appear in the bottom cell and start again. Here is a picture to get a better idea of what I'm talking about:
DragMeToHell Screenshot
And here's my drawRect code for the UIView and UIImages:
override func drawRect(rect: CGRect) {
print( "drawRect:" )
let context = UIGraphicsGetCurrentContext()! // obtain graphics context
// CGContextScaleCTM( context, 0.5, 0.5 ) // shrink into upper left quadrant
let bounds = self.bounds // get view's location and size
let w = CGRectGetWidth( bounds ) // w = width of view (in points)
let h = CGRectGetHeight( bounds ) // h = height of view (in points)
self.dw = w/10.0 // dw = width of cell (in points)
self.dh = h/10.0 // dh = height of cell (in points)
print( "view (width,height) = (\(w),\(h))" )
print( "cell (width,height) = (\(self.dw),\(self.dh))" )
// draw lines to form a 10x10 cell grid
CGContextBeginPath( context ) // begin collecting drawing operations
for i in 1..<10 {
// draw horizontal grid line
let iF = CGFloat(i)
CGContextMoveToPoint( context, 0, iF*(self.dh) )
CGContextAddLineToPoint( context, w, iF*self.dh )
}
for i in 1..<10 {
// draw vertical grid line
let iFlt = CGFloat(i)
CGContextMoveToPoint( context, iFlt*self.dw, 0 )
CGContextAddLineToPoint( context, iFlt*self.dw, h )
}
UIColor.grayColor().setStroke() // use gray as stroke color
CGContextDrawPath( context, CGPathDrawingMode.Stroke ) // execute collected drawing ops
// establish bounding box for image
let tl = self.inMotion ? CGPointMake( self.x, self.y )
: CGPointMake( CGFloat(row)*self.dw, CGFloat(col)*self.dh )
let imageRect = CGRectMake(tl.x, tl.y, self.dw, self.dh)
// place images in random cells
//cellCoordinates = self.generateCoordinates()
for xy in cellCoordinates {
let randomImageRect = CGRectMake(xy.x, xy.y, self.dw, self.dh)
let lavaImage : UIImage? = UIImage(named: "lava.png")
lavaImage!.drawInRect(randomImageRect)
imageCells.append(randomImageRect)
}
// place appropriate image where dragging stopped [EDITED]
var img : UIImage?
if ( self.col == 9 ) {
img = UIImage(named:"otto.png")
} else {
img = UIImage(named:"angel.png")
}
img!.drawInRect(imageRect)
// check for image intersection
for tempImageRect in imageCells {
if (CGRectIntersectsRect(imageRect, tempImageRect)) {
img = UIImage(named:"devil.png")
img!.drawInRect(imageRect)
self.backgroundColor = UIColor.redColor()
}
}
}
I am using PdfAnnotation.SetContents to set the value of an annotation.If the annotation is of type FreeText, only then this method correctly works and the value gets displayed on the PDF (using PDF Reader).If the type is Widget, the value gets set as content in pdf dictionary but does not get displayed.Is there a way i could set the value of a widget?
I found the solution, In order for the content to get displayed, an Appearance ("AP") Dictionary has to be set.
This could be used for that:
void PdfField::CreateFieldAppearance(PdfMemDocument *memDoc, const PdfString &value)
{
if( !m_pWidget->HasAppearanceStream() )
{
PdfRect pageRect;
PdfPainter painter;
PoDoFo::PdfRect rect = this->GetWidgetAnnotation()->GetRect();
unsigned int width = rect.GetWidth();
unsigned int height = rect.GetHeight();
PdfRect pdfRect(0, 0, width, height);
PdfXObject xObj(pdfRect, memDoc);
painter.SetPage(&xObj);
painter.SetClipRect(pdfRect);
painter.Save();
painter.SetColor(221.0/255.0, 228.0/255.0, 1.0);
painter.FillRect(0, 0, width, height);
painter.Restore();
// make rotation
painter.Save();
/***********************************************************************************/
// Rotation Logic
double angle = this->GetPage()->GetRotation();
if (angle) {
double radAngle = angle * M_PI / 180;
int cosA = (int)cos(radAngle);
int sinA = (int)sin(radAngle);
double translateY = rect.GetWidth(); // The View goes out of the bound, sits on top
painter.SetTransformationMatrix(cosA, sinA, -sinA, cosA, translateY, 0);
}
/***********************************************************************************/
PdfFont *font = memDoc->CreateFont("Helvetica", true, false);
font->SetFontSize(15);
// Do the drawing
painter.SetFont(font);
painter.BeginText(10, 5);
painter.SetStrokeWidth(20);
painter.AddText(value);
painter.EndText();
painter.FinishPage();
// This is very important. Not only does it disable the editing.
// Also it does correct the appearance issue on Adobe Readers.
this->SetReadOnly(true);
// The Stream Object has to be saved to the annotation
PoDoFo::PdfDictionary dict;
dict.AddKey( "N", xObj.GetObject()->Reference() );
this->GetFieldObject()->GetDictionary().AddKey( "AP", dict );
}
}
I'm developing in Xamarin and would like to draw a simple circle with the text "CIRCLE" inside it and display that image in a UIImageView. The problem is that the circle and text appear very blurry. I've read a bit about subpixels but I don't think that's my problem.
Here's the blurry image and code, hoping someone has some ideas :)
UIGraphics.BeginImageContext (new SizeF(150,150));
var context = UIGraphics.GetCurrentContext ();
var content = "CIRCLE";
var font = UIFont.SystemFontOfSize (16);
const float width = 150;
const float height = 150;
context.SetFillColorWithColor (UIColor.Red.CGColor);
context.FillEllipseInRect (new RectangleF (0, 0, width, height));
var contentString = new NSString (content);
var contentSize = contentString.StringSize (font);
var rect = new RectangleF (0, ((height - contentSize.Height) / 2) + 0, width, contentSize.Height);
context.SetFillColorWithColor (UIColor.White.CGColor);
new NSString (content).DrawString (rect, font, UILineBreakMode.WordWrap, UITextAlignment.Center);
var image = UIGraphics.GetImageFromCurrentImageContext ();
imageView.Image = image;
The reason why it's blurry is because it was resized. That bitmap is not 150x150 (like the context you created), it's 333x317 pixels.
It could be because imageView is scaling it's image (there's no source code) or because of pixel doubling (for retina displays). In the later case what you really want to use is:
UIGraphics.BeginImageContextWithOptions (size, false, 0);
which will (using 0) automagically use the right scaling factor for retina (or not) display - and look crisp (and not oversized) on all types of devices.