How to draw in X11 with Go - graphics

I've been looking into draw and draw.x11 packages that come with Go. I didn't find out a simple way to draw a line on a X11 window.
Where I can find some simple 2D drawing examples?

I found myself the answer, here it goes a simple example:
package main
import (
"os"
"time"
"image"
"exp/draw/x11"
)
func main() {
win, _ := x11.NewWindow()
color := image.RGBAColor{255, 255, 255, 255}
img := win.Screen()
for i, j := 0, 0; i < 100 && j < 100; i, j = i + 1, j + 1 {
img.Set(i, j, color)
}
win.FlushImage()
time.Sleep(10 * 1000 * 1000 * 1000)
win.Close()
os.Exit(0)
}

While your solution works, I think what you're really looking for is X Go Binding

package main
import (
"fmt"
"code.google.ui/x11" // i'm not sure this is the actual package
"time" // name u better refer the packages
"os"
)
func main() {
win,err := x11.NewWindowArea(600,600) // it creates a window with 600 width&600
if err != nil { // height
fmt.Println(err)
os.Exit(0) // if any err occurs it exits
}
img :=win.Screen // in this newly created screen u cn draw
for i:=0;i<100;i++ { // any thing pixel by pixel
for j:=0;j<100;j++ {
img.Set(0+i,0+j,image.Black) // now this draws a square in the black
} // color oo the created screen
}
win.FlushImage() // its for flushing the image then only new
time.Sleep(time.Second*15) // image cn be draw
}

Related

zoom in / out the image inside a pictureBox in VC++2015 (OpenCV used)

OS : Win 10
IDE: Visual Studio 2015
Language: C++
Others: I use OpenCV 3.4
I just create a Window Form using CLR empty project,
then put on a pictureBox & three buttons.
First button: load a local image and show on the pictureBox:
pictureBox1->Image = Image::FromFile("D:/something.png");
global_mat = imread("D:/something.png", 1); // global_mat is a global Mat.
zoom_in_counter = 0; // zoom_in_counter is a global int.
Second button: zoom in the image in the pictureBox
if (zoom_in_counter < 5) // You can only enlarge the image 5 times.
{
Mat new_mat = Mat::zeros(0, 0, CV_8UC3);
resize(global_mat, new_mat, cv::Size(global_mat.cols * 2, global_mat.rows * 2));
global_mat = new_mat;
if ((pictureBox1->Width != new_mat.cols) || (pictureBox1->Height != new_mat.rows))
{
pictureBox1->Width = new_mat.cols;
pictureBox1->Height = new_mat.rows;
pictureBox1->Image = gcnew System::Drawing::Bitmap(new_mat.cols, new_mat.rows);
}
System::Drawing::Bitmap^ bmpImage = gcnew Bitmap(
new_mat.cols, new_mat.rows, new_mat.step,
System::Drawing::Imaging::PixelFormat::Format24bppRgb,
System::IntPtr(new_mat.data)
);
Graphics^ g = Graphics::FromImage(pictureBox1->Image);
g->DrawImage(bmpImage, 0, 0, new_mat.cols, new_mat.rows);
pictureBox1->Refresh();
delete g;
zoom_in_counter++;
}
Third buttin: zoom out the image in the pictureBox
if (zoom_in_counter > 0) // You can't shrink the image.
{
Mat new_mat = Mat::zeros(0, 0, CV_8UC3);
resize(global_mat, new_mat, cv::Size(global_mat.cols * 0.5, global_mat.rows * 0.5));
global_mat = new_mat;
if ((pictureBox1->Width != new_mat.cols) || (pictureBox1->Height != new_mat.rows))
{
pictureBox1->Width = new_mat.cols;
pictureBox1->Height = new_mat.rows;
pictureBox1->Image = gcnew System::Drawing::Bitmap(new_mat.cols, new_mat.rows);
}
System::Drawing::Bitmap^ bmpImage = gcnew Bitmap(
new_mat.cols, new_mat.rows, new_mat.step,
System::Drawing::Imaging::PixelFormat::Format24bppRgb,
System::IntPtr(new_mat.data)
);
Graphics^ g = Graphics::FromImage(pictureBox1->Image);
g->DrawImage(bmpImage, 0, 0, new_mat.cols, new_mat.rows);
pictureBox1->Refresh();
delete g;
zoom_in_counter--;
}
And then,
every I zoom in or zoom out, it works,
excludeingthe image is zoomed back to the original size.
I'll get such error message:
An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll
It's really odd!
Finally, my friend figure out what's wrong,
please refer to:
https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms536315(v=vs.85).aspx
stride [in]
Type: INT
Integer that specifies the byte offset between the beginning of one scan line and the next. This is usually (but not necessarily) the number of bytes in the pixel format (for example, 2 for 16 bits per pixel) multiplied by the width of the bitmap. The value passed to this parameter must be a multiple of four.

Using the Color package to create new Color from RGB value?

I'm trying to create a new Color object using RGB values I have in variables:
http://golang.org/pkg/image/color/
package main
import (
"fmt"
"image"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
"os"
)
func main() {
reader, err := os.Open("test-image.jpg")
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
image, _, err := image.Decode(reader)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
}
bounds := image.Bounds()
for i := 0; i <= bounds.Max.X; i++ {
for j := 0; j <= bounds.Max.Y; j++ {
pixel := image.At(i, j)
if i == 0 && j == 0 {
red, green, blue, _ := pixel.RGBA()
averaged := (red + green + blue) / 3
// This FromRGBA function DOES NOT EXIST!
grayColor := Color.FromRGBA(averaged, averaged, averaged, 1)
// Then I could do something like:
grayColor.RGBA() // This would work since it's a type Color.
}
}
}
}
I can't seem to find any package Function that generates a new Color object given rgba values.
Any recommendations?
The image.Color actually is an interface. You can use any structure which satisfies it. Even your own structures.
For example, you could use image.Gary:
grayColor := image.Gray{averaged}
or your own grayColor:
type MyGray struct {
y uint32
}
func (gray *MyGray) FromRGBA(r, g, b, a uint32) {
gray.y = (r + g + b) / 3
}
func (gray *MyGray) RGBA() (r, g, b, a uint32) { // to satisfy image.Color
return gray.y, gray.y, gray.y, 1
}
grayColor := &MyGray{}
grayColor.FromRGBA(pixel.RGBA())
grayColor.RGBA()
// blablabla
The types in the image/color package have exported fields, so you can instantiate them directly. For your example, you could create the colour value with:
grayColor := color.Gray16{Y: uint16(averaged)}
(The red, green and blue values are all in the 0..0xffff range, so the 16-bit Gray colour implementation seems appropriate).

Having trouble moving a reticle around the screen while following Chili's Beginning DirectX tutorial

To begin with I am using the Chili Framework for lessons 1-15 as downloadable here:
http://www.planetchili.net/
I am using DirectX 9 on an old laptop running Windows XP SP3. I have set the Direct3D rendering to software in order to run the framework. I am using Visual Studio Express C++ 2010 with the first service pack installed.
This is the code I am having trouble with:
// Start moving reticle code
DrawReticle(itemLocX, itemLocY, 255, 255, 255);
if(itemLocX == pointA && itemLocX != pointAb)
{
itemLocX += 2;
}
else if(itemLocX == pointBc && itemLocX != pointDa)
{
itemLocX -= 2;
}
if(itemLocY == pointAb && itemLocY != pointBc)
{
itemLocY += 2;
}
else if(itemLocY == pointDa && itemLocX != pointA)
{
itemLocY -= 2;
}
// End moving reticle code
Now Chili's solution is to move along the y axis while checking for x, and x while checking for y. I may post that later, don't have it readily available. You can see it at the beginning of this video:
http://youtu.be/JEmwkQsi8l0
However I wanted to do this logically, as if I was walking the border along an invisible wall inside a box. I wanted it to make sense what was going on. But the cursor won't move, and I see no reason why it doesn't. Here is my game.h:
#pragma once
#include "D3DGraphics.h"
#include "Keyboard.h"
class Game
{
public:
Game( HWND hWnd,const KeyboardServer& kServer );
void Go();
private:
void ComposeFrame();
/********************************/
/* User Functions */
void DrawReticle(int xP, int yP, int cR, int cG, int cB);
/*
xP = x position,
yP = y position,
cR = color red,
cG = color green,
cB = color blue
*/
// TODO: User functions go here
/********************************/
private:
D3DGraphics gfx;
KeyboardClient kbd;
/********************************/
/* User Variables */
int pointA; // Starting at pointA (100, 100) - the top left
int pointAb; // Move from pointA to pointAb (700, 100) - the top right
int pointBc; // Move from pointAb to pointBc (700, 500) - the bottom right
int pointCd; // Move from pointBc to pointCd (100,500) - the bottom left
int pointDa; // Move from pointCd to pointDa (100,100) - the top left
/*
These points describe the process of starting, then four movements. The four points are A, B, C, D. We start at A, then go to B (pointAb, read as A to b), then go to C (pointBc, read as B to c), then go to D (pointCd, read as C to d) then go to A (pointDa, read as D to a).
This can be very confusing, because there are five varibles used. But if we drew it out there would only four points, as well as only four movements. The best way to think of it is that starting is itself a movement, and as you need a place to start from, it itself must have a point. Since you start at A, but haven't yet gone anywhere, pointA is our starting point. Once you start moving, you go from pointA to pointB. Now if we used pointB as our variable it would be confusing,because we would have to move from pointA to pointB to pointC to pointD and then back to pointA. Still five variables, one is repeating, but the first pointA describes where you start, and the last where you end. Since these are two different actions on the same point, I have elected to use two letter names for each of the points you move to, while the point you start at has a single letter name. It was the best way I could clearly think about this process.
*/
int itemLocX; // Initial position of item on the x axis
int itemLocY; // Initial position of item on the y axis
int reticleX; // Initial position of reticle on the x axis
int reticleY; // Initial position of reticle on the y axis
// TODO: User variables go here
/********************************/
};
Here is my game.cpp:
#include "Game.h"
Game::Game( HWND hWnd,const KeyboardServer& kServer )
: gfx(hWnd),
kbd(kServer),
itemLocX(100), // Initial position of item on the x axis
itemLocY(100), // Initial position of item on the y axis
reticleX(400), // Initial position of reticle on the x axis
reticleY(300), // Initial position of reticle on the y axis
pointA(100), // Movement from 0 to A, stopping at A
pointAb(700), // Movement from A to b, stopping at B
pointBc(500), // Movement from B to c, stopping at C
pointCd(700), // Movement from C to d, stopping at D
pointDa(500) // Movement from D to a, stopping at A
{}
void Game::Go()
{
gfx.BeginFrame();
ComposeFrame();
gfx.EndFrame();
}
void Game::DrawReticle(int xP, int yP, int cR, int cG, int cB)
/*
xP = x position,
yP = y position,
cR = color red,
cG = color green,
cB = color blue
*/
{
gfx.PutPixel(xP-5,yP,cR,cG,cB);
gfx.PutPixel(xP-4,yP,cR,cG,cB);
gfx.PutPixel(xP-3,yP,cR,cG,cB);
gfx.PutPixel(xP+3,yP,cR,cG,cB);
gfx.PutPixel(xP+4,yP,cR,cG,cB);
gfx.PutPixel(xP+5,yP,cR,cG,cB);
gfx.PutPixel(xP,yP,cR,cG,cB);
gfx.PutPixel(xP,yP-5,cR,cG,cB);
gfx.PutPixel(xP,yP-4,cR,cG,cB);
gfx.PutPixel(xP,yP-3,cR,cG,cB);
gfx.PutPixel(xP,yP+3,cR,cG,cB);
gfx.PutPixel(xP,yP+4,cR,cG,cB);
gfx.PutPixel(xP,yP+5,cR,cG,cB);
}
void Game::ComposeFrame()
{
// Start draw reticle code
DrawReticle(reticleX, reticleY, 100, 155, 255);
// End draw reticle code
// Start color change code
int yT = 200; // Border 200 pixels from top
int yB = 400; // Border 200 pixels from bottom
int xL = 300; // Border 200 pixels from left
int xR = 500; // Border 200 pixels from right
if(reticleX < xL || reticleX > xR) // Defining color change area for X
{
DrawReticle(reticleX, reticleY, 255, 255, 255);
}
if(reticleY < yT || reticleY > yB) // Defining color change area for Y
{
DrawReticle(reticleX, reticleY, 255, 255, 255);
}
// End color change code
// Start moving reticle code
DrawReticle(itemLocX, itemLocY, 255, 255, 255);
if(itemLocX == pointA && itemLocX != pointAb)
{
itemLocX += 2;
}
else if(itemLocX == pointBc && itemLocX != pointDa)
{
itemLocX -= 2;
}
if(itemLocY == pointAb && itemLocY != pointBc)
{
itemLocY += 2;
}
else if(itemLocY == pointDa && itemLocX != pointA)
{
itemLocY -= 2;
}
// End moving reticle code
// Start border code
if(reticleX < 6)
{
reticleX = 6;
}
else if(reticleX > 794)
{
reticleX = 794;
}
if(reticleY < 6)
{
reticleY = 6;
}
else if(reticleY > 594)
{
reticleY = 594;
}
// End border code
// Start speed change code
int cSpeed = 4; // Default cursor speed
if(kbd.EnterIsPressed()) // Change to high speed
{
cSpeed = 8;
}
if(kbd.SpaceIsPressed()) // Change to low speed
{
cSpeed = 1;
}
if(kbd.RightIsPressed())
{
reticleX += cSpeed;
}
if(kbd.LeftIsPressed())
{
reticleX -= cSpeed;
}
if(kbd.UpIsPressed())
{
reticleY -= cSpeed;
}
if(kbd.DownIsPressed())
{
reticleY += cSpeed;
}
// End speed change code
}
Now I should note here that this should be done without functions and only the basic C++ operators. That's as far as Chili has taught to this point. This is my second attempt to solve this myself, after hours thinking about it and working on it on paper. I'm stuck. Just not seeing it. I think there is a logic error here on my part. I want to understand where my thinking may be mistaken, but more than that, how to think correctly, like the computer, about this.
I am also open to advice regarding my coding style. If I am not being clear enough, or am doing something that should not become a bad habit - basically if there is something I should be doing differently in writing my code I would like to know about it.
Thank you for your help - it is very much appreciated!
I see how you have tried to do this. Personally you have over complexed it.
1: you don't need the != operator in your if statements.
2: try this:
if(itemLocX < 700)
{
itemLocX += 2;
}
3: This worked fine during testing. Another point is that the if statements could be in the wrong order. I changed it to the order in which it moved across the screen in. I have X Y X Y and you have X X Y Y. (unconfirmed) It executes the if statements in order. I have hard coded the answer. set them to variables if you really want to. Hope this helped!

User input displayed at wrong coordinates in OpenCV

I'm trying to display circles at a user accepted input (usually centers), using OpenCV 2.4.3 (VS 2010). On output image (displayed using 'namedWindow') circle seems to shift column-wise as one marks points along columns. Not sure how I should correct this.
Code:
struct OPTIONS{
OPTIONS(): X(-1), Y(-1), drawing_dot(false){}
int X;
int Y;
bool drawing_dot;
};
OPTIONS options;
void my_mouse_callback( int event, int x, int y, int flags, void* param ){
IplImage* image = (IplImage*) param;
switch( event ){
case CV_EVENT_LBUTTONDOWN:
options.X = x;
options.Y = y;
options.drawing_dot = true;
break;
default:
break;
}
}
int main( void ){
IplImage* image = cvLoadImage("Images/TestRealData/img1.bmp");
Mat frame = imread("Images/TestRealData/img1.bmp");
namedWindow("Test", CV_WINDOW_KEEPRATIO);
cvSetMouseCallback("Test", my_mouse_callback, (void*) image);
while( cvWaitKey(15) != 27 ){
if( options.drawing_dot ){
circle(frame, Point(options.X,options.Y), 3, CV_RGB(0,0,255), 2);
options.drawing_dot = false;
}
imshow("Test", frame);
waitKey(10);
}
cvReleaseImage(&image);
return 0;
}
I think the circle does not shift. The mouse cursor may trick our eyes. You may simply check it by increasing the radius and reduce the thickness of the circle outline like:
circle(frame, Point(options.X, options.Y/2), 15, CV_RGB(0, 0, 255), 1);
By the way, I think if you want to draw the circle at the point you click on, options.Y should not be divided by 2.
Found answer after much time lost - Make sure to specify flags in 'namedWindow'. Changing flag to CV_WINDOW_KEEPRATIO did the trick for me. Hope this helps somebody out there.

Object Detection in openCV

I have a problem with my program written in Visual C++ using OpenCV:
i have to capture frames from webcam and find all the various rectangle (it doesn't matter the color).
I try to modify the samples in c, squares.c, but it doesn't work as well, because the program wait any key (different from 'q') to continue.
This is the code. Someone can tell me where is the problem???
Thank you in advance.
//
// Object Detection of squares
// Take images from webcam and find the square in them
//
//
#include "stdafx.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
int thresh = 50;
IplImage* img = 0;
IplImage* img0 = 0;
CvMemStorage* storage = 0;
//const char* wndname = "Square Detection Demo with Webcam";
// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )
{
double dx1 = pt1->x - pt0->x;
double dy1 = pt1->y - pt0->y;
double dx2 = pt2->x - pt0->x;
double dy2 = pt2->y - pt0->y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )
{
CvSeq* contours;
int i, c, l, N = 11;
CvSize sz = cvSize( img->width & -2, img->height & -2 );
IplImage* timg = cvCloneImage( img ); // make a copy of input image
IplImage* gray = cvCreateImage( sz, 8, 1 );
IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );
IplImage* tgray;
CvSeq* result;
double s, t;
// create empty sequence that will contain points -
// 4 points per square (the square's vertices)
CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );
// select the maximum ROI in the image
// with the width and height divisible by 2
cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height ));
// down-scale and upscale the image to filter out the noise
cvPyrDown( timg, pyr, 7 );
cvPyrUp( pyr, timg, 7 );
tgray = cvCreateImage( sz, 8, 1 );
// find squares in every color plane of the image
for( c = 0; c < 3; c++ )
{
// extract the c-th color plane
cvSetImageCOI( timg, c+1 );
cvCopy( timg, tgray, 0 );
// try several threshold levels
for( l = 0; l < N; l++ )
{
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if( l == 0 )
{
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
cvCanny( tgray, gray, 0, thresh, 5 );
// dilate canny output to remove potential
// holes between edge segments
cvDilate( gray, gray, 0, 1 );
}
else
{
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );
}
// find contours and store them all as a list
cvFindContours( gray, storage, &contours, sizeof(CvContour),
CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
// test each contour
while( contours )
{
// approximate contour with accuracy proportional
// to the contour perimeter
result = cvApproxPoly( contours, sizeof(CvContour), storage,
CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if( result->total == 4 &&
fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 &&
cvCheckContourConvexity(result) )
{
s = 0;
printf("ciclo for annidato fino a 5\t\n");
for( i = 0; i < 5; i++ )
{
// find minimum angle between joint
// edges (maximum of cosine)
if( i >= 2 )
{
t = fabs(angle(
(CvPoint*)cvGetSeqElem( result, i ),
(CvPoint*)cvGetSeqElem( result, i-2 ),
(CvPoint*)cvGetSeqElem( result, i-1 )));
s = s > t ? s : t;
}
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if( s < 0.3 )
for( i = 0; i < 4; i++ )
cvSeqPush( squares,
(CvPoint*)cvGetSeqElem( result, i ));
}
// take the next contour
contours = contours->h_next;
}
}
}
// release all the temporary images
cvReleaseImage( &gray );
cvReleaseImage( &pyr );
cvReleaseImage( &tgray );
cvReleaseImage( &timg );
return squares;
}
// the function draws all the squares in the image
void drawSquares( IplImage* img, CvSeq* squares )
{
CvSeqReader reader;
IplImage* cpy = cvCloneImage( img );
int i;
// initialize reader of the sequence
cvStartReadSeq( squares, &reader, 0 );
// read 4 sequence elements at a time (all vertices of a square)
for( i = 0; i < squares->total; i += 4 )
{
CvPoint pt[4], *rect = pt;
int count = 4;
// read 4 vertices
CV_READ_SEQ_ELEM( pt[0], reader );
CV_READ_SEQ_ELEM( pt[1], reader );
CV_READ_SEQ_ELEM( pt[2], reader );
CV_READ_SEQ_ELEM( pt[3], reader );
// draw the square as a closed polyline
cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );
}
cvSaveImage("squares.jpg",cpy);
//show the resultant image
//cvShowImage( wndname, cpy );
cvReleaseImage( &cpy );
//return cpy;
}
int _tmain(int argc, _TCHAR* argv[])
{
int key = 0;
IplImage* frame =0;
IplImage* squares=0;
// create memory storage that will contain all the dynamic data
storage = cvCreateMemStorage(0);
CvCapture *camera = cvCreateCameraCapture(CV_CAP_ANY); /* Usa USB camera */
frame = cvQueryFrame(camera);
frame = cvQueryFrame(camera);
frame = cvQueryFrame(camera);
while(key!='q'){
frame = cvQueryFrame(camera);
frame = cvQueryFrame(camera);
if(frame!=NULL){
printf("Got frame\t\n");
cvSaveImage("frame.jpg", frame);
/*img0*/ img = cvLoadImage("frame.jpg");
//img = cvCloneImage( img0 );
cvNamedWindow( "img0", CV_WINDOW_AUTOSIZE);
cvShowImage("img0",/*img0*/img);
// find and draw the squares
drawSquares( img, findSquares4( img, storage ) );
squares = cvLoadImage("squares.jpg");
// create window and a trackbar (slider)
//with parent "image" and set callback
//(the slider regulates upper threshold,
//passed to Canny edge detector)
cvNamedWindow( "main", CV_WINDOW_AUTOSIZE);
cvShowImage("main", squares);
/* wait for key.
Also the function cvWaitKey takes care of event processing */
key = cvWaitKey(0);
}
}
// release both images
cvReleaseImage( &img );
cvReleaseImage( &img0 );
cvReleaseCapture(&camera);
cvDestroyWindow("main");
cvDestroyWindow("img0");
// clear memory storage - reset free space position
cvClearMemStorage( storage );
return 0;
}
I believe your problem is here:
/* wait for key.
Also the function cvWaitKey takes care of event processing */
key = cvWaitKey(0);
Try changing 0 to 10.
I see some other problems in your code. For instance, you create windows inside the while loop, which is not good. Try moving cvNamedWindow() function calls outside your while loop. Also, I'm not sure why you query camera for frames and do not process them?
If your problem is that the window dissappers without waiting for any hit from the keyboard, you can add a cvWaitKey(0) at the end of the code.
Also a getch( ) at the end would help. make sure you include in the headers.

Resources