1

i am making an app of which it can initialize the camera and then after taking the photo, the photo could be imported and the user to further draw on it.

Coding:

Class A:

   public OnClickListener cameraButtonListener = new OnClickListener()   
   {
      @Override
      public void onClick(View v) 
          {  
               vibrate();
               Toast.makeText(Doodlz.this, R.string.message_initalize_camera, Toast.LENGTH_SHORT).show();
               Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
               startActivityForResult(cameraIntent, CAMERA_REQUEST);               
           }      
   }; 

protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{
    super.onActivityResult(requestCode, resultCode, data);      

    if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) 
    {  
        Bitmap photo = (Bitmap) data.getExtras().get("data"); 
        Bitmap photocopy = photo.copy(Bitmap.Config.ARGB_8888, true);
        doodleView.get_camera_pic(photocopy);
    }
}

doodleView:

   public void get_camera_pic (Bitmap photocopy)
   {
    // get screen dimension first
      WindowManager wm = (WindowManager) context_new.getSystemService(Context.WINDOW_SERVICE);
      Display display = wm.getDefaultDisplay();
      final int screenWidth = display.getWidth();
      final int screenHeight = display.getHeight(); 
      bitmap = photocopy;
      bitmap = Bitmap.createScaledBitmap(bitmap, screenWidth, screenHeight, true);
      bitmapCanvas = new Canvas(bitmap);
      invalidate(); // refresh the screen      
   }

Question:

The photo can be successfully captured using the camera and return to doodleView for user. Yet since the imported image dimension is very small, just a thumbnail size!! (dont know why), so I tired scaling it up and then the resolution is very poor.

My question is that, how modify the above code so as to set the photo taken dimension be fitting to the screen's dimension and the returned photo be 1:1 of the screen instead of getting like a thumbnail one? (best to be fit 1:1 of screen, because if it is then importing as original photo size the photo dimension is then greater then the screen, it then need to scale down and distorted by different ratio of width and height ratio to fit full screen)

Thanks!!

pearmak
  • 4,979
  • 15
  • 64
  • 122
  • @323go: start with this: http://stackoverflow.com/questions/1910608/android-action-image-capture-intent – Alex Cohn Feb 11 '13 at 07:58

2 Answers2

3

This is normal for the default camera application. The way to get the full size image is to tell the camera activity to put the result into a file. First create a file and then start the camera application as follows:

outputFileName = createImageFile(".tmp");
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputFileName));
startActivityForResult(takePictureIntent, takePhotoActionCode);

Then in your onActivityResult, you can get this image file back and manipulate it.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    if (requestCode == takePhotoActionCode)
    {
        if (resultCode == RESULT_OK)
        {
            // NOTE: The intent returned might be NULL if the default camera app was used.
            // This is because the image returned is in the file that was passed to the intent.
                processPhoto(data);
        }
    }
}

processPhoto will look a bit like this:

    protected void processPhoto(Intent i)
    {
        int imageExifOrientation = 0;

// Samsung Galaxy Note 2 and S III doesn't return the image in the correct orientation, therefore rotate it based on the data held in the exif.

        try
        {


    ExifInterface exif;
        exif = new ExifInterface(outputFileName.getAbsolutePath());
        imageExifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                                    ExifInterface.ORIENTATION_NORMAL);
    }
    catch (IOException e1)
    {
        e1.printStackTrace();
    }

    int rotationAmount = 0;

    if (imageExifOrientation == ExifInterface.ORIENTATION_ROTATE_270)
    {
        // Need to do some rotating here...
        rotationAmount = 270;
    }
    if (imageExifOrientation == ExifInterface.ORIENTATION_ROTATE_90)
    {
        // Need to do some rotating here...
        rotationAmount = 90;
    }
    if (imageExifOrientation == ExifInterface.ORIENTATION_ROTATE_180)
    {
        // Need to do some rotating here...
        rotationAmount = 180;
    }       

    int targetW = 240;
    int targetH = 320; 

    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(outputFileName.getAbsolutePath(), bmOptions);
    int photoWidth = bmOptions.outWidth;
    int photoHeight = bmOptions.outHeight;

    int scaleFactor = Math.min(photoWidth/targetW, photoHeight/targetH);

    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap scaledDownBitmap = BitmapFactory.decodeFile(outputFileName.getAbsolutePath(), bmOptions);

    if (rotationAmount != 0)
    {
        Matrix mat = new Matrix();
        mat.postRotate(rotationAmount);
        scaledDownBitmap = Bitmap.createBitmap(scaledDownBitmap, 0, 0, scaledDownBitmap.getWidth(), scaledDownBitmap.getHeight(), mat, true);
    }       

    ImageView iv2 = (ImageView) findViewById(R.id.photoImageView);
    iv2.setImageBitmap(scaledDownBitmap);

    FileOutputStream outFileStream = null;
    try
    {
        mLastTakenImageAsJPEGFile = createImageFile(".jpg");
        outFileStream = new FileOutputStream(mLastTakenImageAsJPEGFile);
        scaledDownBitmap.compress(Bitmap.CompressFormat.JPEG, 75, outFileStream);
    }
    catch (Exception e)
    {
        e.printStackTrace();
            }
    }

One thing to note is that on Nexus devices the calling activity is not normally destroyed. However on Samsung Galaxy S III and Note 2 devices the calling activity is destroyed. Therefore the just storing the outputFileName as a member variable in the Activity will result in it being null when the camera app returns unless you remember to save it when the activity dies. It's good practice to do that anyhow, but this is a mistake that I've made before so I thought I'd mention it.

EDIT:

Regarding your comment, the createImageFile is a not in the standard API, it's something I wrote (or I may have borrowed :-), I don't remember), here is the method for createImageFile():

    private File createImageFile(String fileExtensionToUse) throws IOException 
{

    File storageDir = new File(
            Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES
            ), 
            "MyImages"
        );      

    if(!storageDir.exists())
    {
        if (!storageDir.mkdir())
        {
            Log.d(TAG,"was not able to create it");
        }
    }
    if (!storageDir.isDirectory())
    {
        Log.d(TAG,"Don't think there is a dir there.");
    }

    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "FOO_" + timeStamp + "_image";

    File image = File.createTempFile(
        imageFileName, 
        fileExtensionToUse, 
        storageDir
    );

    return image;
}    
Mark Fidell
  • 1,123
  • 8
  • 14
  • thanks for your detailed answer. I am now trying it =) Just would like to know for the first one: CreateImageFile(".tmp") and it underlines The method createImageFile(String) is undefined for the type new View.OnClickListener(){}. Is that a way to tackle it? – pearmak Feb 09 '13 at 14:58
  • please allow me to study a while hahaa i am now trying and working on it...really thanks a lot for your help!! btw how come you would know about the Samsung issue..! i just think all device running on android has the same operating system and would give same result... – pearmak Feb 09 '13 at 15:11
  • 1
    I came across the Samsung issue because I develop on a Galaxy Nexus and Nexus 7 but use a Note II as my personal phone. I was testing my app and all was working fine, then loaded it onto my personal phone and had issues, I then borrowed an S3 from a friend and had the same issue. Lots of digging later and eventually found the problem. You are right that the main OS is the same, but many manufactures change components in the OS, for example the default camera app on the Nexus phones is not the same as the one on the Note II and hence the orientation problem. – Mark Fidell Feb 09 '13 at 15:20
  • I got a problem that after declaring outputFileName Type as File, for the lines exif = new ExifInterface(outputFileName); it underlines and says "The constructor ExifInterface(File) is undefined" and suggest outputFileName to be declared as String. Same for lines BitmapFactory.decodeFile, underlining the decodeFile. – pearmak Feb 09 '13 at 15:45
  • yes, in actual fact in processPhoto() you would want to use outputFileName.getAbsolutePath(). I'll update the code. – Mark Fidell Feb 09 '13 at 15:55
  • Did you manage to get it working then? The code I have provided above should sort your issue. If it's still not working, let me know, otherwise please flag your question as resolved. – Mark Fidell Feb 11 '13 at 17:19
1

To access the full image, you either need to access the intent URI by using data.getData() in your doodleView, or (better) provide your own URI for storing the image by passing it to the intent by supplying a URI in EXTRA_OUTPUT extra.

323go
  • 14,143
  • 6
  • 33
  • 41
  • you mean need to save the file output from the camera at location A and then load back the picture from the location A? – pearmak Feb 09 '13 at 13:55
  • The camera app will save the image for you. A full size image is a bit too unwieldy to pass as Intent extra. – 323go Feb 10 '13 at 05:03
  • if the user use another camera app instead of the build in app, is there a way to know where the camera has saved the image so that i can call it out? do you have some examples? – pearmak Feb 10 '13 at 05:45
  • As written in the answer, it should be in the URI of the response intent: `data.getData()`, but it's better to pass EXTRA_OUTPUT and tell it where to put it. – 323go Feb 10 '13 at 05:48
  • _it's better to pass EXTRA_OUTPUT and tell it where to put it_ - except there are quite a few Android devices that crash when EXTRA_OUTPUT is specified – Alex Cohn Feb 10 '13 at 19:57