OSDN Git Service

16d3f93a40e04766a93a9fb1a33fbbe963250c1c
[gokigen/A01c.git] / wear / src / main / java / jp / sfjp / gokigen / a01c / liveview / CameraLiveImageView.java
1 package jp.sfjp.gokigen.a01c.liveview;
2
3 import android.content.Context;
4 import android.graphics.Bitmap;
5 import android.graphics.BitmapFactory;
6 import android.graphics.Canvas;
7 import android.graphics.Color;
8 import android.graphics.Paint;
9 import android.graphics.PointF;
10 import android.graphics.Rect;
11 import android.graphics.RectF;
12 import androidx.exifinterface.media.ExifInterface;
13 import androidx.preference.PreferenceDataStore;
14
15 import android.os.Looper;
16 import android.util.AttributeSet;
17 import android.util.DisplayMetrics;
18 import android.util.Log;
19 import android.util.TypedValue;
20 import android.view.MotionEvent;
21 import android.view.View;
22 import android.widget.ImageView;
23
24 import java.util.Map;
25 import java.util.Timer;
26 import java.util.TimerTask;
27
28 import jp.co.olympus.camerakit.OLYCamera;
29
30 import jp.sfjp.gokigen.a01c.R;
31 import jp.sfjp.gokigen.a01c.liveview.dialog.IDialogController;
32 import jp.sfjp.gokigen.a01c.liveview.dialog.IDialogDrawer;
33 import jp.sfjp.gokigen.a01c.liveview.gridframe.GridFrameFactory;
34 import jp.sfjp.gokigen.a01c.liveview.gridframe.IGridFrameDrawer;
35 import jp.sfjp.gokigen.a01c.olycamerawrapper.ILevelGauge;
36 import jp.sfjp.gokigen.a01c.preference.IPreferenceCameraPropertyAccessor;
37 import jp.sfjp.gokigen.a01c.preference.PreferenceAccessWrapper;
38
39 /**
40  *   CameraLiveImageView :
41  *    (OLYMPUS の ImageCaptureSample をカスタマイズ)
42  *
43  */
44 public class CameraLiveImageView extends View implements IImageDataReceiver, IAutoFocusFrameDisplay, ILiveImageStatusNotify, IDialogController
45 {
46     private final String TAG = toString();
47
48     private static final String EXIF_ORIENTATION = "Orientation";
49
50     private boolean showGridFeature = false;
51     private boolean showLevelGaugeFeature = false;
52     private ImageView.ScaleType imageScaleType;
53     private Bitmap imageBitmap;
54     private int imageRotationDegrees;
55     private boolean showingFocusFrame = false;
56     private IAutoFocusFrameDisplay.FocusFrameStatus focusFrameStatus;
57     private RectF focusFrameRect;
58     private Timer focusFrameHideTimer;
59
60     private IGridFrameDrawer gridFrameDrawer = null;
61     private ShowMessageHolder messageHolder;
62
63     private IDialogDrawer dialogDrawer = null;
64     private PreferenceDataStore preferences = null;
65
66     /**
67      *   コンストラクタ
68      *
69      */
70     public CameraLiveImageView(Context context)
71     {
72         super(context);
73         initComponent(context);
74     }
75
76     /**
77      *   コンストラクタ
78      *
79      */
80     public CameraLiveImageView(Context context, AttributeSet attrs)
81     {
82         super(context, attrs);
83         initComponent(context);
84     }
85
86     /**
87      *   コンストラクタ
88      *
89      */
90     public CameraLiveImageView(Context context, AttributeSet attrs, int defStyleAttr)
91     {
92         super(context, attrs, defStyleAttr);
93         initComponent(context);
94     }
95
96     /**
97      * 初期化ロジック (preferenceからデータを読み出す)
98      */
99     private void initComponent(Context context)
100     {
101         messageHolder = new ShowMessageHolder();
102
103         imageScaleType = ImageView.ScaleType.FIT_CENTER;
104
105         preferences = new PreferenceAccessWrapper(context);
106         showGridFeature = preferences.getBoolean(IPreferenceCameraPropertyAccessor.SHOW_GRID_STATUS, true);
107         showLevelGaugeFeature = preferences.getBoolean(IPreferenceCameraPropertyAccessor.SHOW_LEVEL_GAUGE_STATUS, false);
108
109         int framingGridStatus = 0; // IPreferenceCameraPropertyAccessor.FRAME_GRID_DEFAULT_VALUE;
110         try
111         {
112             framingGridStatus = Integer.parseInt(preferences.getString(IPreferenceCameraPropertyAccessor.FRAME_GRID, IPreferenceCameraPropertyAccessor.FRAME_GRID_DEFAULT_VALUE));
113         }
114         catch (Exception e)
115         {
116             e.printStackTrace();
117         }
118         gridFrameDrawer = GridFrameFactory.getGridFrameDrawer(framingGridStatus);
119
120         // ダミーのビットマップデータ読み込み...画面表示のテスト用ロジック
121         try
122         {
123             imageBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.momonga);
124         }
125         catch (Throwable t)
126         {
127             t.printStackTrace();
128             imageBitmap = null;
129         }
130     }
131
132     /**
133      *
134      *
135      */
136     @Override
137     protected void onAttachedToWindow()
138     {
139         super.onAttachedToWindow();
140     }
141
142     /**
143      *
144      *
145      */
146     @Override
147     protected void onDetachedFromWindow()
148     {
149         super.onDetachedFromWindow();
150
151         imageBitmap = null;
152         if (focusFrameHideTimer != null)
153         {
154             focusFrameHideTimer.cancel();
155             focusFrameHideTimer = null;
156         }
157     }
158
159     /**
160      *
161      *
162      */
163     @Override
164     protected void onDraw(Canvas canvas)
165     {
166         super.onDraw(canvas);
167         try
168         {
169             // 画像の表示
170             drawCanvas(canvas);
171
172             // ダイアログの表示
173             if (dialogDrawer != null)
174             {
175                 dialogDrawer.drawDialog(canvas);
176                 return;
177             }
178
179             // メッセージの表示 (Overwrite)
180             drawInformationMessages(canvas);
181         }
182         catch (Exception e)
183         {
184             e.printStackTrace();
185         }
186     }
187
188     /**
189      *
190      *
191      */
192     @Override
193     public float getContentSizeWidth() {
194         return getIntrinsicContentSizeWidth();
195     }
196
197     /**
198      *
199      *
200      */
201     @Override
202     public float getContentSizeHeight() {
203         return getIntrinsicContentSizeHeight();
204     }
205
206     /**
207      *
208      *
209      */
210     private float getIntrinsicContentSizeWidth()
211     {
212         if (imageBitmap == null)
213         {
214             return (1.0f);
215         }
216         return (imageBitmap.getWidth());
217     }
218
219     /**
220      *
221      *
222      */
223     private float getIntrinsicContentSizeHeight()
224     {
225         if (imageBitmap == null)
226         {
227             return (1.0f);
228         }
229         return (imageBitmap.getHeight());
230     }
231
232     /**
233      * Sets a image to view.
234      * (CameraLiveViewListenerImpl.IImageDataReceiver の実装)
235      *
236      * @param data     A image of live-view.
237      * @param metadata A metadata of the image.
238      */
239     public void setImageData(byte[] data, Map<String, Object> metadata)
240     {
241         Bitmap bitmap;
242         int rotationDegrees;
243
244         if (data != null && metadata != null)
245         {
246             // Create a bitmap.
247             try
248             {
249                 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
250             }
251             catch (OutOfMemoryError e)
252             {
253                 e.printStackTrace();
254                 return;
255             }
256
257             // Acquire a rotation degree of image.
258             int orientation = ExifInterface.ORIENTATION_UNDEFINED;
259             try
260             {
261                 if (metadata.containsKey(EXIF_ORIENTATION))
262                 {
263                     orientation = Integer.parseInt((String) metadata.get(EXIF_ORIENTATION));
264                 }
265             }
266             catch (Exception e)
267             {
268                 e.printStackTrace();
269             }
270             switch (orientation)
271             {
272                 case ExifInterface.ORIENTATION_ROTATE_90:
273                     rotationDegrees = 90;
274                     break;
275                 case ExifInterface.ORIENTATION_ROTATE_180:
276                     rotationDegrees = 180;
277                     break;
278                 case ExifInterface.ORIENTATION_ROTATE_270:
279                     rotationDegrees = 270;
280                     break;
281                 case ExifInterface.ORIENTATION_NORMAL:
282                 default:
283                     rotationDegrees = 0;
284                     break;
285             }
286             imageBitmap = bitmap;
287             imageRotationDegrees = rotationDegrees;
288         }
289         refreshCanvas();
290     }
291
292     /**
293      * Returns a point which is detected by a motion event.
294      *
295      * @param event A motion event.
296      * @return A point in the view finder. if a point is equal to null, the point is out of the view finder.
297      */
298     public PointF getPointWithEvent(MotionEvent event)
299     {
300         if (event == null || imageBitmap == null)
301         {
302             return null;
303         }
304
305         PointF pointOnView = new PointF(event.getX(), event.getY());
306         PointF pointOnImage = convertPointFromViewArea(pointOnView);
307         float imageWidth;
308         float imageHeight;
309         if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
310             imageWidth = imageBitmap.getWidth();
311             imageHeight = imageBitmap.getHeight();
312         } else {
313             imageWidth = imageBitmap.getHeight();
314             imageHeight = imageBitmap.getWidth();
315         }
316         return (OLYCamera.convertPointOnLiveImageIntoViewfinder(pointOnImage, imageWidth, imageHeight, imageRotationDegrees));
317     }
318
319     /**
320      * Returns whether a image area contains a specified point.
321      *
322      * @param point The point to examine.
323      * @return true if the image is not null or empty and the point is located within the rectangle; otherwise, false.
324      */
325     public boolean isContainsPoint(PointF point)
326     {
327         return ((point != null) && (new RectF(0, 0, 1, 1)).contains(point.x, point.y));
328     }
329
330     /**
331      * Hides the forcus frame.
332      */
333     public void hideFocusFrame()
334     {
335         if (focusFrameHideTimer != null)
336         {
337             focusFrameHideTimer.cancel();
338             focusFrameHideTimer = null;
339         }
340         showingFocusFrame = false;
341         refreshCanvas();
342     }
343
344     /**
345      * Shows the focus frame.
346      *
347      * @param rect     A rectangle of the focus frame on view area.
348      * @param status   A status of the focus frame.
349      * @param duration A duration of the focus frame showing.
350      */
351     @Override
352     public void showFocusFrame(RectF rect, FocusFrameStatus status, double duration)
353     {
354         if (focusFrameHideTimer != null) {
355             focusFrameHideTimer.cancel();
356             focusFrameHideTimer = null;
357         }
358
359         showingFocusFrame = true;
360         focusFrameStatus = status;
361         focusFrameRect = rect;
362
363         refreshCanvas();
364
365         if (duration > 0) {
366             focusFrameHideTimer = new Timer();
367             focusFrameHideTimer.schedule(new TimerTask() {
368                 @Override
369                 public void run() {
370                     hideFocusFrame();
371                 }
372             }, (long) (duration * 1000));
373         }
374     }
375
376     /**
377      *
378      *
379      */
380     private void refreshCanvas()
381     {
382         if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
383             invalidate();
384         } else {
385             postInvalidate();
386         }
387     }
388
389     /**
390      * ビットマップの表示・画面表示の更新
391      *
392      * @param canvas キャンバス
393      */
394     private void drawCanvas(Canvas canvas)
395     {
396         // Clears the canvas.
397         canvas.drawARGB(255, 0, 0, 0);
398
399         // ビットマップの取得
400         Bitmap bitmapToShow = imageBitmap;
401         if (bitmapToShow == null)
402         {
403             // 表示するビットマップがないとき
404             return;
405         }
406
407         // Rotates the image.
408         int centerX = canvas.getWidth() / 2;
409         int centerY = canvas.getHeight() / 2;
410         canvas.rotate(imageRotationDegrees, centerX, centerY);
411
412         RectF viewRect = null;
413
414         //  Calculate the viewport of bitmap.
415         if (imageScaleType == ImageView.ScaleType.FIT_CENTER)
416         {
417             viewRect = decideViewRect(canvas, bitmapToShow, imageRotationDegrees);
418
419             // Draws the bitmap.
420             Rect imageRect = new Rect(0, 0, bitmapToShow.getWidth(), bitmapToShow.getHeight());
421             canvas.drawBitmap(bitmapToShow, imageRect, viewRect, null);
422         }
423         else
424         {
425             // Sorry, other scale types are not supported.
426             Log.v(TAG, "Sorry, other scale types are not supported. " + imageScaleType);
427         }
428
429         // Cancels rotation of the canvas.
430         canvas.rotate(-imageRotationDegrees, centerX, centerY);
431
432
433         // フォーカスフレームを表示する
434         if ((focusFrameRect != null) && (showingFocusFrame)) {
435             if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
436                 drawFocusFrame(canvas, bitmapToShow.getWidth(), bitmapToShow.getHeight());
437             } else {
438                 drawFocusFrame(canvas, bitmapToShow.getHeight(), bitmapToShow.getWidth());
439             }
440         }
441
442         if (viewRect != null)
443         {
444             // グリッド(撮影補助線)の表示
445             if ((showGridFeature) && (gridFrameDrawer != null))
446             {
447                 drawGridFrame(canvas, viewRect);
448             }
449
450             // レベルゲージ(デジタル水準器)の表示
451             if (showLevelGaugeFeature)
452             {
453                 drawLevelGauge(canvas, viewRect);
454             }
455         }
456     }
457
458     /**
459      *
460      *
461      */
462     private RectF decideViewRect(Canvas canvas, Bitmap bitmapToShow, int degree)
463     {
464         final int srcWidth;
465         final int srcHeight;
466         if ((degree == 0) || (degree == 180))
467         {
468             srcWidth = bitmapToShow.getWidth();
469             srcHeight = bitmapToShow.getHeight();
470         }
471         else
472         {
473             // Replaces width and height.
474             srcWidth = bitmapToShow.getHeight();
475             srcHeight = bitmapToShow.getWidth();
476         }
477
478         int maxWidth = canvas.getWidth();
479         int maxHeight = canvas.getHeight();
480
481         int centerX = canvas.getWidth() / 2;
482         int centerY = canvas.getHeight() / 2;
483
484         float widthRatio = maxWidth / (float) srcWidth;
485         float heightRatio = maxHeight / (float) srcHeight;
486         float smallRatio = Math.min(widthRatio, heightRatio);
487
488         final int dstWidth;
489         final int dstHeight;
490         if (widthRatio < heightRatio)
491         {
492             // Fits to maxWidth with keeping aspect ratio.
493             dstWidth = maxWidth;
494             dstHeight = (int) (smallRatio * srcHeight);
495         }
496         else
497         {
498             // Fits to maxHeight with keeping aspect ratio.
499             dstHeight = maxHeight;
500             dstWidth = (int) (smallRatio * srcWidth);
501         }
502
503         final float halfWidth = dstWidth * 0.5f;
504         final float halfHeight = dstHeight * 0.5f;
505         if ((degree == 0) || (degree == 180))
506         {
507             return (new RectF(
508                     centerX - halfWidth,
509                     centerY - halfHeight,
510                     centerX - halfWidth + dstWidth,
511                     centerY - halfHeight + dstHeight));
512         }
513
514         // Replaces the width and height.
515         return (new RectF(
516                 centerX - halfHeight,
517                 centerY - halfWidth,
518                 centerX - halfHeight + dstHeight,
519                 centerY - halfWidth + dstWidth));
520     }
521
522     /**
523      * AF枠の表示
524      *
525      * @param canvas      キャンバス
526      * @param imageWidth  幅
527      * @param imageHeight 高さ
528      */
529     private void drawFocusFrame(Canvas canvas, float imageWidth, float imageHeight)
530     {
531         //Log.v(TAG, "drawFocusFrame() :" + focusFrameStatus);
532
533         //  Calculate the rectangle of focus.
534         RectF focusRectOnImage = OLYCamera.convertRectOnViewfinderIntoLiveImage(focusFrameRect, imageWidth, imageHeight, imageRotationDegrees);
535         RectF focusRectOnView = convertRectFromImageArea(focusRectOnImage);
536
537         // Draw a rectangle to the canvas.
538         Paint focusFramePaint = new Paint();
539         focusFramePaint.setStyle(Paint.Style.STROKE);
540         switch (focusFrameStatus) {
541             case Running:
542                 focusFramePaint.setColor(Color.WHITE);
543                 break;
544
545             case Focused:
546                 focusFramePaint.setColor(Color.GREEN);
547                 break;
548
549             case Failed:
550                 focusFramePaint.setColor(Color.RED);
551                 break;
552
553             case Errored:
554                 focusFramePaint.setColor(Color.YELLOW);
555                 break;
556         }
557         float focusFrameStrokeWidth = 2.0f;
558         DisplayMetrics dm = getResources().getDisplayMetrics();
559         float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, focusFrameStrokeWidth, dm);
560         focusFramePaint.setStrokeWidth(strokeWidth);
561         canvas.drawRect(focusRectOnView, focusFramePaint);
562     }
563
564     /**
565      * グリッドの表示
566      *
567      * @param canvas   キャンバスエリア
568      * @param viewRect 表示領域
569      */
570     private void drawGridFrame(Canvas canvas, RectF viewRect)
571     {
572         RectF gridRect;
573         if ((imageRotationDegrees == 0) || (imageRotationDegrees == 180)) {
574             gridRect = new RectF(viewRect);
575         } else {
576             float height = viewRect.right - viewRect.left;
577             float width = viewRect.bottom - viewRect.top;
578             float left = (canvas.getWidth() / 2.0f) - (width / 2.0f);
579             float top = (canvas.getHeight() / 2.0f) - (height / 2.0f);
580             gridRect = new RectF(left, top, left + width, top + height);
581         }
582
583         Paint framePaint = new Paint();
584         framePaint.setStyle(Paint.Style.STROKE);
585         framePaint.setAntiAlias(true);
586
587         //DisplayMetrics dm = getResources().getDisplayMetrics();
588         //float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.0f, dm);
589         //framePaint.setStrokeWidth(strokeWidth);
590         framePaint.setStrokeWidth(0.0f);
591         framePaint.setColor(gridFrameDrawer.getDrawColor());
592         gridFrameDrawer.drawFramingGrid(canvas, gridRect, framePaint);
593     }
594
595     /**
596      *   デジタル水準器の表示
597      *
598      */
599     private void drawLevelGauge(Canvas canvas, RectF viewRect)
600     {
601        ILevelGauge levelGauge = messageHolder.getLevelGauge();
602         if (levelGauge == null)
603         {
604             // デジタル水準器がとれない場合は、何もしない
605             return;
606         }
607
608         // レベルゲージの表示位置
609         int height = (int) viewRect.bottom; // canvas.getHeight();
610         int width =  (int) viewRect.right;  // canvas.getWidth();
611         int centerX = width / 2;
612         int centerY = height / 2;
613
614         //float maxBandWidth = width / 3.0f;     // ゲージの最大長 (画面の 1/3 ぐらい)
615         float maxBandHeight = height / 3.0f;   // ゲージの最大長 (画面の 1/3 ぐらい)
616         int barWidthInitial = 4;               // 表示するゲージの幅(の初期値)
617         int barWidth;                          // 実際に表示するゲージの幅
618
619         Paint paint = new Paint();
620
621         // 垂直線
622         float verticalValue = levelGauge.getLevel(ILevelGauge.LevelArea.LEVEL_VERTICAL);
623         float verticalSize = verticalValue / 60.0f * maxBandHeight;  // 45度で切り替わるはずだが、一応...
624         if (Math.abs(verticalSize) < 1.0f)
625         {
626             // 線引き限界以下、水平検出とする (この時の線は倍の長さにする)
627             verticalSize = 1.0f;
628             barWidth = barWidthInitial * 2;
629         }
630         else
631         {
632             barWidth = barWidthInitial;
633         }
634         paint.setStrokeWidth(barWidth);
635         paint.setColor(levelGauge.getLevelColor(verticalValue));
636         canvas.drawLine((width - barWidth), centerY, (width - barWidth), (centerY + verticalSize), paint);
637
638         // 水平線の表示
639         float horizontalValue = levelGauge.getLevel(ILevelGauge.LevelArea.LEVEL_HORIZONTAL);
640         paint.setStrokeWidth(2.0f);
641         paint.setAntiAlias(true);
642         paint.setColor(levelGauge.getLevelColor(horizontalValue));
643         if ((imageRotationDegrees == 0) || (imageRotationDegrees == 180))
644         {
645             // 通常状態
646             float YY = canvas.getHeight() / 2.0f; // centerY
647             float diffY = (float) Math.sin(Math.toRadians(horizontalValue)) * (float) centerX;
648             canvas.drawLine(0, (YY + diffY), width, (YY - diffY), paint);
649         }
650         else
651         {
652             // 縦持ち状態
653             float XX = canvas.getWidth() / 2.0f; // centerX
654             float diffX = (float) Math.sin(Math.toRadians(horizontalValue)) * (float) centerY;
655             canvas.drawLine((XX + diffX), 0, (XX - diffX), canvas.getHeight(), paint);
656
657         }
658 /*
659         // 縦と同じ水平線を表示する場合...
660         float horizontalValue = levelGauge.getLevel(ILevelGauge.LevelArea.LEVEL_HORIZONTAL);
661         float horizontalSize = horizontalValue / 60.0f * maxBandWidth;  // 45度ぐらいで切り替わるはずだが、一応...
662         if (Math.abs(horizontalSize) < 1.0f)
663         {
664             // 線引き限界以下、水平検出とする (この時の線は倍の長さにする)
665             horizontalSize = 1.0f;
666             barWidth = barWidthInitial * 2;
667         }
668         else
669         {
670             barWidth = barWidthInitial;
671         }
672         paint.setStrokeWidth(barWidth);
673         paint.setColor(levelGauge.getLevelColor(horizontalValue));
674         canvas.drawLine(centerX, (height - barWidth), (centerX + horizontalSize),  (height - barWidth), paint);
675 */
676     }
677
678     /**
679      *   画面にメッセージを表示する
680      */
681     private void drawInformationMessages(Canvas canvas)
682     {
683         String message;
684         RectF viewRect;
685         if (imageBitmap != null)
686         {
687             // ビットマップの表示エリアに合わせて位置をチューニングする
688             viewRect = decideViewRect(canvas, imageBitmap, 0);
689         }
690         else
691         {
692             // 適当なサイズ...
693             viewRect = new RectF(5.0f, 0.0f, canvas.getWidth() - 5.0f, canvas.getHeight() - 55.0f);
694         }
695
696         // 画面の中心に表示する
697         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.CENTER);
698         if ((message != null)&&(message.length() > 0))
699         {
700             Paint paint = new Paint();
701             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.CENTER));
702             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.CENTER));
703             paint.setAntiAlias(true);
704             paint.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
705             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
706             float cx = (canvas.getWidth() / 2.0f) - (paint.measureText(message) / 2.0f);
707             float cy = (canvas.getHeight() / 2.0f) - ((fontMetrics.ascent + fontMetrics.descent) / 2.0f);
708             canvas.drawText(message, cx, cy, paint);
709         }
710
711         // 画面上部左側に表示する
712         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.UPLEFT);
713         if ((message != null)&&(message.length() > 0))
714         {
715             Paint paintUp = new Paint();
716             paintUp.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.UPLEFT));
717             paintUp.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.UPLEFT));
718             paintUp.setAntiAlias(true);
719             paintUp.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
720             Paint.FontMetrics fontMetrics = paintUp.getFontMetrics();
721             canvas.drawText(message, viewRect.left + 3.0f, viewRect.top + (fontMetrics.descent - fontMetrics.ascent), paintUp);
722         }
723
724         // 画面上部右側に表示する
725         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.UPRIGHT);
726         if ((message != null)&&(message.length() > 0))
727         {
728             Paint paintUp = new Paint();
729             paintUp.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.UPRIGHT));
730             paintUp.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.UPRIGHT));
731             paintUp.setAntiAlias(true);
732             paintUp.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
733             float width = paintUp.measureText(message);
734             Paint.FontMetrics fontMetrics = paintUp.getFontMetrics();
735             canvas.drawText(message, (viewRect.right - 3.0f) - width, viewRect.top + (fontMetrics.descent - fontMetrics.ascent), paintUp);
736         }
737
738         // 画面下部左側に表示する
739         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.LOWLEFT);
740         if ((message != null)&&(message.length() > 0))
741         {
742             Paint paint = new Paint();
743             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.LOWLEFT));
744             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.LOWLEFT));
745             paint.setAntiAlias(true);
746             paint.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
747             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
748             canvas.drawText(message, viewRect.left + 3.0f, viewRect.bottom - fontMetrics.bottom, paint);
749         }
750
751         // 画面下部右側に表示する
752         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.LOWRIGHT);
753         if ((message != null)&&(message.length() > 0))
754         {
755             Paint paint = new Paint();
756             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.LOWRIGHT));
757             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.LOWRIGHT));
758             paint.setAntiAlias(true);
759             paint.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
760             float width = paint.measureText(message);
761             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
762             canvas.drawText(message, (viewRect.right - 3.0f) - width, viewRect.bottom - fontMetrics.bottom, paint);
763         }
764
765 /**/
766         // 画面上部中央に表示する
767         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.UPCENTER);
768         if ((message != null)&&(message.length() > 0))
769         {
770             Paint paintUp = new Paint();
771             paintUp.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.UPCENTER));
772             paintUp.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.UPCENTER));
773             paintUp.setAntiAlias(true);
774             paintUp.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
775             float width = paintUp.measureText(message) / 2.0f;
776             Paint.FontMetrics fontMetrics = paintUp.getFontMetrics();
777             canvas.drawText(message, (viewRect.centerX()) - width, viewRect.top + (fontMetrics.descent - fontMetrics.ascent), paintUp);
778         }
779
780         // 画面下部中央に表示する
781         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.LOWCENTER);
782         if ((message != null)&&(message.length() > 0))
783         {
784             Paint paint = new Paint();
785             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.LOWCENTER));
786             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.LOWCENTER));
787             paint.setAntiAlias(true);
788             paint.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
789             float width = paint.measureText(message) / 2.0f;
790             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
791             canvas.drawText(message, (viewRect.centerX()) - width, viewRect.bottom - fontMetrics.bottom, paint);
792         }
793
794         // 画面中央左に表示する
795         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.CENTERLEFT);
796         if ((message != null)&&(message.length() > 0))
797         {
798             Paint paint = new Paint();
799             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.CENTERLEFT));
800             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.CENTERLEFT));
801             paint.setAntiAlias(true);
802             paint.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
803             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
804             float cy = (canvas.getHeight() / 2.0f) - ((fontMetrics.ascent + fontMetrics.descent) / 2.0f);
805             canvas.drawText(message, viewRect.left + 3.0f, cy, paint);
806         }
807
808         // 画面中央右に表示する
809         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.CENTERRIGHT);
810         if ((message != null)&&(message.length() > 0))
811         {
812             Paint paint = new Paint();
813             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.CENTERRIGHT));
814             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.CENTERRIGHT));
815             paint.setAntiAlias(true);
816             paint.setShadowLayer(5.0f, 3.0f, 3.0f, Color.BLACK);  // これで文字に影をつけたい
817             float width = paint.measureText(message);
818             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
819             float cy = (canvas.getHeight() / 2.0f) - ((fontMetrics.ascent + fontMetrics.descent) / 2.0f);
820             canvas.drawText(message, (viewRect.right - 3.0f) - width, cy, paint);
821         }
822         /**/
823     }
824
825     /**
826      * Converts a point on image area to a point on view area.
827      *
828      * @param point A point on image area. (e.g. a live preview image)
829      * @return A point on view area. (e.g. a touch panel view)
830      */
831     private PointF convertPointFromImageArea(PointF point) {
832         if (imageBitmap == null) {
833             return new PointF();
834         }
835
836         float viewPointX = point.x;
837         float viewPointY = point.y;
838         float imageSizeWidth;
839         float imageSizeHeight;
840         if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
841             imageSizeWidth = imageBitmap.getWidth();
842             imageSizeHeight = imageBitmap.getHeight();
843         } else {
844             imageSizeWidth = imageBitmap.getHeight();
845             imageSizeHeight = imageBitmap.getWidth();
846         }
847         float viewSizeWidth = this.getWidth();
848         float viewSizeHeight = this.getHeight();
849         float ratioX = viewSizeWidth / imageSizeWidth;
850         float ratioY = viewSizeHeight / imageSizeHeight;
851         float scale;
852
853         switch (imageScaleType)
854         {
855             case FIT_XY:
856                 viewPointX *= ratioX;
857                 viewPointY *= ratioY;
858                 break;
859             case FIT_CENTER:    // go to next label.
860             case CENTER_INSIDE:
861                 scale = Math.min(ratioX, ratioY);
862                 viewPointX *= scale;
863                 viewPointY *= scale;
864                 viewPointX += (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
865                 viewPointY += (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
866                 break;
867             case CENTER_CROP:
868                 scale = Math.max(ratioX, ratioY);
869                 viewPointX *= scale;
870                 viewPointY *= scale;
871                 viewPointX += (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
872                 viewPointY += (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
873                 break;
874             case CENTER:
875                 viewPointX += viewSizeWidth / 2.0 - imageSizeWidth / 2.0f;
876                 viewPointY += viewSizeHeight / 2.0 - imageSizeHeight / 2.0f;
877                 break;
878             default:
879                 break;
880         }
881         return new PointF(viewPointX, viewPointY);
882     }
883
884     /**
885      * Converts a point on view area to a point on image area.
886      *
887      * @param point A point on view area. (e.g. a touch panel view)
888      * @return A point on image area. (e.g. a live preview image)
889      */
890     private PointF convertPointFromViewArea(PointF point) {
891         if (imageBitmap == null) {
892             return new PointF();
893         }
894
895         float imagePointX = point.x;
896         float imagePointY = point.y;
897         float imageSizeWidth;
898         float imageSizeHeight;
899         if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
900             imageSizeWidth = imageBitmap.getWidth();
901             imageSizeHeight = imageBitmap.getHeight();
902         } else {
903             imageSizeWidth = imageBitmap.getHeight();
904             imageSizeHeight = imageBitmap.getWidth();
905         }
906         float viewSizeWidth = this.getWidth();
907         float viewSizeHeight = this.getHeight();
908         float ratioX = viewSizeWidth / imageSizeWidth;
909         float ratioY = viewSizeHeight / imageSizeHeight;
910         float scale;
911
912         switch (imageScaleType) {
913             case FIT_XY:
914                 imagePointX /= ratioX;
915                 imagePointY /= ratioY;
916                 break;
917             case FIT_CENTER:    // go to next label.
918             case CENTER_INSIDE:
919                 scale = Math.min(ratioX, ratioY);
920                 imagePointX -= (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
921                 imagePointY -= (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
922                 imagePointX /= scale;
923                 imagePointY /= scale;
924                 break;
925             case CENTER_CROP:
926                 scale = Math.max(ratioX, ratioY);
927                 imagePointX -= (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
928                 imagePointY -= (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
929                 imagePointX /= scale;
930                 imagePointY /= scale;
931                 break;
932             case CENTER:
933                 imagePointX -= (viewSizeWidth - imageSizeWidth) / 2.0f;
934                 imagePointY -= (viewSizeHeight - imageSizeHeight) / 2.0f;
935                 break;
936             default:
937                 break;
938         }
939         return new PointF(imagePointX, imagePointY);
940     }
941
942     /**
943      * Converts a rectangle on image area to a rectangle on view area.
944      *
945      * @param rect A rectangle on image area. (e.g. a live preview image)
946      * @return A rectangle on view area. (e.g. a touch panel view)
947      */
948     private RectF convertRectFromImageArea(RectF rect)
949     {
950         if (imageBitmap == null)
951         {
952             return new RectF();
953         }
954
955         PointF imageTopLeft = new PointF(rect.left, rect.top);
956         PointF imageBottomRight = new PointF(rect.right, rect.bottom);
957
958         PointF viewTopLeft = convertPointFromImageArea(imageTopLeft);
959         PointF viewBottomRight = convertPointFromImageArea(imageBottomRight);
960
961         return (new RectF(viewTopLeft.x, viewTopLeft.y, viewBottomRight.x, viewBottomRight.y));
962     }
963
964     /**
965      *
966      *
967      */
968     public void setShowGridFrame(boolean isShowGridFeature)
969     {
970         showGridFeature = isShowGridFeature;
971         try
972         {
973             preferences.putBoolean(IPreferenceCameraPropertyAccessor.SHOW_GRID_STATUS, showGridFeature);
974         }
975         catch (Exception e)
976         {
977             e.printStackTrace();
978         }
979     }
980
981     /**
982      *
983      *
984      */
985     @Override
986     public void toggleShowGridFrame()
987     {
988         setShowGridFrame(!showGridFeature);
989     }
990
991     /**
992      *
993      *
994      */
995     public void setShowLevelGauge(boolean isShowLevelGaugeFeature)
996     {
997         Log.v(TAG, "setShowLevelGauge : " + isShowLevelGaugeFeature);
998         showLevelGaugeFeature = isShowLevelGaugeFeature;
999         try
1000         {
1001             preferences.putBoolean(IPreferenceCameraPropertyAccessor.SHOW_LEVEL_GAUGE_STATUS, showLevelGaugeFeature);
1002             ILevelGauge levelGauge = messageHolder.getLevelGauge();
1003             if (levelGauge == null)
1004             {
1005                 // デジタル水準器がとれない場合は、何もしない
1006                 Log.v(TAG, "setShowLevelGauge : levelGauge is null.");
1007                 return;
1008             }
1009             levelGauge.updateLevelGaugeChecking(isShowLevelGaugeFeature);
1010         }
1011         catch (Exception e)
1012         {
1013             e.printStackTrace();
1014         }
1015     }
1016
1017     /**
1018      *
1019      *
1020      */
1021     @Override
1022     public void toggleShowLevelGauge()
1023     {
1024         setShowLevelGauge(!showLevelGaugeFeature);
1025     }
1026
1027     /**
1028      *
1029      *
1030      */
1031     @Override
1032     public boolean isShowLevelGauge()
1033     {
1034         return (showLevelGaugeFeature);
1035     }
1036
1037     /**
1038      *
1039      *
1040      */
1041     @Override
1042     public boolean isShowGrid()
1043     {
1044         return (showGridFeature);
1045     }
1046
1047
1048     /**
1049      *
1050      *
1051      */
1052     public IMessageDrawer getMessageDrawer()
1053     {
1054         return (messageHolder);
1055     }
1056
1057     /**
1058      *
1059      *
1060      */
1061     @Override
1062     public void showDialog(IDialogDrawer dialogDrawer)
1063     {
1064         this.dialogDrawer = dialogDrawer;
1065     }
1066
1067     /**
1068      *
1069      *
1070      */
1071     @Override
1072     public void hideDialog()
1073     {
1074         this.dialogDrawer = null;
1075         System.gc();
1076     }
1077
1078     /**
1079      *
1080      *
1081      */
1082     @Override
1083     public boolean touchedPosition(float posX, float posY)
1084     {
1085         return ((dialogDrawer != null)&&(dialogDrawer.touchedPosition(posX, posY)));
1086     }
1087 }