From bfab14264c6b8aee87d0383df8c00ca844c3bee4 Mon Sep 17 00:00:00 2001 From: jinwu <jinwu@codeaurora.org> Date: Fri, 21 Sep 2018 18:33:37 +0800 Subject: [PATCH] SnapdraongCamera:add HEIF support add option to allow user to save captured image with HEIF format. Change-Id: I267b783bf7e4f41f523ef2ac4fbb734657b8e827 CRs-Fixed: 2312764 --- Android.mk | 1 + res/values/camera2arrays.xml | 10 +++ res/values/qcomstrings.xml | 5 ++ res/xml/capture_preferences.xml | 8 +++ res/xml/setting_menu_preferences.xml | 10 +++ src/com/android/camera/CaptureModule.java | 19 ++++++ src/com/android/camera/MediaSaveService.java | 68 +++++++++++++++++++ src/com/android/camera/SettingsActivity.java | 1 + src/com/android/camera/SettingsManager.java | 11 +++ src/com/android/camera/Storage.java | 66 ++++++++++++++++-- .../camera/imageprocessor/PostProcessor.java | 16 ++++- 11 files changed, 207 insertions(+), 8 deletions(-) diff --git a/Android.mk b/Android.mk index 557a04750..ba490b2e3 100755 --- a/Android.mk +++ b/Android.mk @@ -8,6 +8,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview LOCAL_STATIC_JAVA_LIBRARIES += xmp_toolkit +LOCAL_STATIC_JAVA_LIBRARIES += androidx.heifwriter_heifwriter LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES += $(call all-java-files-under, src_pd) diff --git a/res/values/camera2arrays.xml b/res/values/camera2arrays.xml index e05303325..2916736cf 100755 --- a/res/values/camera2arrays.xml +++ b/res/values/camera2arrays.xml @@ -508,6 +508,16 @@ <item>320x240</item> </string-array> + <string-array name="pref_camera2_picture_format_entries" translatable="false"> + <item>@string/pref_camera2_picture_format_entry_0</item> + <item>@string/pref_camera2_picture_format_entry_1</item> + </string-array> + + <string-array name="pref_camera2_picture_format_entryvalues" translatable="false"> + <item>0</item> + <item>1</item> + </string-array> + <!-- Camera Preferences focus mode dialog box entries --> <string-array name="pref_camera2_focusmode_entries" translatable="false"> <item>@string/pref_camera_focusmode_entry_auto</item> diff --git a/res/values/qcomstrings.xml b/res/values/qcomstrings.xml index bf6deb455..46cc2ab9d 100755 --- a/res/values/qcomstrings.xml +++ b/res/values/qcomstrings.xml @@ -1258,6 +1258,11 @@ <string name="pref_camera2_video_hdr_entry_value_enable" translatable="false">1</string> <string name="pref_camera2_video_hdr_entry_value_disable" translatable="false">0</string> + <string name="pref_camera2_picture_format_title">Picture Format</string> + <string name="pref_camera2_picture_format_default">0</string> + <string name="pref_camera2_picture_format_entry_0">JPEG</string> + <string name="pref_camera2_picture_format_entry_1">HEIF</string> + <string name="pref_camera2_deepportrait_entry_value_disable" translatable="false">off</string> <string name="pref_camera2_deepportrait_entry_value_enable" translatable="false">on</string> <string name="pref_camera_scenemode_entry_deepportrait" translatable="false">Deepportrait</string> diff --git a/res/xml/capture_preferences.xml b/res/xml/capture_preferences.xml index bc74e280b..7575eb1a6 100755 --- a/res/xml/capture_preferences.xml +++ b/res/xml/capture_preferences.xml @@ -156,6 +156,14 @@ camera:singleIcon="@drawable/ic_settings_picturesize" camera:title="@string/pref_camera_picturesize_title"/> + <IconListPreference + camera:defaultValue="@string/pref_camera2_picture_format_default" + camera:entries="@array/pref_camera2_picture_format_entries" + camera:entryValues="@array/pref_camera2_picture_format_entryvalues" + camera:key="pref_camera2_picture_format_key" + camera:singleIcon="@drawable/ic_settings_storage" + camera:title="@string/pref_camera2_picture_format_title"/> + <IconListPreference camera:defaultValue="@string/pref_exposure_default" camera:key="pref_camera2_exposure_key" diff --git a/res/xml/setting_menu_preferences.xml b/res/xml/setting_menu_preferences.xml index da47590be..a9268e6cc 100755 --- a/res/xml/setting_menu_preferences.xml +++ b/res/xml/setting_menu_preferences.xml @@ -141,6 +141,16 @@ android:layout="@layout/preference" android:title="@string/pref_camera2_shutter_sound_title" /> + <ListPreference + android:defaultValue="@string/pref_camera2_picture_format_default" + android:entries="@array/pref_camera2_picture_format_entries" + android:entryValues="@array/pref_camera2_picture_format_entryvalues" + android:icon="@drawable/ic_settings_storage" + android:key="pref_camera2_picture_format_key" + android:layout="@layout/preference" + android:summary="%s" + android:title="@string/pref_camera2_picture_format_title"/> + <SwitchPreference android:defaultValue="false" android:key="pref_camera2_mono_only_key" diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index 7bfee3041..0c93f9b73 100755 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -31,6 +31,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.graphics.Matrix; import android.graphics.Point; @@ -2422,6 +2423,24 @@ public class CaptureModule implements CameraModule, PhotoController, byte[] bytes = getJpegData(image); + if (mSettingsManager.getSavePictureFormat() == + SettingsManager.HEIF_FORMAT) { + String value = mSettingsManager.getValue( + SettingsManager.KEY_JPEG_QUALITY); + int qualityNumber = getQualityNumber(value); + mActivity.getMediaSaveService().addHEIFImageFromJpeg(bytes, + title,date,null,image.getWidth(),image.getHeight(), + 0,null,mContentResolver, + mOnMediaSavedListener,qualityNumber,"heif"); + image.close(); + if (mLongshotActive) { + mLastJpegData = bytes; + } else { + mActivity.updateThumbnail(bytes); + } + return; + } + if (image.getFormat() == ImageFormat.RAW10) { mActivity.getMediaSaveService().addRawImage(bytes, title, "raw"); diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java index 217f44f27..8394162db 100644 --- a/src/com/android/camera/MediaSaveService.java +++ b/src/com/android/camera/MediaSaveService.java @@ -163,6 +163,23 @@ public class MediaSaveService extends Service { t.execute(); } + public void addHEIFImageFromJpeg(byte[] data, String title, long date, Location loc, + int width, int height, int orientation, ExifInterface exif, + ContentResolver resolver, OnMediaSavedListener listener, + int qualitiy, String pictureFormat) { + if (isQueueFull()) { + Log.e(TAG, "Cannot add image when the queue is full"); + return; + } + HEIFImageSaveTask t = new HEIFImageSaveTask(data, title, date, loc, width, height, orientation, + exif, resolver, listener, qualitiy, pictureFormat); + mMemoryUse += data.length; + if (isQueueFull()) { + onQueueFull(); + } + t.execute(); + } + public void addClearsightImage(byte[] clearsight, GImage bayer, GDepth.DepthMap depthMap, String title, long date, Location loc, int width, int height, int orientation, ExifInterface exif, @@ -328,6 +345,57 @@ public class MediaSaveService extends Service { } } + private class HEIFImageSaveTask extends AsyncTask<Void, Void, Uri> { + private byte[] data; + private String title; + private long date; + private Location loc; + private int width, height; + private int orientation; + private ExifInterface exif; + private ContentResolver resolver; + private OnMediaSavedListener listener; + private int quality; + private String pictureFormat; + + public HEIFImageSaveTask(byte[] data, String title, long date, Location loc, + int width, int height, int orientation, ExifInterface exif, + ContentResolver resolver, OnMediaSavedListener listener, + int quality,String pictureFormat) { + this.data = data; + this.title = title; + this.date = date; + this.loc = loc; + this.width = width; + this.height = height; + this.orientation = orientation; + this.exif = exif; + this.resolver = resolver; + this.listener = listener; + this.quality = quality; + this.pictureFormat = pictureFormat; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected Uri doInBackground(Void... params) { + return Storage.addHeifImage( + resolver,title,date,loc,orientation,exif,data, + width,height,quality,pictureFormat); + } + + @Override + protected void onPostExecute(Uri uri) { + boolean previouslyFull = isQueueFull(); + mMemoryUse -= data.length; + if (isQueueFull() != previouslyFull) onQueueAvailable(); + } + } + private class ImageSaveTask extends AsyncTask <Void, Void, Uri> { private byte[] data; private String title; diff --git a/src/com/android/camera/SettingsActivity.java b/src/com/android/camera/SettingsActivity.java index e413090a4..e0330063a 100755 --- a/src/com/android/camera/SettingsActivity.java +++ b/src/com/android/camera/SettingsActivity.java @@ -452,6 +452,7 @@ public class SettingsActivity extends PreferenceActivity { private void initializePreferences() { updatePreference(SettingsManager.KEY_PICTURE_SIZE); + updatePreference(SettingsManager.KEY_PICTURE_FORMAT); updatePreference(SettingsManager.KEY_VIDEO_QUALITY); updatePreference(SettingsManager.KEY_EXPOSURE); updatePreference(SettingsManager.KEY_VIDEO_HIGH_FRAME_RATE); diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java index 7640cb53b..4346f2599 100755 --- a/src/com/android/camera/SettingsManager.java +++ b/src/com/android/camera/SettingsManager.java @@ -102,6 +102,8 @@ public class SettingsManager implements ListMenu.SettingsListener { public static final int SCENE_MODE_PROMODE_INT = SCENE_MODE_CUSTOM_START + 9; public static final int SCENE_MODE_DEEPZOOM_INT = SCENE_MODE_CUSTOM_START + 10; public static final int SCENE_MODE_DEEPPORTRAIT_INT = SCENE_MODE_CUSTOM_START + 11; + public static final int JPEG_FORMAT = 0; + public static final int HEIF_FORMAT = 1; public static final String SCENE_MODE_DUAL_STRING = "100"; public static final String SCENE_MODE_SUNSET_STRING = "10"; public static final String SCENE_MODE_LANDSCAPE_STRING = "4"; @@ -124,6 +126,7 @@ public class SettingsManager implements ListMenu.SettingsListener { public static final String KEY_CAMERA_ID = "pref_camera2_id_key"; public static final String KEY_SWITCH_CAMERA = "pref_camera2_switch_camera_key"; public static final String KEY_PICTURE_SIZE = "pref_camera2_picturesize_key"; + public static final String KEY_PICTURE_FORMAT = "pref_camera2_picture_format_key"; public static final String KEY_ISO = "pref_camera2_iso_key"; public static final String KEY_EXPOSURE = "pref_camera2_exposure_key"; public static final String KEY_TIMER = "pref_camera2_timer_key"; @@ -1693,11 +1696,19 @@ public class SettingsManager implements ListMenu.SettingsListener { return num_val; } + + public boolean isCamera2HDRSupport(){ String value = getValue(KEY_HDR); return value != null && value.equals("enable"); } + public int getSavePictureFormat() { + String value = getValue(SettingsManager.KEY_PICTURE_FORMAT); + if (value == null) return 0; + return Integer.valueOf(value); + } + public boolean isZSLInHALEnabled(){ String value = getValue(KEY_ZSL); String halZSLValue = mContext.getString(R.string.pref_camera2_zsl_entryvalue_hal_zsl); diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java index 13f65e14c..a71a88a47 100755 --- a/src/com/android/camera/Storage.java +++ b/src/com/android/camera/Storage.java @@ -18,14 +18,18 @@ package com.android.camera; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.ContentValues; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.location.Location; import android.net.Uri; import android.os.Build; import android.os.Environment; +import android.os.Handler; import android.os.StatFs; import android.provider.MediaStore.Images; import android.provider.MediaStore.Images.ImageColumns; @@ -35,6 +39,8 @@ import android.util.Log; import com.android.camera.data.LocalData; import com.android.camera.exif.ExifInterface; import com.android.camera.util.ApiHelper; +import androidx.heifwriter.HeifWriter; +import android.graphics.ImageFormat; public class Storage { private static final String TAG = "CameraStorage"; @@ -135,13 +141,24 @@ public class Storage { values.put(ImageColumns.TITLE, title); if (mimeType.equalsIgnoreCase("jpeg") || mimeType.equalsIgnoreCase("image/jpeg") || + mimeType.equalsIgnoreCase("heif") || mimeType == null) { - values.put(ImageColumns.DISPLAY_NAME, title + ".jpg"); + + if (mimeType.equalsIgnoreCase("heif")){ + values.put(ImageColumns.DISPLAY_NAME, title + ".heic"); + } else { + values.put(ImageColumns.DISPLAY_NAME, title + ".jpg"); + } + } else { values.put(ImageColumns.DISPLAY_NAME, title + ".raw"); } values.put(ImageColumns.DATE_TAKEN, date); - values.put(ImageColumns.MIME_TYPE, "image/jpeg"); + if (mimeType.equalsIgnoreCase("heif")) { + values.put(ImageColumns.MIME_TYPE, "image/heif"); + } else { + values.put(ImageColumns.MIME_TYPE, "image/jpeg"); + } // Clockwise rotation in degrees. 0, 90, 180, or 270. values.put(ImageColumns.ORIENTATION, orientation); values.put(ImageColumns.DATA, path); @@ -180,6 +197,40 @@ public class Storage { return size; } + public static Uri addHeifImage(ContentResolver resolver, String title, long date, + Location location, int orientation, ExifInterface exif, byte[] data, int width, + int height, int quality, String mimeType) { + String path = generateFilepath(title, mimeType); + Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length); + if (bitmap != null) { + try { + HeifWriter.Builder builder = + new HeifWriter.Builder(path,width, height,HeifWriter.INPUT_MODE_BITMAP); + builder.setQuality(quality); + builder.setMaxImages(1); + builder.setPrimaryIndex(0); + builder.setRotation(orientation); + HeifWriter heifWriter = builder.build(); + heifWriter.start(); + heifWriter.addBitmap(bitmap); + heifWriter.stop(3000); + heifWriter.close(); + } catch (IOException|IllegalStateException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + bitmap.recycle(); + } + File f = new File(path); + int size = 0; + if (f.exists() && f.isFile()) { + size = (int) f.length(); + } + return addImage(resolver, title, date, location, orientation, + size, path, width, height, mimeType); + } + // Overwrites the file and updates the MediaStore, or inserts the image if // one does not already exist. public static void updateImage(Uri imageUri, ContentResolver resolver, String title, long date, @@ -224,11 +275,16 @@ public class Storage { } public static String generateFilepath(String title, String pictureFormat) { - if (pictureFormat == null || pictureFormat.equalsIgnoreCase("jpeg")) { + if (pictureFormat == null || pictureFormat.equalsIgnoreCase("jpeg") + || pictureFormat.equalsIgnoreCase("heif")) { + String suffix = ".jpg"; + if (pictureFormat.equalsIgnoreCase("heif")) { + suffix = ".heic"; + } if (isSaveSDCard() && SDCard.instance().isWriteable()) { - return SDCard.instance().getDirectory() + '/' + title + ".jpg"; + return SDCard.instance().getDirectory() + '/' + title + suffix; } else { - return DIRECTORY + '/' + title + ".jpg"; + return DIRECTORY + '/' + title + suffix; } } else { return RAW_DIRECTORY + '/' + title + ".raw"; diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java index c227f32b2..f91f6b031 100755 --- a/src/com/android/camera/imageprocessor/PostProcessor.java +++ b/src/com/android/camera/imageprocessor/PostProcessor.java @@ -1278,9 +1278,19 @@ public class PostProcessor{ mController.showCapturedReview(bytes, orientation); } } else { - mActivity.getMediaSaveService().addImage( - bytes, title, date, null, image.getCropRect().width(), image.getCropRect().height(), - orientation, null, mController.getMediaSavedListener(), mActivity.getContentResolver(), "jpeg"); + if(SettingsManager.getInstance().getSavePictureFormat() == + SettingsManager.HEIF_FORMAT) { + String value = SettingsManager.getInstance().getValue( + SettingsManager.KEY_JPEG_QUALITY); + int qualityNumber = CaptureModule.getQualityNumber(value); + mActivity.getMediaSaveService().addHEIFImageFromJpeg(bytes,title,date,null, + image.getWidth(),image.getHeight(),orientation,null,mActivity.getContentResolver(), + mController.getMediaSavedListener(),qualityNumber,"heif"); + } else { + mActivity.getMediaSaveService().addImage( + bytes, title, date, null, image.getCropRect().width(), image.getCropRect().height(), + orientation, null, mController.getMediaSavedListener(), mActivity.getContentResolver(), "jpeg"); + } mController.updateThumbnailJpegData(bytes); image.close(); } -- GitLab