イメージの左右反転表示
アナログで紙に絵を描いている時、絵のバランスを確認するために、紙の裏を覗いて見る、ということがよくあります。
左右反転した状態の絵を確認することで、絵のバランスを確認できるというものですが、これがペイントソフト上でも出来ると便利ですね。
前回はイメージの基準位置を変更できるようにしましたが、これに少し手を加えれば、キャンバス上でイメージを左右反転することは割と簡単に出来ます。
左右反転した状態の絵を確認することで、絵のバランスを確認できるというものですが、これがペイントソフト上でも出来ると便利ですね。
前回はイメージの基準位置を変更できるようにしましたが、これに少し手を加えれば、キャンバス上でイメージを左右反転することは割と簡単に出来ます。
ソースファイル
>> 020_canvas3.c
H キーで左右反転の ON/OFF ができます。
タイトルバーに、現在の ON/OFF 状態が表示されます。
H キーで左右反転の ON/OFF ができます。
タイトルバーに、現在の ON/OFF 状態が表示されます。
解説
キャンバスの左右反転状態は canvas_hrev に格納し、0 で通常、1 で左右反転状態とします。
H キーで、このフラグを反転します。
H キーで、このフラグを反転します。
キャンバス描画
まずは、キャンバス描画の変更部分を見てみます。
今までは incfxy を使って X, Y 方向ともに同じ値を加算していましたが、今回はそれを X, Y それぞれに分けて incfx, incfy の2つを用意しています。
左右反転の適用における実質の変更点は、以下の部分だけです。
キャンバスの左右反転が ON の場合、incfx の値を符号反転させています。
「キャンバス座標→イメージ座標」の変換としては、基準位置を元に拡大縮小した後、左右反転する場合はその値を符号反転し、基準位置を元にイメージ座標を左右反転させることになります。
ここでは、incfx を符号反転させることで、その左右反転処理が行えます。
左右反転時の X 方向では、イメージ座標は右から左へ値が減っていくことになるので、ループ時は符号反転させた incfx をそのまま足します。
void draw_canvas(SPTK_IMAGE32 *srcimg,SPTK_RECTWH *rc) { int ix,iy,pitchd,sfx,sfy,sfx_left,incfx,incfy,sx,sy; uint8_t *pdst; SPTK_PIX_RGBA *psrc; pdst = sptk_image_getptbuf(winimg, rc->x, rc->y); pitchd = winimg->pitch_dir - rc->w * winimg->bpp; incfx = incfy = (1 << 18) * 100 / zoom; if(canvas_hrev) incfx = -incfx; sfx_left = (rc->x - CANVAS_W / 2 + ptScr.x) * incfx + (ptImgBase.x << 18); sfy = (rc->y - CANVAS_H / 2 + ptScr.y) * incfy + (ptImgBase.y << 18); for(iy = 0; iy < rc->h; iy++) { sfx = sfx_left; sy = sfy >> 18; for(ix = 0; ix < rc->w; ix++) { sx = sfx >> 18; if(sx < 0 || sx >= srcimg->w || sy < 0 || sy >= srcimg->h) sptk_image_setpixel_buf_rgb(winimg, pdst, 0xcc, 0xcc, 0xcc); else { psrc = srcimg->pixbuf + sy * srcimg->w + sx; sptk_image_setpixel_buf_rgb(winimg, pdst, psrc->r, psrc->g, psrc->b); } sfx += incfx; pdst += winimg->bpp; } sfy += incfy; pdst += pitchd; } }
今までは incfxy を使って X, Y 方向ともに同じ値を加算していましたが、今回はそれを X, Y それぞれに分けて incfx, incfy の2つを用意しています。
左右反転の適用における実質の変更点は、以下の部分だけです。
incfx = incfy = (1 << 18) * 100 / zoom; if(canvas_hrev) incfx = -incfx;
キャンバスの左右反転が ON の場合、incfx の値を符号反転させています。
「キャンバス座標→イメージ座標」の変換としては、基準位置を元に拡大縮小した後、左右反転する場合はその値を符号反転し、基準位置を元にイメージ座標を左右反転させることになります。
ここでは、incfx を符号反転させることで、その左右反転処理が行えます。
左右反転時の X 方向では、イメージ座標は右から左へ値が減っていくことになるので、ループ時は符号反転させた incfx をそのまま足します。
座標変換
座標変換の計算部分も、少し手を加えます。
それぞれ、左右反転時は、各タイミングで X 座標を符号反転します。
なお、今回は、「イメージ範囲→キャンバス範囲」の変換処理にも少し手を加えました。
というのも、範囲の左上と右下の座標を img_to_canvas() で変換した値は、左右反転時には x1 > x2 となるからです。
(x1,y1) - (x2,y2) が正しく左上・右下になるように、sptk_rect_swap() で値を入れ替えています。
また、同じように、スクロールの最小値・最大値の計算時も、左右反転時に合わせた処理が必要になります。
void img_to_canvas(int *x,int *y) { int xx; xx = *x - ptImgBase.x; if(canvas_hrev) xx = -xx; *x = (int)(xx * zoom / 100.0 + CANVAS_W / 2 - ptScr.x); *y = (int)((*y - ptImgBase.y) * zoom / 100.0 + CANVAS_H / 2 - ptScr.y); } void canvas_to_img(int *x,int *y) { double dx,dy; dx = (*x - CANVAS_W / 2 + ptScr.x) * 100.0 / zoom; dy = (*y - CANVAS_H / 2 + ptScr.y) * 100.0 / zoom; if(canvas_hrev) dx = -dx; *x = (int)(dx + ptImgBase.x); *y = (int)(dy + ptImgBase.y); }
それぞれ、左右反転時は、各タイミングで X 座標を符号反転します。
なお、今回は、「イメージ範囲→キャンバス範囲」の変換処理にも少し手を加えました。
というのも、範囲の左上と右下の座標を img_to_canvas() で変換した値は、左右反転時には x1 > x2 となるからです。
(x1,y1) - (x2,y2) が正しく左上・右下になるように、sptk_rect_swap() で値を入れ替えています。
また、同じように、スクロールの最小値・最大値の計算時も、左右反転時に合わせた処理が必要になります。
そのほか
今回は、左右反転の変更時にイメージの基準位置などを調整していないので、画面上のイメージ位置が別の場所に飛びますが、実際のペイントソフトでは、左右反転の変更時にも画面上のイメージ位置が移動しないように調整するべきです。