turning the corners of CGRect round like with UIView - uibezierpath

I have this function that basically adds a given text below a given image, I wish to make the corners of textRect round, can you help me understand how to use UIBezierPath in this code
-(UIImage*) overlapText:(NSString*) p_text inImage:(UIImage*) p_image atPoint:(CGPoint) p_point
{
p_point.y += p_image.size.height-5;
UIFont *font = [UIFont boldSystemFontOfSize:11];
UIGraphicsBeginImageContext(CGSizeMake(p_image.size.width+15,p_image.size.height+15));
CGFloat imageX = (p_image.size.width+10)/2 - (p_image.size.width/2);
[p_image drawInRect:CGRectMake(imageX,0,p_image.size.width,p_image.size.height)];
CGRect textRect = CGRectMake(0, p_point.y, p_image.size.width+15, p_image.size.height+10);
[[UIColor colorWithRed:(70/255.0) green:(70/255.0) blue:(70/255.0) alpha:1] set];
CGContextFillRect(UIGraphicsGetCurrentContext(), textRect);
[[UIColor whiteColor] set];
[p_text drawInRect:textRect withFont:font lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentCenter];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

Your image context is the current context, so just construct the rounded rect with bezierPathWithRoundedRect:cornerRadius:, set your fill color, and tell the bezier path to fill. It's one line of code (well, two if you count setting the fill color):
[[UIColor colorWithRed:(70/255.0) green:(70/255.0) blue:(70/255.0) alpha:1] set];
[[UIBezierPath bezierPathWithRoundedRect:textRect cornerRadius:5] fill];
Feel free to play with the numbers here; for example, you might like a different corner radius. Experiment!

Related

How would I make a color relative to images in the background?

For example, if you go to Twitter and click on an image, you can see they have a nice color that is close to what you see on the image. I tried looking up ways to achieve this as well as trying to figure it out on my own but no luck. I'm not sure if there's a color: relative property or not.
if you want to use the a colour that exists in your image and set it as a background colour you need to use the canvas element in the following manner:
HTML (this is your image)
<img src="multicolour.jpg" id="mainImage">
JS
window.onload = function() {
// get the body element to set background (this can change dependending of your needs)
let body = document.getElementsByTagName("body")
// get references to the image element that contains the picture you want to match with background
let referenceImage = document.getElementById("mainImage");
// create a canvas element (but don't add it to the page)
let canvas = document.createElement("canvas");
// make the canvas size the same as your image
canvas.width = referenceImage.offsetWidth
canvas.height = referenceImage.offsetHeight
// create the canvas context
let context = canvas.getContext('2d')
// usage your image reference to draw the image in the canvas
context.drawImage(referenceImage,0,0);
// select a random X and Y coordinates inside the drawn image in the canvas
// (you don't have to do this one, but I did to demonstrate the code)
let randomX = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
// THIS IS THE MOST IMPORTANT LINE
// getImageData takes 4 arguments: coord x, coord y, sample size w, and sample size h.
// in our case the sample size is going to be of 1 pixel so it retrieves only 1 color
// the method gives you the data object which constains and array with the r, b, g colour data from the selected pixel
let color = context.getImageData(randomX, randomY, 1, 1).data
// use the data to dynamically add a background color extracted from your image
body[0].style.backgroundColor = `rgb(${color[0]},${color[1]},${color[2]})`
}
here is a gif of the code working... hopefully this helps
UPDATE
Here is the code to select two random points and create a css3 background gradient
window.onload = function() {
// get the body element to set background (this can change dependending of your needs)
let body = document.getElementsByTagName("body")
// get references to the image element that contains the picture you want to match with background
let referenceImage = document.getElementById("mainImage");
// create a canvas element (but don't add it to the page)
let canvas = document.createElement("canvas");
// make the canvas size the same as your image
canvas.width = referenceImage.offsetWidth
canvas.height = referenceImage.offsetHeight
// create the canvas context
let context = canvas.getContext('2d')
// usage your image reference to draw the image in the canvas
context.drawImage(referenceImage,0,0);
// select a random X and Y coordinates inside the drawn image in the canvas
// (you don't have to do this one, but I did to demonstrate the code)
let randomX = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
// THIS IS THE MOST IMPORTANT LINE
// getImageData takes 4 arguments: coord x, coord y, sample size w, and sample size h.
// in our case the sample size is going to be of 1 pixel so it retrieves only 1 color
// the method gives you the data object which constains and array with the r, b, g colour data from the selected pixel
let colorOne = context.getImageData(randomX, randomY, 1, 1).data
// THE SAME TO OBTAIN ANOTHER pixel data
let randomX2 = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY2 = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
let colorTwo = context.getImageData(randomX2, randomY2, 1, 1).data
// use the data to dynamically add a background color extracted from your image
//body[0].style.backgroundColor = `rgb(${allColors[0]},${allColors[1]},${allColors[2]})`
body[0].style.backgroundImage = `linear-gradient(to right, rgb(${colorOne[0]},${colorOne[1]},${colorOne[2]}),rgb(${colorTwo[0]},${colorTwo[1]},${colorTwo[2]}))`;
}
The following are your options.
1. Use an svg.
As far as I know there's no way to have javascript figure out what color is being used in a png and set it as a background color. But you can work the other way around. You can have javascript set the background color and an svg image to be the same color.
See this stackoverflow answer to learn more about modifying svgs with javascript.
2. Use a custom font.
There are fonts out there that provide a bunch of icons instead of letters, you can also create your own font if you feel so inclined to do so. With css you just have to set the font-color of that icon to be the same as the background-color of your other element.
Font Awesome provides a bunch of useful custom icons. If the image you need to use happens to be similar to one of theirs, you can just go with them.
3. Use canvas
If you really want to spend the time to code it up you can use a html <canvas/> element and put the image into it. From there you can inspect certain details about the image like its color, then apply that color to other elements. I won't go into too much detail about using this method as it seems like it's probably overkill for what you're trying to do, but you can read up more about from this stackoverflow answer.
4. Just live with it.
Not a fun solution, but this is usually the option I go with. You simply have to hard-code the color of the image into your css and live with it. If you ever need to modify the color of the image, you have to remember to update your css also.

HTML5 Canvas with Predefined Image

Recently I started working on HTML5 Canvas, I'm new to it.
I've a problem as follows:
I'm loading a Canvas with Body Chart Image (Predefined Image) and on that User will Draw some lines, shapes, etc.
After that I'll generate an image object as follows
var canvas = document.getElementById("MyCanvas");
var dataURL = canvas.toDataURL();
var image = new Image();
image.src = dataURL;
But, Here it generates only those elements which are drawn by users (lines, shapes) as PNG Image. It won't take that Predefined canvas background Image.
I need to generate a PNG image which should include both the Canvas background Image as well as User entered drawing elements.
How to do this?
Try to actually draw you image onto your canvas, utilizing these functions:
var canvas = document.getElementById("MyCanvas");
var img = new Image();
img.src = 'pathToYourImageHere';
canvas.drawImage(img,0,0); /* 0,0 is x and y from the top left */
When you now try to save it, it should also save your background image.
EDIT:
In response to your comment:
You can circument your layering problem by using two different canvases. One for the image, and one for your drawing. Then layer them on top of each other using absolute positioning.
You can read more here: Save many canvas element as image
EDIT2:
But actually you shouldn't have a layering problem, since the following code will first draw the image and then draw the arc, and the layering will be fine:
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.src = "somePathToAnImage";
context.drawImage(imageObj, 50, 50);
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 1.1 * Math.PI;
var endAngle = 1.9 * Math.PI;
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 15;
// line color
context.strokeStyle = "red";
context.stroke();
Even though the layering is fine, you will be better of by using two canvases, in case you would like to only save the drawing, without the background. You can always save both into a new canvas and save that, when you only use one canvas you'll have a hard time separating the drawing from the background.
This is because the image needs time to load, you have to use the onload function.
imgObj.onload = function() { context.drawImage(imageObj, 50, 50); imgLoaded = true;}
if (imgLoaded) { /*you draw shapes here */ }

HTML5 Canvas Fill with two colours

I have a requirement to fill a shape with a two colours - like a chess board.
I have seen some gradient effects with css but have not seen any examples like this.
Would this even be possible in Html5 Canvas?
You sure can. In fact you can fill any arbitrary shape with any repeatable thing, even with shapes that you make in the Canvas itself!
Here's an example of an arbitrary shape getting filled with "pea pods" that were defined on a canvas: http://jsfiddle.net/NdUcv/
Here it is with a simple checkerboard pattern: http://jsfiddle.net/NdUcv/2/
That second one makes a shape fill look like this:
I create that pattern by making a canvas and then drawing whatever I want to repeat on it:
var pattern = document.createElement('canvas');
pattern.width = 40;
pattern.height = 40;
var pctx = pattern.getContext('2d');
// Two green rects make a checkered square: two green, two transparent (white)
pctx.fillStyle = "rgb(188, 222, 178)";
pctx.fillRect(0,0,20,20);
pctx.fillRect(20,20,20,20);
Then on my normal canvas I can do:
var pattern = ctx.createPattern(pattern, "repeat");
ctx.fillStyle = pattern;
and draw fill anything with that pattern.
Of course it doesn't have to be a canvas path, you could use a checkerboard image (or any kind of image) and fill a shape with it using the canvas patterns.
I did a quick example
<html>
<head>
<hea>
<body onload='xx()'>
<canvas id='mycanvas' width='256' height='256'>ops</canvas>
</body>
<script type='text/javascript'>
function xx(){
var canvas= document.getElementById('mycanvas');
ctx= canvas.getContext('2d');
for(var i=0;i<8;i++){
for(var j=0;j<8;j++){
if (ctx.fillStyle == '#000000')
ctx.fillStyle = 'blue';
else ctx.fillStyle = '#000000';
ctx.fillRect(32*j, 32*i, 32,32);
}
if (ctx.fillStyle == '#000000')
ctx.fillStyle = 'blue';
else ctx.fillStyle = '#000000';
}
}

flex: Drag and drop- object centering

In a drag+drop situation using Flex, I am trying to get the object center aligned to the point of drop- somehow, irrespective of the adjustments to height and width, it is always positioning drop point to left top.
here is the code..
imageX = SkinnableContainer(event.currentTarget).mouseX;
imageY = SkinnableContainer(event.currentTarget).mouseY;
// Error checks if imageX/imageY dont satisfy certain conditions- move to a default position
// img.width and img.height are both defined and traced to be 10- idea to center image to drop point
Image(event.dragInitiator).x = imageX-(img.width)/2;
Image(event.dragInitiator).y = imageY-(img.height)/2
The last 2 lines don't seem to have any effect. Any ideas why-must be something straightforward, that I am missing...
You can use the following snippet:
private function on_drag_start(event:MouseEvent):void
{
var drag_source:DragSource = new DragSource();
var drag_initiator:UIComponent = event.currentTarget as UIComponent;
var thumbnail:Image = new Image();
// Thumbnail initialization code goes here
var offset:Point = this.localToGlobal(new Point(0, 0));
offset.x -= event.stageX;
offset.y -= event.stageY;
DragManager.doDrag(drag_initiator, drag_source, event, thumbnail, offset.x + thumbnail.width / 2, offset.y + thumbnail.height / 2, 1.0);
}
Here is one important detail. The snippet uses stage coordinate system.
If you use event.localX and event.localY, this approach will fail in some cases. For example, you click-and-drag a movie clip. If you use localX and localY instead of stage coordinates, localX and localY will define coordinates in currently clicked part of the movie clip, not in the whole movie clip.
Use the xOffset and yOffset properties in the doDrag method of DragManager.
Look here for an example.

Flex 3 - Diagonally draw text in a shape and adjust size

I'm trying to create the following component:
Just for information, the blank space will contain a text control, and I'm creating a component that represents the black corner with the (i) icon and the "promotion" text.
The part I'm having issues with is this component representing the black corner with the diagonal text. The text has to be able to hold 2 lines. And the black corner has to be able to adjust to the text's size.
What's more, the text has a rotation...
I'm having some doubts on how to do this:
Should I have different controls for each text line?
Should I draw the text in the shape (after doing the rotation) or should I just overlap both components? [When I talk about drawing the text in the shape, I mean in the same way as asked in this question]
Is there any way to get the proper size of the triangle shape without doing some extravagant calculations?
And... do you have any "easier" ways to do this ?
A big thanks for any help you can provide :) I'm a little bit lost with this little component :)
Regards.
BS_C3
Edit 1:
The triangle may have 2 sizes: 1 size that will fit 1 line, and another size to fit 2 lines of text.
The text will be sent as a single string, so it will have to be automatically divided in two lines if needed
I was thinking of using graphics to draw the triangle shape and then use a mask to create the rounded corner --> This is because the same component will be used in other places of the application without the rounded corner
Flex is pretty good at updating group components to whatever size thier contents become, updating dynamically on the fly..
for what your suggesting, I'd probably create the "Promotion" group in the corner as a rectangle, rotate it and fit it to the corner like you want, then using a copy of the rounded rect you use as the maing component background, i'd make a mask to cut the "Promotion" component so you don't see the overlap.
Well, I finally wrote the class and this is the result:
public class Corner extends Canvas
{
private var infoIcon:Image;
private var text:Text;
private var triangle:Shape;
private var bgColor:uint;
public function Corner()
{
super();
infoIcon = new Image;
text = new Text;
text.rotation = -45;
text.width = 75;
text.maxHeight = 30;
text.setStyle('color', '0xffffff');
text.setStyle('textAlign', 'center');
text.y = 53;
this.addChild(infoIcon);
this.addChild(text);
triangle = new Shape;
}
public function build(bgColor:uint = 0x61113D):void{
this.bgColor = bgColor;
// info icon data
// set text
text.addEventListener(FlexEvent.UPDATE_COMPLETE, textHandler);
text.text = 'blabla';
text.validateNow();
}
/**
*
*/
private function textHandler(e:FlexEvent):void{
switch(e.type){
case FlexEvent.UPDATE_COMPLETE:
text.removeEventListener(FlexEvent.UPDATE_COMPLETE, textHandler);
drawTriangle();
break;
}
}
/**
*
*/
private function drawTriangle():void{
var h:int = 80;
// check if the text has 1 or 2 lines
if(text.height > 20)
h = 95;
// remove the triangle shape if it exists
if(this.rawChildren.contains(triangle))
this.rawChildren.removeChild(triangle);
// draw triangle
triangle = new Shape;
triangle.graphics.moveTo(0, 0);
triangle.graphics.beginFill(bgColor);
triangle.graphics.lineTo(h, 0);
triangle.graphics.lineTo(0, h);
triangle.graphics.lineTo(0, 0);
triangle.graphics.endFill();
this.rawChildren.addChildAt(triangle,0);
dispatchEvent(new MyEvent(MyEvent.CORNER_UPDATED));
}
...
}

Resources