The digital photo frame project displays a picture that can be enlarged, reduced, and dragged

I have worked on an electronic photo frame project before, and the main difficulties involved are: zooming in, zooming out, and moving pictures on the LCD.

First of all, we have to understand that whether it is zoomed in or out, the original image is actually reduced in equal proportions, and then displayed on the LCD, but the degree of reduction is different (about how to take out the original image data, and then Reduced to the size we need, you can see my other blog: https://blog.csdn.net/qq_37659294/article/details/104382032 ).

After the zoom algorithm introduced in the previous blog, we have obtained a picture that is reduced and proportional to the original picture and stored in the buffer, but this is only a picture, which has not been displayed on the LCD, so how do we Will this picture be dynamically enlarged, reduced, and moved on the LCD?

 

First, let ’s take a look at a very critical function, the ShowZoomedPictureInLayout function . This function displays a zoomed and moved picture on the LCD, because the size of the picture may be larger than the display area, it may be small, or it may be moved. To the edge of the photo frame, only part of the picture can be displayed, so we must confirm where to start fetching data from the picture (iStartXofNewPic, iStartYofNewPic), and where to display in the display area (iStartXofOldPic, iStartYofOldPic), how big to display (iWidthPictureInPlay, iHeightPictureInPlay) Area.

The realization idea of ​​ShowZoomedPictureInLayout function is:

① Calculate iStartXofNewPic, iStartYofNewPic, determine where to start fetching data from the picture

②Use the g_iXofZoomedPicShowInCenter-iStartXofNewPic = iDeltaX = X coordinate of the center point of the display area (g_tManualPictureLayout.iTopLeftX + iPictureLayoutWidth / 2)-iStartXofOldPic (the starting coordinate of the picture displayed on the LCD) equation to calculate the location of iStartXofOldPic, iStartYofOldPic, which location to display Start showing pictures

③ Calculate the actual width iWidthPictureInPlay and height iHeightPictureInPlay

④Brush the picture data into the LCD framebuffer according to the calculated parameters above


/ ************************************************* *********************
 * Function name: ShowZoomedPictureInLayout
 * Function description: Display the zoomed picture in the "manual page"
 * Input parameter: ptZoomedPicPixelDatas-contains already Pixel data of the zoomed picture
 * ptVideoMem-displayed in this VideoMem
 * Output parameter: None
 * Return value: None
 *************************** ********************************************** /

static void ShowZoomedPictureInLayout (PT_PixelDatas ptZoomedPicPixelDatas, PT_VideoMem ptVideoMem)
{

    / * The two variables




iStartXofNewPic and iStartYofNewPic do not mean the xy coordinates of the new picture in the display area (or the entire screen area)      * but from the zoomed picture coordinates (iStartXofNewPic, iStartYofNewPic), display this picture      * coordinates (x, y ) The previous area, that is, any place where the horizontal coordinate is less than x and the vertical coordinate is less than y, is not displayed      * because the zoomed picture may not be completely displayed on the screen, and only a part of it may be displayed      * Calculate where to start displaying the picture , And add a length and width, then the part displayed on the screen can be depicted      * /
    int iStartXofNewPic, iStartYofNewPic;

    / * The two variables




iStartXofOldPic and iStartYofOldPic are not the display position of the previous picture, but the starting coordinates of the new picture displayed on the screen.      * These six variables are connected together to think of:      * From the picture after the zoom (iStartXofNewPic , iStartYofNewPic) This place starts      * Take a large area such as iWidthPictureInPlay, iHeightPictureInPlay      * Display to the memory (iStartXofOldPic, iStartYofOldPic) this place      * /
    int iStartXofOldPic, iStartYofOldPic;
    int iWidthPictureInPlay, iHeight;


    int iPictureLayoutWidth, iPictureLayoutHeight;
    int iDeltaX, iDeltaY; // Intermediate variables in the calculation process

 

    / * iPictureLayoutWidth width of display area
     * iPictureLayoutHeight height of display area
     * /

    = g_tManualPictureLayout.iBotRightX iPictureLayoutWidth - g_tManualPictureLayout.iTopLeftX +. 1;
    iPictureLayoutHeight = g_tManualPictureLayout.iBotRightY - g_tManualPictureLayout.iTopLeftY +. 1;
    
    / * g_iXofZoomedPicShowInCenter image is to the left from the center of the display area, g_iXofZoomedPicShowInCenter = half width of the scaled offset movement + Amount (positive when moving to the left, negative when moving to the right (moving too much may become negative))
     * The first assignment of this variable is in ShowPictureInManualPage (the first display of the picture (centered display), at this time the picture The size is smaller than the LCD image display area) In this function, the value is half the width of the displayed image, which also represents the distance from the leftmost to the center
     * When not moving, the value of g_iXofZoomedPicShowInCenter is the same multiple of zooming in and out
     * When moving At the time, in the processing logic of "moving pictures" in the ManualPageRun function, the left shift increases and the right shift decreases.
     * Similarly, g_iYofZoomedPicShowInCenter is the distance from the top of the picture display position to the center of the display area
     * /

    iStartXofNewP ic = g_iXofZoomedPicShowInCenter-iPictureLayoutWidth / 2;// Calculate iStartXofNewPic by using g_iXofZoomedPicShowInCenter, and then know where to take the data from the picture to display, corresponding to the first step of the above idea
    if (iStartXofNewPic <0) // That is, g_iXofZoomedPicShowInCenter <iPictureLayoutWidth / 2 (half the width of the display area) , Indicating that the leftmost side of the picture is in the display area
    {
        iStartXofNewPic = 0; // If the leftmost side of the picture is in the display area, then the data will be taken from the leftmost side of the picture
    }

    / * There is another situation in between, that is,
     when (iStartXofNewPic> 0) && (iStartXofNewPic <ptZoomedPicPixelDatas-> iWidth)
     * means that the left side of the picture has been moved out of the display area (the rightmost side is still in the display area) and can only be displayed Part of
     this * iStartXofNewPic = g_iXofZoomedPicShowInCenter-iPictureLayoutWidth / 2;
     * means to start displaying from this place of the picture
     * /

    if (iStartXofNewPic> ptZoomedPicPixelDatas-> iWidth) // that is, g_iXofZoomedPicShowInCenter> ptZoomedPicPixelData (PicPixelDatas) (Half the width of the display area), indicating that the picture has been completely         moved to the left
    {
iStartXofNewPic = ptZoomedPicPixelDatas-> iWidth; // The entire picture has been moved out of the display area to the left, no need to display
    }

     / * iDeltaX is the distance from the actual position of the displayed image to the center of the display area, which is obtained by subtracting iStartXofNewPic from g_iXofZoomedPicShowInCenter, but is only an intermediate variable used to calculate iStartXofOldPic
     * because it may move to or zoom to the left and cannot start from the beginning This is the case of 0 <iStartXofNewPic <ptZoomedPicPixelDatas-> iWidth
     * This formula calculates the distance from the
leftmost edge of the actual picture to the center of the display area      * iDeltaX may be a negative number (when the picture moves to the right of the centerline, Then iDeltaX is a negative number), but because we are using mathematical equations to calculate iStartXofOldPic, the final negative and negative will be positive
     * /
    iDeltaX = g_iXofZoomedPicShowInCenter-iStartXofNewPic;

     / * g_iXofZoomedPicShowInCenter-iStartXofNewPic
     * = iDeltaX
     * = X coordinate of the center point of the display area (g_tManualPictureLayout.iTopLeftX + iPictureLayoutWidth / 2)-iStartXofOldPic (the starting coordinate of the picture displayed on the LCD)
     * According to the above equation we can calculate iStartXofOldPic

     * /
    iStartXofOldPic * / = (g_tManualPictureLayout.iTopLeftX + iPictureLayoutWidth / 2)-iDeltaX;


     / * When iStartXofNewPic = ptZoomedPicPixelDatas-> iWidth, it means that the whole picture has been drawn out from the left side
     * iDeltaX = g_iXofZoomedPicShowInCenter-ptZoomedPicPixelDatas-> iWidth> = iPictureLayoutWidth / 2
     * So iStartXofOldPic is less than g in this case. So you need to judge
     * /

    if (iStartXofOldPic <g_tManualPictureLayout.iTopLeftX)
    {
        iStartXofOldPic = g_tManualPictureLayout.iTopLeftX;
    }

     / *
    Marked out to the right * / if (iStartXofOldPic> g_tManualPictureLayout.iBotRightX)
    {
        iStartXofOldPic = g_tManualPictureLayout.iBotRightX + 1;
    }
     

     / * ptZoomedPicPixelDatas-> iWidth-iStartXofNewPic is the picture except for the left side that may not be displayed, the rest is to be displayed
     * g_tManualPictureLayout.iBotRightX-iStartXofOldPic + 1 is from the display position to the end of the area where the picture can be displayed, how wide is it
     * the two selected from a small, as the width of the actual display
     * /

    IF ((ptZoomedPicPixelDatas-> iWidth - iStartXofNewPic)> (g_tManualPictureLayout.iBotRightX - iStartXofOldPic +. 1))
        iWidthPictureInPlay = (g_tManualPictureLayout.iBotRightX - iStartXofOldPic +. 1);
    the else
        iWidthPictureInPlay = (ptZoomedPicPixelDatas-> iWidth-iStartXofNewPic);
    

     / * The above is about the calculation of the X coordinate, the following starts the calculation of the Y direction, the principle is the same * /
    iStartYofNewPic = g_iYofZoomedPicShowInCenter-iPictureLayoutHeight / 2;
    if (iStartYofNewPic <0)
    {
        iStartYofNewPic = 0;
    }
    if (iStartYofNewPic> ptZoomedPicPixels)
    {
        iStartYofNewPic = ptZoomedPicPixelDatas-> iHeight;
    }
    iDeltaY = g_iYofZoomedPicShowInCenter-iStartYofNewPic;
    iStartYofOldPic = (g_tManualPictureLayout.iTopLeftY + iPictureLayoutHeight / 2)-iDeltaY;

    if (iStartYofOldPic < g_tManualPictureLayout.iTopLeftY)
    {
        iStartYofOldPic = g_tManualPictureLayout.iTopLeftY;
    }
    if (iStartYofOldPic > g_tManualPictureLayout.iBotRightY)
    {
        iStartYofOldPic = g_tManualPictureLayout.iBotRightY + 1;
    }
    
    if ((ptZoomedPicPixelDatas->iHeight - iStartYofNewPic) > (g_tManualPictureLayout.iBotRightY - iStartYofOldPic + 1))
    {
        iHeightPictureInPlay = (g_tManualPictureLayout.iBotRightY - iStartYofOldPic + 1);
    }
    else
    {
        iHeightPictureInPlay = (ptZoomedPicPixelDatas->iHeight - iStartYofNewPic);
    }
   

     / * Fill the entire picture display area with a background color * /    
    ClearVideoMemRegion (ptVideoMem, & g_tManualPictureLayout, COLOR_BACKGROUND);

     / *
     Pass in the previously calculated parameters and display the zoomed and moved picture * iStartXofNewPic, iStartYofNewPic: from which position of the picture to start taking data
     * iStartXofOldPic, iStartYofOldPic: where to start displaying the picture at the LCD
     * iWidthPictureInPlay, iHeightPictureInPlay: true display image width and height
     * ptZoomedPicPixelDatas, & ptVideoMem-> tPixelDatas: source and destination
     * /

    PicMergeRegion (iStartXofNewPic, iStartYofNewPic, iStartXofOldPic, iStartYofOldPic, iWidthPictureInPlay, iHeightPictureInPlay, ptZoomedPicPixelDatas, & ptVideoMem-> tPixelDatas);
}

 

The PicMergeRegion function is defined as follows:



/**********************************************************************
 * 函数名称: PicMergeRegion
 * 功能描述: 把新图片的某部分, 合并入老图片的指定区域
 * 输入参数: iStartXofNewPic, iStartYofNewPic : 从新图片的(iStartXofNewPic, iStartYofNewPic)座标处开始读出数据用于合并
 *            iStartXofOldPic, iStartYofOldPic : 合并到老图片的(iStartXofOldPic, iStartYofOldPic)座标去
 *            iWidth, iHeight                  : 合并区域的大小
 *            ptNewPic                         : 新图片
 *            ptOldPic                         : 老图片
 * 输出参数: 无
 * 返 回 值: 0 - 成功, 其他值 - 失败
 ***********************************************************************/
int PicMergeRegion(int iStartXofNewPic, int iStartYofNewPic, int iStartXofOldPic, int iStartYofOldPic, int iWidth, int iHeight, PT_PixelDatas ptNewPic, PT_PixelDatas ptOldPic)
{
	int i;
	unsigned char *pucSrc;
	unsigned char *pucDst;
    int iLineBytesCpy = iWidth * ptNewPic->iBpp / 8;

    if ((iStartXofNewPic < 0 || iStartXofNewPic >= ptNewPic->iWidth) || \
        (iStartYofNewPic < 0 || iStartYofNewPic >= ptNewPic->iHeight) || \
        (iStartXofOldPic < 0 || iStartXofOldPic >= ptOldPic->iWidth) || \
        (iStartYofOldPic < 0 || iStartYofOldPic >= ptOldPic->iHeight))
    {
        return -1;
    }
	
	pucSrc = ptNewPic->aucPixelDatas + iStartYofNewPic * ptNewPic->iLineBytes + iStartXofNewPic * ptNewPic->iBpp / 8;
	pucDst = ptOldPic->aucPixelDatas + iStartYofOldPic * ptOldPic->iLineBytes + iStartXofOldPic * ptOldPic->iBpp / 8;
	for (i = 0; i < iHeight; i++)
	{
		memcpy(pucDst, pucSrc, iLineBytesCpy);
		pucSrc += ptNewPic->iLineBytes;
		pucDst += ptOldPic->iLineBytes;
	}
	return 0;
}

 

 

The following is the complete process of zooming in:

static int g_iXofZoomedPicShowInCenter;  
static int g_iYofZoomedPicShowInCenter;
/* 放大/缩小系数 */
#define ZOOM_RATIO (0.9)
case 2: /* 放大按钮 */
{
     /* 获得放大后的数据 */
     iZoomedWidth  = (float)g_tZoomedPicPixelDatas.iWidth / ZOOM_RATIO;
     iZoomedHeight = (float)g_tZoomedPicPixelDatas.iHeight / ZOOM_RATIO;
     ptZoomedPicPixelDatas = GetZoomedPicPixelDatas(&g_tOriginPicPixelDatas, iZoomedWidth, iZoomedHeight);

     /* 重新计算中心点 */
     g_iXofZoomedPicShowInCenter = (float)g_iXofZoomedPicShowInCenter / ZOOM_RATIO;
     g_iYofZoomedPicShowInCenter = (float)g_iYofZoomedPicShowInCenter / ZOOM_RATIO;

     /* 显示新数据 */
     ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);

     break;
}

Zoom out:

/* 放大/缩小系数 */
#define ZOOM_RATIO (0.9)
case 1: /* 缩小按钮 */
{
    /* 获得缩小后的数据 */
    iZoomedWidth  = (float)g_tZoomedPicPixelDatas.iWidth * ZOOM_RATIO;
    iZoomedHeight = (float)g_tZoomedPicPixelDatas.iHeight * ZOOM_RATIO;
    ptZoomedPicPixelDatas = GetZoomedPicPixelDatas(&g_tOriginPicPixelDatas, iZoomedWidth, iZoomedHeight);

    /* 重新计算中心点 */
    g_iXofZoomedPicShowInCenter = (float)g_iXofZoomedPicShowInCenter * ZOOM_RATIO;
    g_iYofZoomedPicShowInCenter = (float)g_iYofZoomedPicShowInCenter * ZOOM_RATIO;

    /* 显示新数据 */
    ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);

    break;
}

Drag and drop:

/* 如果触点滑动距离大于规定值, 则挪动图片 */
if (DistanceBetweenTwoPoint(&tInputEvent, &tPreInputEvent) > SLIP_MIN_DISTANCE)
{                            
    /* 重新计算中心点 */
    g_iXofZoomedPicShowInCenter -= (tInputEvent.iX - tPreInputEvent.iX);
    g_iYofZoomedPicShowInCenter -= (tInputEvent.iY - tPreInputEvent.iY);
                            
    /* 显示新数据 */
    ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);
                            
    /* 记录上次滑动点 */
    tPreInputEvent = tInputEvent;                            
}

Experimental effect:

The initial display is centered

Drag 

amplification 

Reference article: https://blog.csdn.net/qq_22655017/article/details/97627382

 

Published 42 original articles · Like 10 · Visitors 10,000+

Guess you like

Origin blog.csdn.net/qq_37659294/article/details/104518692