デジタルフォトフレームプロジェクトは、拡大、縮小、およびドラッグできる画像を表示します

私は以前に電子フォトフレームプロジェクトに取り組んだことがあり、主な困難は、ズームイン、ズームアウト、およびLCDでの画像の移動です。

まず、拡大・縮小に関わらず、実際に元の画像を等比率に縮小してLCDに表示しますが、縮小の度合いは異なります(元の画像データの取り出し方と、必要なサイズに縮小すると、他のブログ(https://blog.csdn.net/qq_37659294/article/details/104382032)を見ることができます

前のブログで紹介したズームアルゴリズムの後、元の画像に比例して縮小され、バッファーに保存された画像を取得しましたが、これはLCDに表示されていない画像にすぎないので、この画像は動的に拡大、縮小され、LCD上で移動されますか?

 

最初に、非常に重要な関数であるShowZoomedPictureInLayout関数を見てみましょう。この関数は、画像のサイズが表示領域よりも大きい、小さい、または移動している可能性があるため、ズームして移動した画像をLCDに表示します。フォトフレームの端までは、画像の一部しか表示できないため、画像からデータのフェッチを開始する場所(iStartXofNewPic、iStartYofNewPic)、表示領域に表示する場所(iStartXofOldPic、iStartYofOldPic)、表示する大きさ(iWidthPictureInPlay、iHeightPicture)を確認する必要があります。エリア。

ShowZoomedPictureInLayout関数の実現の考え方は次のとおりです。

①iStartXofNewPic、iStartYofNewPicを計算し、画像からデータのフェッチを開始する場所を決定します

②g_iXofZoomedPicShowInCenter-iStartXofNewPic= iDeltaX =表示領域の中心点のX座標(g_tManualPictureLayout.iTopLeftX + iPictureLayoutWidth / 2)-iStartXofOldPic(LCDに表示される画像の開始座標、iOldPの開始位置、iOldPの開始位置、iOldiOの開始位置、iOldPからiOldOの開始位置、iOldPのiOldOの位置を計算するには、i写真の表示を開始します

③実際の幅iWidthPictureInPlayと高さiHeightPictureInPlayを計算します

④上記の計算されたパラメータに従って、画像データをLCDフレームバッファにブラッシングします。


/ ************************************************* *********************
 *関数名:ShowZoomedPictureInLayout
 *関数の説明:ズームされた画像を「手動ページ」に表示します
 *入力パラメーター:ptZoomedPicPixelDatas-containsはすでにズームされた画像のピクセルデータ
 *このVideoMemにptVideoMemで表示
 *出力パラメーター:なし
 *戻り値:なし
 *************************** ********************************************** /

static void ShowZoomedPictureInLayout (PT_PixelDatas ptZoomedPicPixelDatas、PT_VideoMem ptVideoMem)
{

    / * 2つの変数




iStartXofNewPicとiStartYofNewPic は、表示領域(または画面領域全体)の新しい画像のxy座標を意味しません      *ではなく、ズームされた画像座標(iStartXofNewPic、iStartYofNewPic)から、この画像を表示      *座標(x、y )前の領域、つまり、水平座標がx未満で垂直座標がy未満の場所は表示されません      *ズームされた画像が画面に完全に表示されず、その一部のみが表示される場合がある      *画像の表示を開始する場所を計算します、そして長さと幅を追加すると、画面に表示される部分を描画できます      * /
    int iStartXofNewPic、iStartYofNewPic;

    / * IStartXofOldPicとiStartYofOldPic これら二つの変数と、その位置が画面上に表示されていないが、新しい画像が座標の最初に画面に表示され
     、これらの6つの変数をリンクする*です:
     *のズーム後の画像から(iStartXofNewPic 、iStartYofNewPic)この場所が開始します
     * iWidthPictureInPlay、iHeightPictureInPlayなどの大きな領域を取得します* この場所を
     メモリ(iStartXofOldPic、iStartYofOldPic)に表示します
     * /

    int iStartXofOldPic、iStartYofOldPic;
    int iWidthPictureInPlay、iHeight;


    int iPictureLayoutWidth、iPictureLayoutHeight;
    int iDeltaX、iDeltaY; //計算プロセスの中間変数

 

    / * iPictureLayoutWidth表示領域の幅* iPictureLayoutHeight表示領域の
     高さ
     * /

    = g_tManualPictureLayout.iBotRightX iPictureLayoutWidth - g_tManualPictureLayout.iTopLeftX + 1;
    iPictureLayoutHeight = g_tManualPictureLayout.iBotRightY - g_tManualPictureLayout.iTopLeftY + 1;
    
    / * g_iXofZoomedPicShowInCenter画像は、表示領域の中心から左側にあるスケーリングオフセット移動+のg_iXofZoomedPicShowInCenter =半値幅量(左に移動すると正、右に移動すると負(移動が多すぎると負になる可能性があります))
     *この変数の最初の割り当ては、ShowPictureInManualPage(画像の最初の表示(中央表示)、この時点では画像)にありますサイズはLCD画像表示領域よりも小さい)この関数では、値は表示された画像の幅の半分であり、これは左端から中央までの距離も表します
     *移動しない場合、g_iXofZoomedPicShowInCenterの値はズームインとズームアウトの同じ倍数
     *移動する場合このとき、ManualPageRun関数の「動画」の処理ロジックでは、左シフトが増加し、右シフトが減少します
     *同様に、g_iYofZoomedPicShowInCenterは、画像表示位置の上から表示領域の中心までの距離です
     * /

    iStartXofNewP ic = g_iXofZoomedPicShowInCenter-iPictureLayoutWidth / 2;// g_iXofZoomedPicShowInCenterを使用してiStartXofNewPicを計算し、表示する画像からデータを取得する場所を知っています。これは、上記のアイデアの最初のステップに対応します
    (iStartXofNewPic <0)//つまり、g_iXofZoomedPicShowInCenter <iPictureLayoutWidth / 2(ディスプレイの半分の幅) 、画像の左端が表示領域にあることを示す
    {
        iStartXofNewPic = 0; //画像の左端が表示領域にある場合、データは画像の左端から取得されます
    }

    / *間に別の状況があります。つまり、
     (iStartXofNewPic> 0)&&(iStartXofNewPic <ptZoomedPicPixelDatas-> iWidth)
     *は、画像の左側が表示領域の外に移動され(右端がまだ表示領域にある)、表示のみ可能であることを意味します
     この一部* iStartXofNewPic = g_iXofZoomedPicShowInCenter-iPictureLayoutWidth / 2;
     *は、画像のこの場所から表示を開始することを意味します
     * /

    if(iStartXofNewPic> ptZoomedPicPixelDatas-> iWidth)//つまり、g_iXofZoomedPicShowDataPicDataPicDataPicDataPicDataPicDataPicShowInCenter> pt (表示領域の幅の半分)、画像が完全         に左に移動されたことを示します
    {
iStartXofNewPic = ptZoomedPicPixelDatas-> iWidth; //画像全体が表示領域から左に移動され、表示する必要はありません
    }

     / * iDeltaXは、表示された画像の実際の位置から表示領域の中心までの距離です。これは、g_iXofZoomedPicShowInCenterからiStartXofNewPicを差し引いて得られますが、iStartXofOldPicの計算に使用される中間変数にすぎません
     *左に移動またはズームして、最初から開始できないためこれは0の場合です<iStartXofNewPic <ptZoomedPicPixelDatas-> iWidth
     *この式
は、実際の画像の左端から表示領域の中心までの距離を計算します      * iDeltaXは負の数になる場合があります(画像が中心線の右側に移動すると、その場合、iDeltaXは負の数です)が、数式を使用してiStartXofOldPicを計算しているため、最終的な負と負は正になります
     * /
    iDeltaX = g_iXofZoomedPicShowInCenter-iStartXofNewPic;

     / * G_iXofZoomedPicShowInCenter - iStartXofNewPic
     * = iDeltaX
     * = Xディスプレイ領域の中心点の座標(g_tManualPictureLayout.iTopLeftX + iPictureLayoutWidth / 2) - iStartXofOldPic( 表示画像が開始LCD上の座標)
     *上記の式によれば、我々はiStartXofOldPic算出することができる

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


     / * iStartXofNewPic = ptZoomedPicPixelDatas-> iWidthの場合、画像全体が左側から描画されていることを意味します
     * iDeltaX = g_iXofZoomedPicShowInCenter-ptZoomedPicPixelDatas-> iWidth> = iPictureLayoutWidth / 2
     *このため、iStartXofはこのiStartXofOldPよりも小さいです。したがって、判断する必要があります
     * /

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

     / *右に
    マークアウト* / if(iStartXofOldPic> g_tManualPictureLayout.iBotRightX)
    {
        iStartXofOldPic = g_tManualPictureLayout.iBotRightX + 1;
    }
     

     / * ptZoomedPicPixelDatas-> iWidth-iStartXofNewPicは、表示されない可能性がある左側を除く画像であり、残りは表示されます
     * g_tManualPictureLayout.iBotRightX-iStartXofOldPic + 1は、表示位置から画像を表示できる領域の終わりまでの幅です。
     *実際のディスプレイの幅と、小から選択される2
     * /

    IF((ptZoomedPicPixelDatas-> IWIDTH - iStartXofNewPic)>(g_tManualPictureLayout.iBotRightX - iStartXofOldPic + 1)。)
        iWidthPictureInPlay =(g_tManualPictureLayout.iBotRightX - iStartXofOldPic + 1);
    他
        iWidthPictureInPlay =(ptZoomedPicPixelDatas-> iWidth-iStartXofNewPic);
    

     / *上記はX座標の計算に関するもので、以下はY方向の計算を開始します。原理は同じです* /
    iStartYofNewPic = g_iYofZoomedPicShowInCenter-iPictureLayoutHeight / 2;
    if(iStartYofNewPic <0)
    {
        iStartYofNewPic = 0;
    }
    if(iStartYofNewPic)
    {
        iStartYofNewPic = ptZoomedPicPixelDatas-> iHeight;
    }
    iDeltaY = g_iYofZoomedPicShowInCenter-iStartYofNewPic;
    iStartYofOldPic =(g_tManualPictureLayout.iTopLeftY + iPictureLayoutHeY / 2)-i

    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-iStartYofOld);
    }
    else
    {
        iHeightPictureInPlay =(ptZoomedPicPixelDatas-> iHeight-iStartYofNewPic);
    }
   

     / *画像の表示領域全体を背景色で塗りつぶします* /    
    ClearVideoMemRegion(ptVideoMem、&g_tManualPictureLayout、COLOR_BACKGROUND);

     / *以前に計算されたパラメーターを
     渡して、ズームして移動した画像を表示します* iStartXofNewPic、iStartYofNewPic:データの取得を開始する画像の位置
     * iStartXofOldPic、iStartYofOldPic:LCDで画像の表示を開始する場所
     * iWidthPictureInPlay、iHeightPictureInPlay:true表示画像の幅と高さ
     * ptZoomedPicPixelDatas、&ptVideoMem-> tPixelDatas:ソースおよび宛先
     * /

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

 

PicMergeRegion関数は次のように定義されます。



/**********************************************************************
 * 函数名称: 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;
}

 

 

以下は、ズームインの完全なプロセスです。

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;
}

ズームアウト:

/* 放大/缩小系数 */
#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;
}

ドラッグアンドドロップ:

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

実験的効果:

初期表示は中央に配置されます

ドラッグ 

ズームイン 

参照記事:https : //blog.csdn.net/qq_22655017/article/details/97627382

 

42件のオリジナル記事を公開 いいね10 10,000人以上の訪問者

おすすめ

転載: blog.csdn.net/qq_37659294/article/details/104518692