使用C++在andrdoid上画贝塞尔曲线

  最近一直在学习在android上做画图板,不是使用android语言画的,使用的是纯C++,有用C++封装的input子系统触摸事件,还有canvas相结合的C++画图板。

  效果如下:

  

  好多没有优化,代码粗糙仅供阅读。上C++代码:

  1 #include <cutils/memory.h>    
  2 #include <unistd.h>  
  3 #include <utils/Log.h>  
  4 #include <binder/IPCThreadState.h>  
  5 #include <binder/ProcessState.h>  
  6 #include <binder/IServiceManager.h>  
  7   
  8 #include "SkRect.h"
  9 #include "SkTypeface.h"
 10 #include "Surface.h" 
 11 #include "SkPaint.h"
 12 #include <gui/SurfaceComposerClient.h>  
 13 #include <gui/ISurfaceComposer.h>  
 14 #include <ui/DisplayInfo.h>  
 15 #include <ui/Rect.h>  
 16 #include <ui/Region.h>  
 17 #include <android/native_window.h>  
 18 #include <SkGraphics.h>  
 19 #include <SkBitmap.h>  
 20 #include <SkCanvas.h>  
 21 #include <SkDevice.h>  
 22 #include <SkStream.h>  
 23 #include <SkImageDecoder.h>   
 24 #include <hardware/hwcomposer_defs.h>  
 25 
 26 #include <linux/input.h>
 27 #include <stdio.h>
 28 #include <pthread.h>
 29 #include <stdlib.h>
 30 #include <sys/types.h>
 31 #include <string.h>
 32 #include <sys/stat.h>
 33 #include <fcntl.h>
 34 #include <linux/fb.h>
 35 #include <sys/ioctl.h>
 36 
 37 //LCD和触摸框转换比例
 38 float xScale;// = 1920.0/32768;
 39 float yScale;// = 1080.0/32768;
 40 
 41 int fd ; // dev的文件描述符
 42 int fds[2];  //管道
 43 
 44 float x;
 45 float y;
 46 int pressure;
 47 float touchMajor;
 48 float touchMinor; 
 49 int down,up;
 50 
 51 using namespace android;  
 52   
 53 static SkBitmap::Config convertPixelFormat(PixelFormat format) {  
 54     /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then 
 55         we can map to SkBitmap::kARGB_8888_Config, and optionally call 
 56         bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator) 
 57     */  
 58     switch (format) {  
 59     case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;  
 60     case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;  
 61     case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;  
 62     case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;  
 63     case PIXEL_FORMAT_A_8:          return SkBitmap::kA8_Config;  
 64     default:                        return SkBitmap::kNo_Config;  
 65     }     
 66 }  
 67   
 68 int xScaleyScale(void)
 69 {
 70     sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient();  //创建SurfaceFlinger的本地代理
 71     DisplayInfo displayInfo;  
 72     //获取屏幕的宽高等信息
 73     surfaceComposerClient->getDisplayInfo(surfaceComposerClient->getBuiltInDisplay(HWC_DISPLAY_PRIMARY), &displayInfo); 
 74     xScale = displayInfo.w / 32768.0;
 75     yScale = displayInfo.h / 32768.0;
 76     
 77     /* 
 78     struct fb_var_screeninfo vinfo;
 79     // struct fb_fix_screeninfo finfo;
 80     
 81     int fd0 = open("/dev/graphics/fb0", O_RDWR);
 82     if(fd0 < 0)
 83     {
 84         perror("open");
 85         exit(1);
 86     }
 87     // Get variable screen information
 88     if (ioctl(fd0, FBIOGET_VSCREENINFO, &vinfo)) 
 89     {
 90         printf("Error reading variable information.\n");
 91         exit(1);
 92     }
 93     xScale = vinfo.xres / 32768;
 94     yScale = vinfo.yres / 32768;
 95     // printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
 96     close(fd0);
 97      */
 98     
 99     return 0;
100 }
101 
102 static int getTouchEventNum() //判断触摸框事件是哪一个event
103 {
104     char          name[64];           /* RATS: Use ok, but could be better */  
105     char          buf[256] = { 0, };  /* RATS: Use ok */  
106     int           fd = 0;   
107     int           i;    
108     for (i = 0; i < 32; i++) 
109     {  
110         sprintf(name, "/dev/input/event%d", i);  
111         if ((fd = open(name, O_RDONLY, 0)) >= 0) 
112         {  
113             ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);   
114             if(strstr(buf, "MTOUC Touch"))
115             {
116                 close(fd);
117                 return i;
118             }
119             //printf("%s\n", name);  
120             //printf("name: %s\n", buf);           
121             close(fd);  
122         }
123     }
124     return -1;
125 }
126 
127 static void* readInput(void *data)
128 {
129     struct input_event inputEvent;
130     while(1)
131     {
132         read(fd, &inputEvent, sizeof(struct input_event));
133         // 向管道中写数据
134         write(fds[1], &inputEvent, sizeof(struct input_event));
135     }
136     return NULL;
137 }
138 
139 static void* dispatchInput(void *data) 
140 {
141     struct input_event inputEvent;
142     int flag = 1;
143     while(1)
144     {
145         //从管道中读取数据
146         read(fds[0], &inputEvent, sizeof(struct input_event));
147         
148         if(inputEvent.type == EV_ABS && inputEvent.code == ABS_X ){
149             float fv = inputEvent.value * 1.0;
150             x = fv * xScale;
151             continue;
152         }
153         if(inputEvent.type == EV_ABS && inputEvent.code == ABS_Y ){
154              float fv = inputEvent.value * 1.0;
155              y = fv * yScale;
156              continue;
157         }
158         if(inputEvent.type == EV_KEY && inputEvent.code == BTN_TOUCH ){
159             pressure = inputEvent.value;
160             if(1 == pressure )
161             {
162                 down = 1;
163                 up = 0;
164             }
165             else if(0 == pressure)
166             {
167                 up  = 1;
168                 down = 0;
169             }
170             continue;
171         }
172         //增加flag的判断作用是touchMajor和toushMinor事件在pressure事件之前的比较准确
173         if(inputEvent.type == EV_ABS && inputEvent.code == ABS_MT_TOUCH_MAJOR /*&& flag*/ ){
174              float fv = inputEvent.value * 1.0;
175              touchMajor = fv * 10; //10  = 0x4000 / 1920
176              continue;
177         }
178         if(inputEvent.type == EV_ABS && inputEvent.code == ABS_MT_TOUCH_MINOR /*&& flag */){
179             float fv = inputEvent.value * 1.0;
180             touchMinor = fv * 15;  //18  15 = 0x4000 / 1080;
181             continue;
182         }
183     }
184     return NULL;
185 }
186 
187 int initInput(void)
188 {
189     int num = getTouchEventNum();
190     if( num == -1)
191     {
192         printf("No Touch Event\n");
193         return -1;
194     }
195     char name[64];
196     sprintf(name, "/dev/input/event%d", num);
197     fd = open(name, O_RDWR);
198     if(fd < 0)
199     {
200         //LOGI("Open dev Error");
201         return fd;
202     }
203     
204     xScaleyScale();//初始化xy坐标的比例关系
205     
206     //创建无名管道
207     if(-1 == pipe(fds))
208     {
209         printf("pipe\n");
210         exit(-1);
211     }
212     
213     pthread_t readId, disPatchId; 
214     pthread_create(&readId, NULL, readInput, NULL);
215     ///sleep(1);
216     pthread_create(&disPatchId, NULL, dispatchInput, NULL);
217 
218     return fd;
219 }
220 
221 float getX(void)
222 {
223     return x;
224 }
225 
226 float getY(void)
227 {
228     return y;
229 }
230 
231 float getW(void)
232 {
233     return touchMajor;
234 }
235 
236 float getH(void)
237 {
238     return touchMinor;
239 }
240   
241 int getDown(void)
242 {
243     return down;
244 }
245 
246 int getUp(void)
247 {
248     return up;
249 }
250 
251 typedef struct
252 {
253     float x;
254     float y;
255 } Point2D;
256 /* cp 在此是四个元素的数组:
257 cp[0] 为起点,或上图中的 P0
258 cp[1] 为第一控制点,或上图中的 P1
259 cp[2] 为第二控制点,或上图中的 P2
260 cp[3] 为结束点,或上图中的 P3
261 t 为参数值,0 <= t <= 1 */
262 Point2D PointOnCubicBezier( Point2D* cp, float t )
263 {
264     float ax, bx, cx; float ay, by, cy;
265     float tSquared, tCubed; Point2D result;
266     /* 计算多项式系数 */
267     cx = 3.0 * (cp[1].x - cp[0].x);
268     bx = 3.0 * (cp[2].x - cp[1].x) - cx;
269     ax = cp[3].x - cp[0].x - cx - bx;
270     cy = 3.0 * (cp[1].y - cp[0].y);
271     by = 3.0 * (cp[2].y - cp[1].y) - cy;
272     ay = cp[3].y - cp[0].y - cy - by;
273     /* 计算t位置的点值 */
274     tSquared = t * t;
275     tCubed = tSquared * t;
276     result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
277     result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
278     return result;
279 }
280 /* ComputeBezier 以控制点 cp 所产生的曲线点,填入 Point2D 结构数组。
281 调用方必须分配足够的空间以供输出,<sizeof(Point2D) numberOfPoints> */
282 void ComputeBezier( Point2D* cp, int numberOfPoints, Point2D* curve )
283 {
284     float dt; int i;
285     dt = 1.0 / ( numberOfPoints - 1 );
286     for( i = 0; i < numberOfPoints; i++)
287         curve[i] = PointOnCubicBezier( cp, i*dt );
288 }
289 
290 int main(int argc, char** argv)  
291 {  
292     // set up the thread-pool  
293     //sp<ProcessState> proc(ProcessState::self());  
294     //ProcessState::self()->startThreadPool();  
295   
296     initInput();
297   
298     // create a client to surfaceflinger  
299     sp<SurfaceComposerClient> client = new SurfaceComposerClient();  //创建SurfaceFlinger的本地代理
300     
301     DisplayInfo display;  
302     //获取屏幕的宽高等信息
303     client->getDisplayInfo(client->getBuiltInDisplay(HWC_DISPLAY_PRIMARY), &display); 
304     char str[80];
305     sprintf(str,"w=%d,h=%d,xdpi=%f,ydpi=%f,fps=%f,ds=%f,fmt=%d\n",
306                 display.w, display.h, display.xdpi, display.ydpi, 
307                 display.fps, display.density, display.pixelFormatInfo.format);  
308     //创建SurfaceControl的本地代理
309     sp<SurfaceControl> surfaceControl = client->createSurface(String8("testsurface"), 
310         1920/*240*/, 1080/*160*/, PIXEL_FORMAT_RGBA_8888, 0);  
311                        
312     /*********************************************************************/
313     SurfaceComposerClient::openGlobalTransaction();  
314     surfaceControl->setLayer(100000); //设置z轴     
315     surfaceControl->setSize(display.w, display.h);  
316     surfaceControl->setPosition(0, 0);  //起始位置 
317     SurfaceComposerClient::closeGlobalTransaction();
318     // 获取Surface本地代理
319     sp<Surface> surface = surfaceControl->getSurface();//获取surface
320     Surface::SurfaceInfo info;  
321     
322     //创建SurfaceControl的本地代理
323     sp<SurfaceControl> surfaceControl1 = client->createSurface(String8("wenfu"), 
324         display.w, display.h, PIXEL_FORMAT_RGBA_8888, 0);  
325     SurfaceComposerClient::openGlobalTransaction();  
326     surfaceControl1->setLayer(90000); //设置z轴     
327     surfaceControl1->setSize(display.w, display.h);  
328     surfaceControl1->setPosition(0, 0);  //起始位置 
329     SurfaceComposerClient::closeGlobalTransaction();
330     // 获取Surface本地代理
331     sp<Surface> surface1 = surfaceControl1->getSurface();//获取surface
332     Surface::SurfaceInfo info1;  
333     
334     ssize_t bpr ;
335     SkBitmap bitmap;         
336     SkCanvas canvas ;
337     SkCanvas canvas1;
338     SkBitmap bitmap1; 
339     SkPath path;
340     SkPaint paint;  //paint可以指定绘图的颜色,文本的大小及对齐方式,编码格式
341     SkPaint paint1; 
342     SkRect rect;
343     int sx,sy;
344     int w,h;
345     int flg = 1;
346     int flg2 = 0;
347     int lastx = 0, lasty = 0, ctrx = 0, ctry = 0;
348     int TOUCH_TOLERANCE = 4; //只有当移动的距离大于4px时,才在屏幕上绘图 
349     
350     SkFILEStream stream("./5.jpg");  
351     SkImageDecoder* codec = SkImageDecoder::Factory(&stream);  
352     SkBitmap bmp;  
353     if(codec){  
354         stream.rewind();  //将文件指针指向文件开头
355         codec->decode(&stream, &bmp, SkBitmap::kARGB_8888_Config, SkImageDecoder::kDecodePixels_Mode);          
356         surface1->lock(&info1);  
357             bpr = info1.s * bytesPerPixel(info1.format);  
358             bitmap1.setConfig(convertPixelFormat(info1.format), display.w, display.h, bpr);  
359             bitmap1.setPixels(info1.bits);  
360             //dev = new SkDevice(bitmap);  
361             canvas1.setDevice(new SkDevice(bitmap1));    
362             canvas1.drawBitmap(bmp, SkIntToScalar(0), SkIntToScalar(0));  //从0,0点开始画图
363         surface1->unlockAndPost();   
364     }/*
365     surface->lock(&info);  
366         bpr = info.s * bytesPerPixel(info.format);  
367         android_memset32((uint32_t*)info.bits, 0xFFFFFFFF, bpr*info.h);  
368     surface->unlockAndPost(); */
369     
370     int erase = 0;
371     int ew,eh;
372     
373     while(1)
374     {    
375         if(getDown())
376         {
377             if(flg) //按下
378             {
379                 flg = 0;
380                 flg2 = 1;    
381                 
382                 if(getW() > 80)
383                 {
384                     erase = 1;
385                     ew = getW();
386                     eh = getH();
387                 }
388                 else
389                 {
390                     path.reset();  
391                     //获取坐标
392                     ctrx = getX();
393                     ctry = getY();
394                     path.moveTo(ctrx, ctry);  
395                     lastx = ctrx;  
396                     lasty = ctry;
397                 }
398             }
399             else //移动
400             {    
401                     ctrx = getX();  
402                     ctry = getY(); 
403                     float dx = abs(ctrx - lastx);  
404                     float dy = abs(ctry - lasty);  
405                     //两点之间的距离大于等于4时,生成贝塞尔绘制曲线  
406                     if (dx >= 3 || dy >= 3) 
407                     {  
408                         //设置贝塞尔曲线的操作点为起点和终点的一半  
409                         float cX = (ctrx + lastx) / 2;  
410                         float cY = (ctry + lasty) / 2;  
411                         //二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点  
412                         //path.quadTo(lastx, lasty, cX, cY);  
413                         path.quadTo(lastx, lasty, cX, cY);
414                     }
415                     surface->lock(&info);
416                         bpr = info.s * bytesPerPixel(info.format);  
417                         bitmap.setConfig(convertPixelFormat(info.format), display.w, display.h, bpr);  
418                         bitmap.setPixels(info.bits);
419                         paint.setDither(true); //去抖动
420                         paint.setAntiAlias(true); //抗锯齿
421                         canvas.setDevice(new SkDevice(bitmap));    
422                         if(!erase)
423                         {
424                             paint.setARGB(255, 255, 0, 0); //画笔颜色
425                             paint.setStrokeWidth(10); //画笔宽度
426                             paint.setStyle(SkPaint::kStroke_Style); //空心
427                             canvas.drawPath(path, paint); 
428                         }
429                         else
430                         {
431                             paint.setARGB(255, 255, 255, 255); //画笔颜色
432                             paint.setStyle(SkPaint::kFill_Style); //实心
433                             canvas.drawRect(SkRect::MakeXYWH(ctrx - ew/2, ctry - eh/2, ctrx + ew/2,ctry + eh/2), paint); 
434                         }
435                     surface->unlockAndPost();
436                     surface->lock(&info);
437                         bpr = info.s * bytesPerPixel(info.format);  
438                         bitmap.setConfig(convertPixelFormat(info.format), display.w, display.h, bpr);  
439                         bitmap.setPixels(info.bits);
440                         paint.setDither(true); //去抖动
441                         paint.setAntiAlias(true); //抗锯齿
442                         canvas.setDevice(new SkDevice(bitmap));    
443                         if(!erase)
444                         {
445                             paint.setARGB(255, 255, 0, 0); //画笔颜色
446                             paint.setStrokeWidth(10); //画笔宽度
447                             paint.setStyle(SkPaint::kStroke_Style); //空心
448                             canvas.drawPath(path, paint); 
449                         }
450                         else
451                         {
452                             paint.setARGB(255, 255, 255, 255); //画笔颜色
453                             paint.setStyle(SkPaint::kFill_Style); //实心
454                             canvas.drawRect(SkRect::MakeXYWH(ctrx - ew/2, ctry - eh/2, ctrx + ew/2,ctry + eh/2), paint); 
455                         }
456                     surface->unlockAndPost();
457                     
458                     lastx = ctrx;
459                     lasty = ctry;
460             }    
461         }
462         else if(getUp()) //抬起
463         {
464             flg = 1;
465             if(flg2)
466             {    
467                 flg2 = 0;
468                 erase = 0;
469             }                
470         }    
471     }
472     //IPCThreadState::self()->joinThreadPool();        
473     //IPCThreadState::self()->stopProcess();  
474     return 0;  
475 }
View Code

以上是C++代码,功能结果如上图所示,mk文件:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_C_INCLUDES := $(call include-path-for, corecg graphics)
LOCAL_C_INCLUDES += external/skia/include/core
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/core
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/images
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/images
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/core
LOCAL_C_INCLUDES += $(INCLUDES)

LOCAL_SRC_FILES:= \
    Surface.cpp \
    src/core/SkBitmap.cpp \
    src/core/SkDevice.cpp \
    src/core/SkPaint.cpp \
    src/core/SkRect.cpp \
    src/core/SkTypeface.cpp \
    src/images/SkImageEncoder.cpp \
    src/core/SkCanvas.cpp \
    main.cpp
    
 
LOCAL_SHARED_LIBRARIES:= \
    libcutils \
    libutils \
    libbinder \
    libui \
    libgui \
    libskia \
    libandroidfw \
    libEGL \
    libGLESv1_CM \
    libGLESv2    
 
LOCAL_MODULE:= testsurface

LOCAL_STATIC_LIBRARIES := libskiagpu

LOCAL_MODULE_TAGS := eng tests  

include $(BUILD_EXECUTABLE)

文件比较多,不过都是在android源码里面有,可以找到。

 

posted @ 2016-07-26 17:43  winfu  阅读(1240)  评论(0编辑  收藏  举报