I'm working on an iPad app with xcode 4.0.2 and im having trouble getting my fonts to look sharp and clear when i set the font size below 15px. It appears that there is some level of font smoothing being applied to the font and it doesn't look good at all. I've tried several different fonts and i get the same effect. Is there a way i can turn this off?
Make sure you are actually drawing on non fractioned coordinates. If for example you start drawing on X = 0.5 and Y = 0.0, your text will look lousy. Same goes for vertical coordinates. In case your coordinates are resulting from a calculation, simply add a cast towards an integer like this:
CGPoint startDrawingAt = CGPointMake((int)x, (int)y);
Or use proper rounding:
CGPoint startDrawingAt = CGPointMake(roundf(x), roundf(y));
Related
I'm building a universal app using Sprite Kit, Objective C. This app is aimed for OS X as well as iOS platforms.
A problem that many people will have encountered is the positioning of objects on the screen as different devices have different proportions. I have read up many answers/posts online to solve this issue and have come to the conclusion that there seem to be only a few options available to the programmer when it comes to solving this which is selecting the appropriate scaling modes which are available: Aspect Fill, Aspect Fit, Fill, Resize Fill.
I have tried all 4 out, and can see that they all have numerous advantages, but all have their cons, so none of them are what I am looking for.
I have come up with my own solution for what I am looking for (the following code is from the OS X version, but the iOS version is very similar):
First, I define sceneDimension using a macro:
#define sceneDimension 1024
Then I delete the SKScene file, and create my own scene using the following line of code:
#implementation AppDelegate
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
GameScene *scene = [[GameScene alloc] initWithSize:CGSizeMake(sceneDimension * (self.skView.bounds.size.width / MIN(self.skView.bounds.size.width, self.skView.bounds.size.height)), sceneDimension * (self.skView.bounds.size.height / MIN(self.skView.bounds.size.width, self.skView.bounds.size.height)))];
.....
}
.....
#end
This code ensures that whatever the size/proportions of the device the app is running in, the top right coordinate of the screen will always be treated as (x, 1024) if the width of the screen is larger, or (1024, y) if the height of the screen is larger.
In this way, I won't have to worry about repositioning objects as long as the scene always maintains the smaller coordinate of the top right corner to be 1024. (This is not the same as Aspect Fit, as I don't want to have letterboxing)
The problem I'm encountering is apparent when I run the app on OSX. Whenever the window is resized, a scaling mode still needs to be selected, and none were the ones which I was after.
Therefore, I wish to override whatever the program does when it scales the screen, by using the line of code:
scene.size = CGSizeMake(sceneDimension * (self.view.bounds.size.width / MIN(self.view.bounds.size.width, self.view.bounds.size.height)), sceneDimension * (self.view.bounds.size.height / MIN(self.view.bounds.size.width, self.view.bounds.size.height)))
However, I don't know where to add the line of code. I have tried using this line of code in the function didApplyConstraints: in the .m file:
#implementation
.....
- (void)didApplyConstraints {
scene.size = CGSizeMake(sceneDimension * (self.view.bounds.size.width / MIN(self.view.bounds.size.width, self.view.bounds.size.height)), sceneDimension * (self.view.bounds.size.height / MIN(self.view.bounds.size.width, self.view.bounds.size.height)))
}
#end
And this gives the desired result mostly. However, during the dragging of the mouse, it can still be seen that the scene is being scaled using one of the previously mentioned scaling mode, rather than my new function. I also read that didApplyConstraints: is called every frame, which is what I don't want to happen - I want it to be called whenever the size of the window changes.
Is there a more appropriate function instead of didApplyConstraints: which does this? didChangeSize: does not work either, since the program ends up in an infinite loop since I change the size inside the function.
Thanks!
It sounds like what you are trying to attempt is .AspectFill, but with a twist. You want to fill up your screen, but keep your coordinate system the same on the x axis for all devices.
When you are doing your math, you need to take the aspect ratio into consideration.
We are only going to talk about portrait mode here.
We have an iPhone 5 that has an aspect ratio of 9:16.
We want our x to always be 1024.
This means that we want our y to be 1820 (1820.4444~ to be exact)
Now we have an iPhone 4 that has an aspect ratio of 2:3.
This means that we want our y to be 1536
So, to get these numbers, you take (1024 * height) / width
We can now again talk about both portrait and landscape.
Here is how you would apply the math:
let w = sceneDimension
let h = (w * UIScreen.mainScreen().bounds.size.height) / UIScreen.mainScreen().bounds.size.width)
scene.size = CGSizeMake(w,h)
This now means that regardless of orientation, when the scene is created, the bottom left most point is (0,0), the bottom right most point is (1024,0).
Aspect Fill will now fill up the entire screen, leaving no letter boxes, and no loss on your edges
I have a UIView, which I'm drawing manually in the 'drawRect'-Function.
It is basically a coordinate system, which has 'Values' on the Y-Axis and 'Time' on the 'X-Axis'.
Due to space issues, I want the Timestamps to be vertical, instead of horizontal.
For this purpose, I use:
CGContextSaveGState(ctx); //Saves the current graphic context state
CGContextRotateCTM(ctx, M_PI_2); //Rotates the context by 90° clockwise
strPos = CGContextConvertPointToUserSpace(ctx, strPos); //SHOULD convert to Usercoordinates
[str drawAtPoint:strPos withFont:fnt]; //Draws the text to the rotated CTM
CGContextRestoreGState(ctx); //Restores the CTM to the previous state.
ctx (CGContextRef), strPos (CGPoint) and str (NSString) are variables, that have been initialized properly and correctly for 'horizontal text', with a width of the text height.
While this code works flawlessly on the iPhone 3, it gives me a complete mess on the iPhone 4 (Retina), because the CGContextConvertPointToUserSpace function produces completely different results, even though the coordinate system of the iPhone is supposed to remain the same.
I also tried using CGAffineTransform, but only with the same results.
To summarize my question: How do I draw a text to a calculated position in the parent coordinate system (0, 0 being top left)?
After studying the Apple docs regarding Quartz 2D once more, I came to realize, that the rotation by Pi/2 moves all my writing off screen to the left.
I can make the writing appear in a vertical line by translating the CTM by +height.
I'll keep trying, but would still be happy to get an answer.
Edit: Thanks to lawicko's heads-up I was able to fix the problem. See Answer for details.
I would like to thank lawicko for pointing this out.
During my tests I made two mistakes...but he is of course correct. Using CGContextShowTextAtPoint is the most simple solution, since it doesn't require the rotation of the entire CTM.
Again, THANK you.
Now, for the actual answer to my question.
To draw a rotated text at position x/y, the following code works for me.
CGAffineTransform rot = CGAffineTransformMakeRotation(M_PI_2); //Creates the rotation
CGContextSelectFont(ctx, "TrebuchetMS", 10, kCGEncodingMacRoman); //Selects the font
CGContextSetTextMatrix(ctx, CGAffineTransformScale(rot, 1, -1)); //Mirrors the rotated text, so it will be displayed correctly.
CGContextShowTextAtPoint(ctx, strPos.x, strPos.y, TS, 5); //Draws the text
ctx is the CGContext, strPos the desired position in the parent coordinate system, TS a char array.
Again, thank you lawicko.
I probably would've searched forever if not for your suggestion.
Maybe this answer will help someone else, who comes across the same problem.
I have a webcam directly over a chicken nest. This camera takes images and uploads them to a folder on a server. I'd like to detect if an egg has been laid from this image.
I'm thinking the best method would be to compare the contrast as the egg will be much more reflective than the straw nest. (The camera has Infrared so the image is partly grey scale)
I'd like to do this in .NET if possible.
Try to resize your image to a smaller size, maybe 10 x 10 pixel. This averages out any small disturbing details.
Const N As Integer = 10
Dim newImage As New Bitmap(N, N)
Dim fromCamera As Image = Nothing ' Get image from camera here
Using gr As Graphics = Graphics.FromImage(newImage)
gr.SmoothingMode = SmoothingMode.HighSpeed
gr.InterpolationMode = InterpolationMode.Bilinear
gr.PixelOffsetMode = PixelOffsetMode.HighSpeed
gr.DrawImage(fromCamera, New Rectangle(0, 0, N, N))
End Using
Note: you do not need a high quality, but you need a good averaging. Maybe you will have to test different quality settings.
Since now, a pixel covers a large area of your original image, a bright pixel is very likely part of an egg. It might also be a good idea to compare the brightness of the brightest pixel to the average image brightness, since that would reduce problems due to global illumination changes.
EDIT (in response to comment):
Your code is well structured and makes sense. Here some thoughts:
Calculate the gray value from the color value with:
Dim grayValue = c.R * 0.3 + c.G * 0.59 + c.B * 0.11
... instead of comparing the three color components separately. The different weights are due to the fact, that we perceive green stronger than red and red stronger than blue. Again, we do not want a beautiful thumbnail we want a good contrast. Therefore, you might want to do some experiments here as well. May be it is sufficient to use only the red component. Dependent on lighting conditions one color component might yield a better contrast than others. I would recommend, to make the gray conversion part of the thumbnail creation and to write the thumbnails to a file or to the screen. This would allow you to play with the different settings (size of the thumbnail, resizing parameters, color to gray conversion, etc.) and to compare the (intermediate) results visually. Creating a bitmap (bmp) with the (end-)result is a very good idea.
The Using statement does the Dispose() for you. It does it even if an exception should occur before End Using (There is a hidden Try Finally involved).
I have a physical map (real world), for example, a little town map.
A "path" line is painted over the map, think about it like "you are here. here's how to reach the train station" :)
Now, let's suppose I can get an image of that scenario (likewise, coming from a photo).
An image that looks like:
My goal is not easy way out!
I want to GET the path OUT of the image, i.e., separate the two layers.
Is there a way to extract those red marks from the image?
Maybe using CoreGraphics? Maybe an external library?
It's not an objective C specific question, but I am working on Apple iOS.
I already worked with something similar, the face-recognition.
Now the answer I expect is: "What do you mean by PATH?"
Well, I really don't know, maybe a line (see above image) of a completely different color from the 'major' colors in the background.
Let's talk about it.
If you can use OpenCV then it becomes simpler. Here's a general method:
Separate the image into Hue, Saturation and Variation (HSV colorspace)
Here's the OpenCV code:
// Compute HSV image and separate into colors
IplImage* hsv = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 3 );
cvCvtColor( img, hsv, CV_BGR2HSV );
IplImage* h_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
IplImage* s_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
IplImage* v_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );
Deal with the Hue (h_plane) image only as it gives just the hue without any change in value for a lighter or darker shade of the same color
Check which pixels have Red hue (i think red is 0 degree for HSV, but please check the OpenCV values)
Copy these pixels into a separate image
I's strongly suggest using the OpenCV library if possible, which is basically made for such tasks.
You could filter the color, define a threshold for what the color red is, then filter everything else to alpha, and you have left over what your "path" is?
I'm trying to draw a "conical"/"arcing" gradient (I don't know what would be the correct term for this) (Photoshop calls it an "angle" gradient —your friendly neighborhood stackoverflow editor) using Objective-C (IOS), pretty much exactly like the image shown in the following thread.
After days of googling and searching the internet to no avail, I've decided to ask for help here.
A little background on what I'm trying to do. My objective is to create a custom UIView, which is circular progress bar, a ring basicly, somewhat similar to the activity indicator as seen in the TweetBot iPhone app (displays when you drag to refresh, which can be seen in action here, around 17-18 seconds into the video, on top of the iphone screen). I want the progress indicator (the fill of the ring) to be a simple two color gradient, which can be set programmatically, and the view to be resizable.
Filling the ring shape with a gradient that "follows" the arc of the ring is where I'm stuck. The answers that I get from googling, reading Apple's Core Graphics documentation on gradients and searching on SO are either about radial gradients or linear/axial gradients, which is not what I'm trying to achieve.
The thread linked above suggests using pre-made images, but this isn't an option because the colors of the gradient should be settable, the view should be resizable and the fill of the progress bar isn't always 100% full obviously (which would be the state of the gradient as shown in the picture in the thread above).
The only solution that I've come up with is to draw the gradient "manually", so without using a CGGradientRef, clipping small slices of the gradient with single solid color fills within a circular path. I don't know exactly how well this will perform when the bar is being animated though, it shouldn't be that bad, but it might be a problem.
So my first question:
Is there an easier/different solution to draw a conical/arcing gradient in Objective-C (IOS) than the solution I've come up with?
Second question:
If I have to draw the gradient manually in my view using the solution I came up with, how can I determine or calculate (if this is even possible) the value (HEX or RGBA) of each color "slice" of the gradient that I'm trying to draw, as illustrated in the image below.
(Can't link image) gradient slice illustration
Looks to me like a job for a pixel shader. I remember seeing a Quartz Composer example that simulated a radar sweep, and that used a pixel shader to produce an effect like you're describing.
Edit:
Found it. This shader was written by Peter Graffignino:
kernel vec4 radarSweep(sampler image, __color color1,__color color2, float angle, vec4 rect)
{
vec4 val = sample(image, samplerCoord(image));
vec2 locCart = destCoord();
float theta, r, frac, angleDist;
locCart.x = (locCart.x - rect.z/2.0) / (rect.z/2.0);
locCart.y = (locCart.y - rect.w/2.0) / (rect.w/2.0);
// locCart is now normalized
theta = degrees(atan(locCart.y, locCart.x));
theta = (theta < 0.0) ? theta + 360.0 : theta;
r = length(locCart);
angleDist = theta - angle;
angleDist = (angleDist < 0.0) ? angleDist + 360.0 : angleDist;
frac = 1.0 - angleDist/360.0;
// sum up 3 decaying phosphors with different time constants
val = val*exp2(-frac/.005) + (val+.1)*exp2(-frac/.25)*color1 + val*exp2(-frac/.021)*color2;
val = r > 1.0 ? vec4(0.0, 0.0,0.0,0.0) : val; // constrain to circle
return val;
}
The thread linked above suggests using pre-made images, but this isn't an option because the colors of the gradient should be settable, the view should be resizable and the fill of the progress bar isn't always 100% full obviously (which would be the state of the gradient as shown in the picture in the thread above).
Not a problem!
Use the very black-to-white image from the other question (or a bigger version if you need one), in the following fashion:
Clip to whatever shape you want to draw the gradient in.
Fill with the color at the end of the gradient.
Use the black-to-white gradient image as a mask.
Fill with the color at the start of the gradient.
You can rotate the gradient by rotating the mask image.
This only supports the simplest case of a gradient with a color at each extreme end; it doesn't scale to three or more colors and doesn't support unusual gradient stop positioning.
FYI: here's also a good tutorial for creating a circular progress bar using Quartz drawing.
http://www.turnedondigital.com/blog/quartz-tutorial-how-to-draw-in-quartz/