私は以前に電子フォトフレームプロジェクトに取り組んだことがあり、主な困難は、ズームイン、ズームアウト、および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