HTML 문서를 프린터로 인쇄하기

Android 2014. 2. 13. 13:06

- 간단한 사진 이외에 복잡한 문서를 인쇄하기 위해서, 안드로이드는 HTML 형식의 문서를 출력할 수 있도록 지원해준다. Android 4.4 (API Level 19)부터 WebView에 관련 API를 제공하고 있다.

- HTML이 모두 로딩되는 시점을 알기 위해 WebViewClient를 생성하고, WebView에 HTML 문서를 로딩시간다. 모두 로딩이 되지 않은 상태에서 인쇄를 하고자 시도하면, 비어있는 부분이 출력되는 등의 오동작을 하게 된다. 또한, WebView 객체는 출력이 완료되기까지 GC가 되면 안되므로 주의해야 한다. 아래는 관련 코드이다.

private WebView mWebView;

private void doWebViewPrint() {
   
// Create a WebView object specifically for printing
   
WebView webView = new WebView(getActivity());
    webView
.setWebViewClient(new WebViewClient() {

           
public boolean shouldOverrideUrlLoading(WebView view, String url) {
               
return false;
           
}

           
@Override
           
public void onPageFinished(WebView view, String url) {
               
Log.i(TAG, "page finished loading " + url);
                createWebPrintJob
(view);
                mWebView
= null;
           
}
   
});

   
// Generate an HTML document on the fly:
   
String htmlDocument = "<html><body><h1>Test Content</h1><p>Testing, " +
           
"testing, testing...</p></body></html>";
    webView
.loadDataWithBaseURL(null, htmlDocument, "text/HTML", "UTF-8", null);

   
// Keep a reference to WebView object until you pass the PrintDocumentAdapter
   
// to the PrintManager
    mWebView
= webView;
}

loadDataWithBaseURL() 에서  assets/ 의 내용을 불러오기 위해서는 아래와 같이 한다.

webView.loadDataWithBaseURL("file:///android_asset/images/", htmlBody,
       
"text/HTML", "UTF-8", null);

- 외부 URL에서 불러오기 위해서는 아래와 같이 한다.

// Print an existing web page (remember to request INTERNET permission!):
webView
.loadUrl("http://developer.android.com/about/index.html");

- WebView를 통해 인쇄할때에는 아래와 같은 제약 사항이 있다.

  1. Header, Footer, Page Number등을 추가할 수 없다.
  2. 인쇄 페이지를 지정할 수 없다. (예, 10페이지중 2~4페이지만 출력)
  3. 한번에 하나의 인쇄만 진행할 수 있다.
  4. HTML문서에 CSS 인쇄 항목(Landscape 같은)등은 지원하지 않는다.
  5. 인쇄를 시작하도록 하기 위해 JavaScript를 사용할 수 없다.

- 인쇄 작업을 생성하려면 아래와 같이 한다.
private void createWebPrintJob(WebView webView) {

   
// Get a PrintManager instance
   
PrintManager printManager = (PrintManager) getActivity()
           
.getSystemService(Context.PRINT_SERVICE);

   
// Get a print adapter instance
   
PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();

   
// Create a print job with name and adapter instance
   
String jobName = getString(R.string.app_name) + " Document";
   
PrintJob printJob = printManager.print(jobName, printAdapter,
           
new PrintAttributes.Builder().build());

   
// Save the job object for later status checking
    mPrintJobs
.add(printJob);
}

- 위에서 PrintJob을 저장했는데, 이를 통해서 인쇄 진행 상태등을 확인할 수 있다. 인쇄를 진행하면서 Framework에서 알림표시를 하므로, 따로 앱에서 표시해줄 필요는 없다.


출처 : http://developer.android.com/


설정

트랙백

댓글

간단한 사진을 프린터로 인쇄하기

Android 2014. 2. 12. 21:24

- Android 4.4 (API Level 19) 부터는 앱에서 바로 프린팅을 할 수 있는 Framework를 제공한다. Android Support Library v4에서도 프린팅을 위한 최소한의 API는 제공하고 있으므로, 그 이하 버전에서도 사용할 수 있다.

- Support Library의 PrintHelper를 이용해 이미지를 프린트 하려면 아래와 같이 한다. setScaleMode()는 이미지를 인쇄 영역 내부에 출력(이미지 전체 출력, SCALE_MODE_FIT)할지, 이미지를 인쇄 영역에 꽉 채울지(이미지 일부가 잘릴 수 있음, SCALE_MODE_FILL) 선택한다. printBitmap()이 호출되면 Android 프린팅 UI가 표시되어 출력을 진행하므로, 더이상 해줄 것은 없다.

private void doPhotoPrint() {
   
PrintHelper photoPrinter = new PrintHelper(getActivity());
    photoPrinter
.setScaleMode(PrintHelper.SCALE_MODE_FIT);
   
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
            R
.drawable.droids);
    photoPrinter
.printBitmap("droids.jpg - test print", bitmap);
}


설정

트랙백

댓글

카메라 제어

Android 2014. 2. 10. 19:30
  • 우선 카메라 Object를 얻어야 한다. Open을 할 때 UI Thread에서 하면 안된다.
    다른 앱이 카메라를 사용중이거나 다른 문제가 있을 경우 아래 코드의 try에 걸리게 된다.
    API Level 9 이상에서는 멀티 카메라를 지원하므로 ID값을 입력하지만, 그 이전 API에서는 open()하면 첫번째 뒷면 카메라의 Object가 나온다.

    private boolean safeCameraOpen(int id) {
       
    boolean qOpened = false;
     
       
    try {
            releaseCameraAndPreview
    ();
            mCamera
    = Camera.open(id);
            qOpened
    = (mCamera != null);
       
    } catch (Exception e) {
           
    Log.e(getString(R.string.app_name), "failed to open Camera");
            e
    .printStackTrace();
       
    }

       
    return qOpened;    
    }

    private void releaseCameraAndPreview() {
        mPreview
    .setCamera(null);
       
    if (mCamera != null) {
            mCamera
    .release();
            mCamera
    = null;
       
    }
    }
  • 카메라가 찍는 영상을 화면에 미리보기는 SurfaceView에 하게 되는데, 아래와 같이 구현해주면 된다. 

    class Preview extends ViewGroup implements SurfaceHolder.Callback {

       
    SurfaceView mSurfaceView;
       
    SurfaceHolder mHolder;

       
    Preview(Context context) {
           
    super(context);

            mSurfaceView
    = new SurfaceView(context);
            addView
    (mSurfaceView);

           
    // Install a SurfaceHolder.Callback so we get notified when the
           
    // underlying surface is created and destroyed.
            mHolder
    = mSurfaceView.getHolder();
            mHolder
    .addCallback(this);
            mHolder
    .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
       
    }

    }

  • (Preview Class 내부) setCamera()로 카메라 Object를 넘겨주면, startPreview()를 통해 미리보기가 시작된다.

    public void setCamera(Camera camera) {
       
    if (mCamera == camera) { return; }
       
        stopPreviewAndFreeCamera
    ();
       
        mCamera
    = camera;
       
       
    if (mCamera != null) {
           
    List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
            mSupportedPreviewSizes
    = localSizes;
            requestLayout
    ();
         
           
    try {
                mCamera
    .setPreviewDisplay(mHolder);
           
    } catch (IOException e) {
                e
    .printStackTrace();
           
    }
         
           
    // Important: Call startPreview() to start updating the preview
           
    // surface. Preview must be started before you can take a picture.
            mCamera
    .startPreview();
       
    }
    }
  • 카메라 관련 설정(줌 Level 등)이 변경되면, 아래와 같이 setParameters()를 이용해 미리보기를 변경할 수 있다. 아래 예제는 미리보기 View 크기 변경임.
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
       
    // Now that the size is known, set up the camera parameters and begin
       
    // the preview.
       
    Camera.Parameters parameters = mCamera.getParameters();
        parameters
    .setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        requestLayout
    ();
        mCamera
    .setParameters(parameters);

       
    // Important: Call startPreview() to start updating the preview surface.
       
    // Preview must be started before you can take a picture.
        mCamera
    .startPreview();
    }
  • 미리보기 방향을 변경하려면, setCameraDisplayOrientation() 메소드를 사용한다. API Level 14 이전에는 방향 변경전에 미리보기를 중지하고, 설정 후 재시작해야 한다.
    아래 코드는 현재 화면과 같은 방향으로 미리보기를 표시하기 위한 방법이다.

     public static void setCameraDisplayOrientation(Activity activity,
             
    int cameraId, android.hardware.Camera camera) {
         android
    .hardware.Camera.CameraInfo info =
                 
    new android.hardware.Camera.CameraInfo();
         android
    .hardware.Camera.getCameraInfo(cameraId, info);
         
    int rotation = activity.getWindowManager().getDefaultDisplay()
                 
    .getRotation();
         
    int degrees = 0;
         
    switch (rotation) {
             
    case Surface.ROTATION_0: degrees = 0; break;
             
    case Surface.ROTATION_90: degrees = 90; break;
             
    case Surface.ROTATION_180: degrees = 180; break;
             
    case Surface.ROTATION_270: degrees = 270; break;
         
    }

         
    int result;
         
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
             result
    = (info.orientation + degrees) % 360;
             result
    = (360 - result) % 360;  // compensate the mirror
         
    } else {  // back-facing
             result
    = (info.orientation - degrees + 360) % 360;
         
    }
         camera
    .setDisplayOrientation(result);
     
    }
     
  • 사진은 Camera.takePicture()을 통해서 찍을 수 있다. Camera.PictureCallback Camera.ShutterCallback으로 결과를 받는다.
  • 연속적으로 사진 찍기는 Camera.PreviewCallback을 통해서 할 수 있다.
  • 사진을 찍은 후에는 미리보기가 멈추므로, 미리보기를 다시 시작해줘야 한다.
  • 카메라 사용 후 Release는 미리보기 SurfaceView가 Destroy 될 때 하면 좋다. 또한, onPause()에서도 Release를 해야 하며, onResume()에서 다시 카메라를 Open해야 한다. 위 setCamera()처럼 카메라 초기화시에도 항상 미리보기 및 카메라를 Release해야 한다.

    public void surfaceDestroyed(SurfaceHolder holder) {
       
    // Surface will be destroyed when we return, so stop the preview.
       
    if (mCamera != null) {
           
    // Call stopPreview() to stop updating the preview surface.
            mCamera
    .stopPreview();
       
    }
    }

    /**
     * When this function returns, mCamera will be null.
     */

    private void stopPreviewAndFreeCamera() {

       
    if (mCamera != null) {
           
    // Call stopPreview() to stop updating the preview surface.
            mCamera
    .stopPreview();
       
           
    // Important: Call release() to release the camera for use by other
           
    // applications. Applications should release the camera immediately
           
    // during onPause() and re-open() it during onResume()).
            mCamera
    .release();
       
            mCamera
    = null;
       
    }
    }


출처 : http://developer.android.com/

설정

트랙백

댓글

간단히 동영상 찍기

Android 2014. 2. 7. 10:57
  • 사진 찍기와 동일한 퍼미션이 필요하다.
    <manifest ... >
       
    <uses-feature android:name="android.hardware.camera"
                     
    android:required="true" />
        ...
    </manifest>
  • 동영상 촬영을 위해 아래와 같이 카메라 앱을 띄운다.
    static final int REQUEST_VIDEO_CAPTURE = 1;

    private void dispatchTakeVideoIntent() {
       
    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
       
    if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult
    (takeVideoIntent, REQUEST_VIDEO_CAPTURE);
       
    }
    }
  • 카메라 앱에서 촬영한 영상을 VideoView에서 보기 위해서 아래와 같이 한다.
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       
    if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
           
    Uri videoUri = intent.getData();
            mVideoView
    .setVideoURI(videoUri);
       
    }
    }


출처 : http://developer.android.com/

설정

트랙백

댓글