waveshare_epaper

Waveshare e-paper display shenanigans
git clone git://bsandro.tech/waveshare_epaper
Log | Files | Refs | README

GUI_Paint.c (32007B)


      1 /******************************************************************************
      2 * | File      	:   GUI_Paint.c
      3 * | Author      :   Waveshare electronics
      4 * | Function    :	Achieve drawing: draw points, lines, boxes, circles and
      5 *                   their size, solid dotted line, solid rectangle hollow
      6 *                   rectangle, solid circle hollow circle.
      7 * | Info        :
      8 *   Achieve display characters: Display a single character, string, number
      9 *   Achieve time display: adaptive size display time minutes and seconds
     10 *----------------
     11 * |	This version:   V3.2
     12 * | Date        :   2020-07-10
     13 * | Info        :
     14 * -----------------------------------------------------------------------------
     15 * V3.2(2020-07-10):
     16 * 1.Change: Paint_SetScale(UBYTE scale)
     17 *		 Add scale 7 for 5.65f e-Parper
     18 * 2.Change: Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color)
     19 *		 Add the branch for scale 7
     20 * 3.Change: Paint_Clear(UWORD Color)
     21 *		 Add the branch for scale 7
     22 * -----------------------------------------------------------------------------
     23 * V3.1(2019-10-10):
     24 * 1. Add gray level
     25 *   PAINT Add Scale
     26 * 2. Add void Paint_SetScale(UBYTE scale);
     27 * -----------------------------------------------------------------------------
     28 * V3.0(2019-04-18):
     29 * 1.Change: 
     30 *    Paint_DrawPoint(..., DOT_STYLE DOT_STYLE)
     31 * => Paint_DrawPoint(..., DOT_STYLE Dot_Style)
     32 *    Paint_DrawLine(..., LINE_STYLE Line_Style, DOT_PIXEL Dot_Pixel)
     33 * => Paint_DrawLine(..., DOT_PIXEL Line_width, LINE_STYLE Line_Style)
     34 *    Paint_DrawRectangle(..., DRAW_FILL Filled, DOT_PIXEL Dot_Pixel)
     35 * => Paint_DrawRectangle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
     36 *    Paint_DrawCircle(..., DRAW_FILL Draw_Fill, DOT_PIXEL Dot_Pixel)
     37 * => Paint_DrawCircle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Filll)
     38 *
     39 * -----------------------------------------------------------------------------
     40 * V2.0(2018-11-15):
     41 * 1.add: Paint_NewImage()
     42 *    Create an image's properties
     43 * 2.add: Paint_SelectImage()
     44 *    Select the picture to be drawn
     45 * 3.add: Paint_SetRotate()
     46 *    Set the direction of the cache    
     47 * 4.add: Paint_RotateImage() 
     48 *    Can flip the picture, Support 0-360 degrees, 
     49 *    but only 90.180.270 rotation is better
     50 * 4.add: Paint_SetMirroring() 
     51 *    Can Mirroring the picture, horizontal, vertical, origin
     52 * 5.add: Paint_DrawString_CN() 
     53 *    Can display Chinese(GB1312)   
     54 *
     55 * ----------------------------------------------------------------------------- 
     56 * V1.0(2018-07-17):
     57 *   Create library
     58 *
     59 * Permission is hereby granted, free of charge, to any person obtaining a copy
     60 * of this software and associated documnetation files (the "Software"), to deal
     61 * in the Software without restriction, including without limitation the rights
     62 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     63 * copies of the Software, and to permit persons to  whom the Software is
     64 * furished to do so, subject to the following conditions:
     65 *
     66 * The above copyright notice and this permission notice shall be included in
     67 * all copies or substantial portions of the Software.
     68 *
     69 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     70 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     71 * FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     72 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     73 * LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     74 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     75 * THE SOFTWARE.
     76 *
     77 ******************************************************************************/
     78 #include "GUI_Paint.h"
     79 #include "DEV_Config.h"
     80 #include "Debug.h"
     81 #include <stdint.h>
     82 #include <stdlib.h>
     83 #include <string.h> //memset()
     84 #include <math.h>
     85 
     86 PAINT Paint;
     87 
     88 /******************************************************************************
     89 function: Create Image
     90 parameter:
     91     image   :   Pointer to the image cache
     92     width   :   The width of the picture
     93     Height  :   The height of the picture
     94     Color   :   Whether the picture is inverted
     95 ******************************************************************************/
     96 void Paint_NewImage(UBYTE *image, UWORD Width, UWORD Height, UWORD Rotate, UWORD Color)
     97 {
     98     Paint.Image = NULL;
     99     Paint.Image = image;
    100 
    101     Paint.WidthMemory = Width;
    102     Paint.HeightMemory = Height;
    103     Paint.Color = Color;    
    104     Paint.Scale = 2;
    105     Paint.WidthByte = (Width % 8 == 0)? (Width / 8 ): (Width / 8 + 1);
    106     Paint.HeightByte = Height;    
    107 //    printf("WidthByte = %d, HeightByte = %d\r\n", Paint.WidthByte, Paint.HeightByte);
    108 //    printf(" EPD_WIDTH / 8 = %d\r\n",  122 / 8);
    109    
    110     Paint.Rotate = Rotate;
    111     Paint.Mirror = MIRROR_NONE;
    112     
    113     if(Rotate == ROTATE_0 || Rotate == ROTATE_180) {
    114         Paint.Width = Width;
    115         Paint.Height = Height;
    116     } else {
    117         Paint.Width = Height;
    118         Paint.Height = Width;
    119     }
    120 }
    121 
    122 /******************************************************************************
    123 function: Select Image
    124 parameter:
    125     image : Pointer to the image cache
    126 ******************************************************************************/
    127 void Paint_SelectImage(UBYTE *image)
    128 {
    129     Paint.Image = image;
    130 }
    131 
    132 /******************************************************************************
    133 function: Select Image Rotate
    134 parameter:
    135     Rotate : 0,90,180,270
    136 ******************************************************************************/
    137 void Paint_SetRotate(UWORD Rotate)
    138 {
    139     if(Rotate == ROTATE_0 || Rotate == ROTATE_90 || Rotate == ROTATE_180 || Rotate == ROTATE_270) {
    140         Debug("Set image Rotate %d\r\n", Rotate);
    141         Paint.Rotate = Rotate;
    142     } else {
    143         Debug("rotate = 0, 90, 180, 270\r\n");
    144     }
    145 }
    146 
    147 /******************************************************************************
    148 function:	Select Image mirror
    149 parameter:
    150     mirror   :Not mirror,Horizontal mirror,Vertical mirror,Origin mirror
    151 ******************************************************************************/
    152 void Paint_SetMirroring(UBYTE mirror)
    153 {
    154     if(mirror == MIRROR_NONE || mirror == MIRROR_HORIZONTAL || 
    155         mirror == MIRROR_VERTICAL || mirror == MIRROR_ORIGIN) {
    156         Debug("mirror image x:%s, y:%s\r\n",(mirror & 0x01)? "mirror":"none", ((mirror >> 1) & 0x01)? "mirror":"none");
    157         Paint.Mirror = mirror;
    158     } else {
    159         Debug("mirror should be MIRROR_NONE, MIRROR_HORIZONTAL, \
    160         MIRROR_VERTICAL or MIRROR_ORIGIN\r\n");
    161     }    
    162 }
    163 
    164 void Paint_SetScale(UBYTE scale)
    165 {
    166     if(scale == 2){
    167         Paint.Scale = scale;
    168         Paint.WidthByte = (Paint.WidthMemory % 8 == 0)? (Paint.WidthMemory / 8 ): (Paint.WidthMemory / 8 + 1);
    169     }else if(scale == 4){
    170         Paint.Scale = scale;
    171         Paint.WidthByte = (Paint.WidthMemory % 4 == 0)? (Paint.WidthMemory / 4 ): (Paint.WidthMemory / 4 + 1);
    172     }else if(scale == 7){//Only applicable with 5in65 e-Paper
    173 		Paint.Scale = scale;
    174 		Paint.WidthByte = (Paint.WidthMemory % 2 == 0)? (Paint.WidthMemory / 2 ): (Paint.WidthMemory / 2 + 1);;
    175 	}else{
    176         Debug("Set Scale Input parameter error\r\n");
    177         Debug("Scale Only support: 2 4 7\r\n");
    178     }
    179 }
    180 /******************************************************************************
    181 function: Draw Pixels
    182 parameter:
    183     Xpoint : At point X
    184     Ypoint : At point Y
    185     Color  : Painted colors
    186 ******************************************************************************/
    187 void Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color)
    188 {
    189     if(Xpoint > Paint.Width || Ypoint > Paint.Height){
    190         Debug("Exceeding display boundaries\r\n");
    191         return;
    192     }      
    193     UWORD X, Y;
    194     switch(Paint.Rotate) {
    195     case 0:
    196         X = Xpoint;
    197         Y = Ypoint;  
    198         break;
    199     case 90:
    200         X = Paint.WidthMemory - Ypoint - 1;
    201         Y = Xpoint;
    202         break;
    203     case 180:
    204         X = Paint.WidthMemory - Xpoint - 1;
    205         Y = Paint.HeightMemory - Ypoint - 1;
    206         break;
    207     case 270:
    208         X = Ypoint;
    209         Y = Paint.HeightMemory - Xpoint - 1;
    210         break;
    211     default:
    212         return;
    213     }
    214     
    215     switch(Paint.Mirror) {
    216     case MIRROR_NONE:
    217         break;
    218     case MIRROR_HORIZONTAL:
    219         X = Paint.WidthMemory - X - 1;
    220         break;
    221     case MIRROR_VERTICAL:
    222         Y = Paint.HeightMemory - Y - 1;
    223         break;
    224     case MIRROR_ORIGIN:
    225         X = Paint.WidthMemory - X - 1;
    226         Y = Paint.HeightMemory - Y - 1;
    227         break;
    228     default:
    229         return;
    230     }
    231 
    232     if(X > Paint.WidthMemory || Y > Paint.HeightMemory){
    233         Debug("Exceeding display boundaries\r\n");
    234         return;
    235     }
    236     
    237     if(Paint.Scale == 2){
    238         UDOUBLE Addr = X / 8 + Y * Paint.WidthByte;
    239         UBYTE Rdata = Paint.Image[Addr];
    240         if(Color == BLACK)
    241             Paint.Image[Addr] = Rdata & ~(0x80 >> (X % 8));
    242         else
    243             Paint.Image[Addr] = Rdata | (0x80 >> (X % 8));
    244     }else if(Paint.Scale == 4){
    245         UDOUBLE Addr = X / 4 + Y * Paint.WidthByte;
    246         Color = Color % 4;//Guaranteed color scale is 4  --- 0~3
    247         UBYTE Rdata = Paint.Image[Addr];
    248         
    249         Rdata = Rdata & (~(0xC0 >> ((X % 4)*2)));//Clear first, then set value
    250         Paint.Image[Addr] = Rdata | ((Color << 6) >> ((X % 4)*2));
    251     }else if(Paint.Scale == 7){
    252 		UDOUBLE Addr = X / 2  + Y * Paint.WidthByte;
    253 		UBYTE Rdata = Paint.Image[Addr];
    254 		Rdata = Rdata & (~(0xF0 >> ((X % 2)*4)));//Clear first, then set value
    255 		Paint.Image[Addr] = Rdata | ((Color << 4) >> ((X % 2)*4));
    256 		// printf("Add =  %d ,data = %d\r\n",Addr,Rdata);
    257 	}
    258 }
    259 
    260 /******************************************************************************
    261 function: Clear the color of the picture
    262 parameter:
    263     Color : Painted colors
    264 ******************************************************************************/
    265 void Paint_Clear(UWORD Color)
    266 {	
    267 	if(Paint.Scale == 2 || Paint.Scale == 4){
    268 		for (UWORD Y = 0; Y < Paint.HeightByte; Y++) {
    269 			for (UWORD X = 0; X < Paint.WidthByte; X++ ) {//8 pixel =  1 byte
    270 				UDOUBLE Addr = X + Y*Paint.WidthByte;
    271 				Paint.Image[Addr] = Color;
    272 			}
    273 		}		
    274 	}else if(Paint.Scale == 7){
    275 		for (UWORD Y = 0; Y < Paint.HeightByte; Y++) {
    276 			for (UWORD X = 0; X < Paint.WidthByte; X++ ) {
    277 				UDOUBLE Addr = X + Y*Paint.WidthByte;
    278 				Paint.Image[Addr] = (Color<<4)|Color;
    279 			}
    280 		}		
    281 	}
    282 
    283 }
    284 
    285 /******************************************************************************
    286 function: Clear the color of a window
    287 parameter:
    288     Xstart : x starting point
    289     Ystart : Y starting point
    290     Xend   : x end point
    291     Yend   : y end point
    292     Color  : Painted colors
    293 ******************************************************************************/
    294 void Paint_ClearWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color)
    295 {
    296     UWORD X, Y;
    297     for (Y = Ystart; Y < Yend; Y++) {
    298         for (X = Xstart; X < Xend; X++) {//8 pixel =  1 byte
    299             Paint_SetPixel(X, Y, Color);
    300         }
    301     }
    302 }
    303 
    304 /******************************************************************************
    305 function: Draw Point(Xpoint, Ypoint) Fill the color
    306 parameter:
    307     Xpoint		: The Xpoint coordinate of the point
    308     Ypoint		: The Ypoint coordinate of the point
    309     Color		: Painted color
    310     Dot_Pixel	: point size
    311     Dot_Style	: point Style
    312 ******************************************************************************/
    313 void Paint_DrawPoint(UWORD Xpoint, UWORD Ypoint, UWORD Color,
    314                      DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_Style)
    315 {
    316     if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
    317         Debug("Paint_DrawPoint Input exceeds the normal display range\r\n");
    318         return;
    319     }
    320 
    321     int16_t XDir_Num , YDir_Num;
    322     if (Dot_Style == DOT_FILL_AROUND) {
    323         for (XDir_Num = 0; XDir_Num < 2 * Dot_Pixel - 1; XDir_Num++) {
    324             for (YDir_Num = 0; YDir_Num < 2 * Dot_Pixel - 1; YDir_Num++) {
    325                 if(Xpoint + XDir_Num - Dot_Pixel < 0 || Ypoint + YDir_Num - Dot_Pixel < 0)
    326                     break;
    327                 // printf("x = %d, y = %d\r\n", Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel);
    328                 Paint_SetPixel(Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel, Color);
    329             }
    330         }
    331     } else {
    332         for (XDir_Num = 0; XDir_Num <  Dot_Pixel; XDir_Num++) {
    333             for (YDir_Num = 0; YDir_Num <  Dot_Pixel; YDir_Num++) {
    334                 Paint_SetPixel(Xpoint + XDir_Num - 1, Ypoint + YDir_Num - 1, Color);
    335             }
    336         }
    337     }
    338 }
    339 
    340 /******************************************************************************
    341 function: Draw a line of arbitrary slope
    342 parameter:
    343     Xstart :Starting Xpoint point coordinates
    344     Ystart :Starting Xpoint point coordinates
    345     Xend   :End point Xpoint coordinate
    346     Yend   :End point Ypoint coordinate
    347     Color  :The color of the line segment
    348     Line_width : Line width
    349     Line_Style: Solid and dotted lines
    350 ******************************************************************************/
    351 void Paint_DrawLine(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend,
    352                     UWORD Color, DOT_PIXEL Line_width, LINE_STYLE Line_Style)
    353 {
    354     if (Xstart > Paint.Width || Ystart > Paint.Height ||
    355         Xend > Paint.Width || Yend > Paint.Height) {
    356         Debug("Paint_DrawLine Input exceeds the normal display range\r\n");
    357         return;
    358     }
    359 
    360     UWORD Xpoint = Xstart;
    361     UWORD Ypoint = Ystart;
    362     int dx = (int)Xend - (int)Xstart >= 0 ? Xend - Xstart : Xstart - Xend;
    363     int dy = (int)Yend - (int)Ystart <= 0 ? Yend - Ystart : Ystart - Yend;
    364 
    365     // Increment direction, 1 is positive, -1 is counter;
    366     int XAddway = Xstart < Xend ? 1 : -1;
    367     int YAddway = Ystart < Yend ? 1 : -1;
    368 
    369     //Cumulative error
    370     int Esp = dx + dy;
    371     char Dotted_Len = 0;
    372 
    373     for (;;) {
    374         Dotted_Len++;
    375         //Painted dotted line, 2 point is really virtual
    376         if (Line_Style == LINE_STYLE_DOTTED && Dotted_Len % 3 == 0) {
    377             //Debug("LINE_DOTTED\r\n");
    378             Paint_DrawPoint(Xpoint, Ypoint, IMAGE_BACKGROUND, Line_width, DOT_STYLE_DFT);
    379             Dotted_Len = 0;
    380         } else {
    381             Paint_DrawPoint(Xpoint, Ypoint, Color, Line_width, DOT_STYLE_DFT);
    382         }
    383         if (2 * Esp >= dy) {
    384             if (Xpoint == Xend)
    385                 break;
    386             Esp += dy;
    387             Xpoint += XAddway;
    388         }
    389         if (2 * Esp <= dx) {
    390             if (Ypoint == Yend)
    391                 break;
    392             Esp += dx;
    393             Ypoint += YAddway;
    394         }
    395     }
    396 }
    397 
    398 /******************************************************************************
    399 function: Draw a rectangle
    400 parameter:
    401     Xstart :Rectangular  Starting Xpoint point coordinates
    402     Ystart :Rectangular  Starting Xpoint point coordinates
    403     Xend   :Rectangular  End point Xpoint coordinate
    404     Yend   :Rectangular  End point Ypoint coordinate
    405     Color  :The color of the Rectangular segment
    406     Line_width: Line width
    407     Draw_Fill : Whether to fill the inside of the rectangle
    408 ******************************************************************************/
    409 void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend,
    410                          UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
    411 {
    412     if (Xstart > Paint.Width || Ystart > Paint.Height ||
    413         Xend > Paint.Width || Yend > Paint.Height) {
    414         Debug("Input exceeds the normal display range\r\n");
    415         return;
    416     }
    417 
    418     if (Draw_Fill) {
    419         UWORD Ypoint;
    420         for(Ypoint = Ystart; Ypoint < Yend; Ypoint++) {
    421             Paint_DrawLine(Xstart, Ypoint, Xend, Ypoint, Color , Line_width, LINE_STYLE_SOLID);
    422         }
    423     } else {
    424         Paint_DrawLine(Xstart, Ystart, Xend, Ystart, Color, Line_width, LINE_STYLE_SOLID);
    425         Paint_DrawLine(Xstart, Ystart, Xstart, Yend, Color, Line_width, LINE_STYLE_SOLID);
    426         Paint_DrawLine(Xend, Yend, Xend, Ystart, Color, Line_width, LINE_STYLE_SOLID);
    427         Paint_DrawLine(Xend, Yend, Xstart, Yend, Color, Line_width, LINE_STYLE_SOLID);
    428     }
    429 }
    430 
    431 /******************************************************************************
    432 function: Use the 8-point method to draw a circle of the
    433             specified size at the specified position->
    434 parameter:
    435     X_Center  :Center X coordinate
    436     Y_Center  :Center Y coordinate
    437     Radius    :circle Radius
    438     Color     :The color of the :circle segment
    439     Line_width: Line width
    440     Draw_Fill : Whether to fill the inside of the Circle
    441 ******************************************************************************/
    442 void Paint_DrawCircle(UWORD X_Center, UWORD Y_Center, UWORD Radius,
    443                       UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
    444 {
    445     if (X_Center > Paint.Width || Y_Center >= Paint.Height) {
    446         Debug("Paint_DrawCircle Input exceeds the normal display range\r\n");
    447         return;
    448     }
    449 
    450     //Draw a circle from(0, R) as a starting point
    451     int16_t XCurrent, YCurrent;
    452     XCurrent = 0;
    453     YCurrent = Radius;
    454 
    455     //Cumulative error,judge the next point of the logo
    456     int16_t Esp = 3 - (Radius << 1 );
    457 
    458     int16_t sCountY;
    459     if (Draw_Fill == DRAW_FILL_FULL) {
    460         while (XCurrent <= YCurrent ) { //Realistic circles
    461             for (sCountY = XCurrent; sCountY <= YCurrent; sCountY ++ ) {
    462                 Paint_DrawPoint(X_Center + XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//1
    463                 Paint_DrawPoint(X_Center - XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//2
    464                 Paint_DrawPoint(X_Center - sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//3
    465                 Paint_DrawPoint(X_Center - sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//4
    466                 Paint_DrawPoint(X_Center - XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//5
    467                 Paint_DrawPoint(X_Center + XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//6
    468                 Paint_DrawPoint(X_Center + sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//7
    469                 Paint_DrawPoint(X_Center + sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    470             }
    471             if (Esp < 0 )
    472                 Esp += 4 * XCurrent + 6;
    473             else {
    474                 Esp += 10 + 4 * (XCurrent - YCurrent );
    475                 YCurrent --;
    476             }
    477             XCurrent ++;
    478         }
    479     } else { //Draw a hollow circle
    480         while (XCurrent <= YCurrent ) {
    481             Paint_DrawPoint(X_Center + XCurrent, Y_Center + YCurrent, Color, Line_width, DOT_STYLE_DFT);//1
    482             Paint_DrawPoint(X_Center - XCurrent, Y_Center + YCurrent, Color, Line_width, DOT_STYLE_DFT);//2
    483             Paint_DrawPoint(X_Center - YCurrent, Y_Center + XCurrent, Color, Line_width, DOT_STYLE_DFT);//3
    484             Paint_DrawPoint(X_Center - YCurrent, Y_Center - XCurrent, Color, Line_width, DOT_STYLE_DFT);//4
    485             Paint_DrawPoint(X_Center - XCurrent, Y_Center - YCurrent, Color, Line_width, DOT_STYLE_DFT);//5
    486             Paint_DrawPoint(X_Center + XCurrent, Y_Center - YCurrent, Color, Line_width, DOT_STYLE_DFT);//6
    487             Paint_DrawPoint(X_Center + YCurrent, Y_Center - XCurrent, Color, Line_width, DOT_STYLE_DFT);//7
    488             Paint_DrawPoint(X_Center + YCurrent, Y_Center + XCurrent, Color, Line_width, DOT_STYLE_DFT);//0
    489 
    490             if (Esp < 0 )
    491                 Esp += 4 * XCurrent + 6;
    492             else {
    493                 Esp += 10 + 4 * (XCurrent - YCurrent );
    494                 YCurrent --;
    495             }
    496             XCurrent ++;
    497         }
    498     }
    499 }
    500 
    501 /******************************************************************************
    502 function: Show English characters
    503 parameter:
    504     Xpoint           :X coordinate
    505     Ypoint           :Y coordinate
    506     Acsii_Char       :To display the English characters
    507     Font             :A structure pointer that displays a character size
    508     Color_Foreground : Select the foreground color
    509     Color_Background : Select the background color
    510 ******************************************************************************/
    511 void Paint_DrawChar(UWORD Xpoint, UWORD Ypoint, const char Acsii_Char,
    512                     sFONT* Font, UWORD Color_Foreground, UWORD Color_Background)
    513 {
    514     UWORD Page, Column;
    515 
    516     if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
    517         Debug("Paint_DrawChar Input exceeds the normal display range\r\n");
    518         return;
    519     }
    520 
    521     uint32_t Char_Offset = (Acsii_Char - ' ') * Font->Height * (Font->Width / 8 + (Font->Width % 8 ? 1 : 0));
    522     const unsigned char *ptr = &Font->table[Char_Offset];
    523 
    524     for (Page = 0; Page < Font->Height; Page ++ ) {
    525         for (Column = 0; Column < Font->Width; Column ++ ) {
    526 
    527             //To determine whether the font background color and screen background color is consistent
    528             if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
    529                 if (*ptr & (0x80 >> (Column % 8)))
    530                     Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
    531                     // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    532             } else {
    533                 if (*ptr & (0x80 >> (Column % 8))) {
    534                     Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
    535                     // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    536                 } else {
    537                     Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Background);
    538                     // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    539                 }
    540             }
    541             //One pixel is 8 bits
    542             if (Column % 8 == 7)
    543                 ptr++;
    544         }// Write a line
    545         if (Font->Width % 8 != 0)
    546             ptr++;
    547     }// Write all
    548 }
    549 
    550 /******************************************************************************
    551 function:	Display the string
    552 parameter:
    553     Xstart           :X coordinate
    554     Ystart           :Y coordinate
    555     pString          :The first address of the English string to be displayed
    556     Font             :A structure pointer that displays a character size
    557     Color_Foreground : Select the foreground color
    558     Color_Background : Select the background color
    559 ******************************************************************************/
    560 void Paint_DrawString_EN(UWORD Xstart, UWORD Ystart, const char * pString,
    561                          sFONT* Font, UWORD Color_Foreground, UWORD Color_Background)
    562 {
    563     UWORD Xpoint = Xstart;
    564     UWORD Ypoint = Ystart;
    565 
    566     if (Xstart > Paint.Width || Ystart > Paint.Height) {
    567         Debug("Paint_DrawString_EN Input exceeds the normal display range\r\n");
    568         return;
    569     }
    570 
    571     while (* pString != '\0') {
    572         //if X direction filled , reposition to(Xstart,Ypoint),Ypoint is Y direction plus the Height of the character
    573         if ((Xpoint + Font->Width ) > Paint.Width ) {
    574             Xpoint = Xstart;
    575             Ypoint += Font->Height;
    576         }
    577 
    578         // If the Y direction is full, reposition to(Xstart, Ystart)
    579         if ((Ypoint  + Font->Height ) > Paint.Height ) {
    580             Xpoint = Xstart;
    581             Ypoint = Ystart;
    582         }
    583         Paint_DrawChar(Xpoint, Ypoint, * pString, Font, Color_Background, Color_Foreground);
    584 
    585         //The next character of the address
    586         pString ++;
    587 
    588         //The next word of the abscissa increases the font of the broadband
    589         Xpoint += Font->Width;
    590     }
    591 }
    592 
    593 
    594 /******************************************************************************
    595 function: Display the string
    596 parameter:
    597     Xstart  :X coordinate
    598     Ystart  :Y coordinate
    599     pString :The first address of the Chinese string and English
    600               string to be displayed
    601     Font    :A structure pointer that displays a character size
    602     Color_Foreground : Select the foreground color
    603     Color_Background : Select the background color
    604 ******************************************************************************/
    605 void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font,
    606                         UWORD Color_Foreground, UWORD Color_Background)
    607 {
    608     const char* p_text = pString;
    609     int x = Xstart, y = Ystart;
    610     int i, j,Num;
    611 
    612     /* Send the string character by character on EPD */
    613     while (*p_text != 0) {
    614         if(*p_text <= 0x7F) {  //ASCII < 126
    615             for(Num = 0; Num < font->size; Num++) {
    616                 if(*p_text== font->table[Num].index[0]) {
    617                     const char* ptr = &font->table[Num].matrix[0];
    618 
    619                     for (j = 0; j < font->Height; j++) {
    620                         for (i = 0; i < font->Width; i++) {
    621                             if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
    622                                 if (*ptr & (0x80 >> (i % 8))) {
    623                                     Paint_SetPixel(x + i, y + j, Color_Foreground);
    624                                     // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    625                                 }
    626                             } else {
    627                                 if (*ptr & (0x80 >> (i % 8))) {
    628                                     Paint_SetPixel(x + i, y + j, Color_Foreground);
    629                                     // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    630                                 } else {
    631                                     Paint_SetPixel(x + i, y + j, Color_Background);
    632                                     // Paint_DrawPoint(x + i, y + j, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    633                                 }
    634                             }
    635                             if (i % 8 == 7) {
    636                                 ptr++;
    637                             }
    638                         }
    639                         if (font->Width % 8 != 0) {
    640                             ptr++;
    641                         }
    642                     }
    643                     break;
    644                 }
    645             }
    646             /* Point on the next character */
    647             p_text += 1;
    648             /* Decrement the column position by 16 */
    649             x += font->ASCII_Width;
    650         } else {        //Chinese
    651             for(Num = 0; Num < font->size; Num++) {
    652                 if((*p_text== font->table[Num].index[0]) && (*(p_text+1) == font->table[Num].index[1])) {
    653                     const char* ptr = &font->table[Num].matrix[0];
    654 
    655                     for (j = 0; j < font->Height; j++) {
    656                         for (i = 0; i < font->Width; i++) {
    657                             if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
    658                                 if (*ptr & (0x80 >> (i % 8))) {
    659                                     Paint_SetPixel(x + i, y + j, Color_Foreground);
    660                                     // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    661                                 }
    662                             } else {
    663                                 if (*ptr & (0x80 >> (i % 8))) {
    664                                     Paint_SetPixel(x + i, y + j, Color_Foreground);
    665                                     // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    666                                 } else {
    667                                     Paint_SetPixel(x + i, y + j, Color_Background);
    668                                     // Paint_DrawPoint(x + i, y + j, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
    669                                 }
    670                             }
    671                             if (i % 8 == 7) {
    672                                 ptr++;
    673                             }
    674                         }
    675                         if (font->Width % 8 != 0) {
    676                             ptr++;
    677                         }
    678                     }
    679                     break;
    680                 }
    681             }
    682             /* Point on the next character */
    683             p_text += 2;
    684             /* Decrement the column position by 16 */
    685             x += font->Width;
    686         }
    687     }
    688 }
    689 
    690 /******************************************************************************
    691 function:	Display nummber
    692 parameter:
    693     Xstart           :X coordinate
    694     Ystart           : Y coordinate
    695     Nummber          : The number displayed
    696     Font             :A structure pointer that displays a character size
    697     Color_Foreground : Select the foreground color
    698     Color_Background : Select the background color
    699 ******************************************************************************/
    700 #define  ARRAY_LEN 255
    701 void Paint_DrawNum(UWORD Xpoint, UWORD Ypoint, int32_t Nummber,
    702                    sFONT* Font, UWORD Color_Foreground, UWORD Color_Background)
    703 {
    704 
    705     int16_t Num_Bit = 0, Str_Bit = 0;
    706     uint8_t Str_Array[ARRAY_LEN] = {0}, Num_Array[ARRAY_LEN] = {0};
    707     uint8_t *pStr = Str_Array;
    708 
    709     if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
    710         Debug("Paint_DisNum Input exceeds the normal display range\r\n");
    711         return;
    712     }
    713 
    714     //Converts a number to a string
    715     while (Nummber) {
    716         Num_Array[Num_Bit] = Nummber % 10 + '0';
    717         Num_Bit++;
    718         Nummber /= 10;
    719     }
    720 
    721     //The string is inverted
    722     while (Num_Bit > 0) {
    723         Str_Array[Str_Bit] = Num_Array[Num_Bit - 1];
    724         Str_Bit ++;
    725         Num_Bit --;
    726     }
    727 
    728     //show
    729     Paint_DrawString_EN(Xpoint, Ypoint, (const char*)pStr, Font, Color_Background, Color_Foreground);
    730 }
    731 
    732 /******************************************************************************
    733 function:	Display time
    734 parameter:
    735     Xstart           :X coordinate
    736     Ystart           : Y coordinate
    737     pTime            : Time-related structures
    738     Font             :A structure pointer that displays a character size
    739     Color_Foreground : Select the foreground color
    740     Color_Background : Select the background color
    741 ******************************************************************************/
    742 void Paint_DrawTime(UWORD Xstart, UWORD Ystart, PAINT_TIME *pTime, sFONT* Font,
    743                     UWORD Color_Foreground, UWORD Color_Background)
    744 {
    745     uint8_t value[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    746 
    747     UWORD Dx = Font->Width;
    748 
    749     //Write data into the cache
    750     Paint_DrawChar(Xstart                           , Ystart, value[pTime->Hour / 10], Font, Color_Background, Color_Foreground);
    751     Paint_DrawChar(Xstart + Dx                      , Ystart, value[pTime->Hour % 10], Font, Color_Background, Color_Foreground);
    752     Paint_DrawChar(Xstart + Dx  + Dx / 4 + Dx / 2   , Ystart, ':'                    , Font, Color_Background, Color_Foreground);
    753     Paint_DrawChar(Xstart + Dx * 2 + Dx / 2         , Ystart, value[pTime->Min / 10] , Font, Color_Background, Color_Foreground);
    754     Paint_DrawChar(Xstart + Dx * 3 + Dx / 2         , Ystart, value[pTime->Min % 10] , Font, Color_Background, Color_Foreground);
    755     Paint_DrawChar(Xstart + Dx * 4 + Dx / 2 - Dx / 4, Ystart, ':'                    , Font, Color_Background, Color_Foreground);
    756     Paint_DrawChar(Xstart + Dx * 5                  , Ystart, value[pTime->Sec / 10] , Font, Color_Background, Color_Foreground);
    757     Paint_DrawChar(Xstart + Dx * 6                  , Ystart, value[pTime->Sec % 10] , Font, Color_Background, Color_Foreground);
    758 }
    759 
    760 /******************************************************************************
    761 function:	Display monochrome bitmap
    762 parameter:
    763     image_buffer :A picture data converted to a bitmap
    764 info:
    765     Use a computer to convert the image into a corresponding array,
    766     and then embed the array directly into Imagedata.cpp as a .c file.
    767 ******************************************************************************/
    768 void Paint_DrawBitMap(const unsigned char* image_buffer)
    769 {
    770     UWORD x, y;
    771     UDOUBLE Addr = 0;
    772 
    773     for (y = 0; y < Paint.HeightByte; y++) {
    774         for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
    775             Addr = x + y * Paint.WidthByte;
    776             Paint.Image[Addr] = (unsigned char)image_buffer[Addr];
    777         }
    778     }
    779 }