├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── 11.gif ├── README.MD ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── huahua │ │ └── su │ │ └── bitmapwithwatermark │ │ ├── MainActivity.java │ │ ├── SelectPicActivity.java │ │ └── util │ │ └── FileUtil.java │ └── res │ ├── drawable │ └── shape_select_pic.xml │ ├── layout │ ├── activity_main.xml │ └── dialog_select_pic.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | **/local.properties 9 | **/.DS_Store 10 | **/bin/ 11 | **/gen/ 12 | **/out/ 13 | gradle/ 14 | **/*.iml 15 | .idea/ 16 | .DS_Store 17 | bin/ 18 | 19 | app/BuglyUploadLog.txt 20 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | BitmapWithWatermark -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halibobo/WaterMark/7893a5a7dc319827b08832b950aa3835944def84/11.gif -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halibobo/WaterMark/7893a5a7dc319827b08832b950aa3835944def84/README.MD -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.huahua.su.bitmapwithwatermark" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.3.0' 26 | compile 'com.android.support:cardview-v7:23.3.0' 27 | } 28 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\android\android_adt_eclipse\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/huahua/su/bitmapwithwatermark/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.huahua.su.bitmapwithwatermark; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Paint; 9 | import android.graphics.Rect; 10 | import android.graphics.Typeface; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.os.Bundle; 13 | import android.util.Log; 14 | import android.view.View; 15 | import android.widget.EditText; 16 | import android.widget.ImageView; 17 | import android.widget.Toast; 18 | 19 | import com.huahua.su.bitmapwithwatermark.util.FileUtil; 20 | 21 | import java.util.Date; 22 | 23 | public class MainActivity extends AppCompatActivity { 24 | 25 | private final int requestCode = 0x101; 26 | private ImageView imageView; 27 | private EditText editText; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_main); 33 | initViews(); 34 | } 35 | 36 | private void initViews() { 37 | imageView = (ImageView) findViewById(R.id.imageShow); 38 | editText = (EditText) findViewById(R.id.editText); 39 | findViewById(R.id.btnPhoto).setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | Intent intent = new Intent(MainActivity.this, SelectPicActivity.class); 43 | startActivityForResult(intent, requestCode); 44 | } 45 | }); 46 | } 47 | 48 | @Override 49 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 50 | if (resultCode == Activity.RESULT_OK) { 51 | if (requestCode == this.requestCode) { 52 | String picPath; 53 | picPath = data.getStringExtra(SelectPicActivity.KEY_PHOTO_PATH); 54 | if (picPath == null || picPath.equals("")) { 55 | Toast.makeText(this, R.string.no_choosed_pic, Toast.LENGTH_SHORT).show(); 56 | return; 57 | } 58 | Toast.makeText(this,"pic = "+picPath, Toast.LENGTH_SHORT).show(); 59 | Bitmap bm = null; 60 | try { 61 | bm = FileUtil.getInstance().getImage(picPath,imageView.getWidth(),imageView.getHeight()); //获取限定宽高的bitmap,不限定则容易占用内存过大及OOM 62 | if (bm == null) { 63 | Toast.makeText(this, R.string.no_choosed_pic, Toast.LENGTH_SHORT).show(); 64 | }else{ 65 | if (addWatermarkBitmap(bm, editText.getText().toString(), imageView.getWidth(), imageView.getHeight())) { 66 | Toast.makeText(this, "水印生成成功,文件已保存在 " + FileUtil.getInstance().IMAGE_PATH, Toast.LENGTH_SHORT).show(); 67 | } 68 | } 69 | } catch (OutOfMemoryError e) { 70 | e.printStackTrace(); 71 | if (bm != null) { 72 | bm.recycle(); 73 | } 74 | System.gc(); 75 | } 76 | } 77 | } 78 | } 79 | 80 | private boolean addWatermarkBitmap(Bitmap bitmap,String str,int w,int h) { 81 | int destWidth = w; //此处的bitmap已经限定好宽高 82 | int destHeight = h; 83 | Log.v("tag","width = " + destWidth+" height = "+destHeight); 84 | 85 | Bitmap icon = Bitmap.createBitmap(destWidth, destHeight, Bitmap.Config.ARGB_8888); //定好宽高的全彩bitmap 86 | Canvas canvas = new Canvas(icon);//初始化画布绘制的图像到icon上 87 | 88 | Paint photoPaint = new Paint(); //建立画笔 89 | photoPaint.setDither(true); //获取跟清晰的图像采样 90 | photoPaint.setFilterBitmap(true);//过滤一些 91 | 92 | Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());//创建一个指定的新矩形的坐标 93 | Rect dst = new Rect(0, 0, destWidth, destHeight);//创建一个指定的新矩形的坐标 94 | canvas.drawBitmap(bitmap, src, dst, photoPaint);//将photo 缩放或则扩大到 dst使用的填充区photoPaint 95 | 96 | Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);//设置画笔 97 | textPaint.setTextSize(destWidth/20);//字体大小 98 | textPaint.setTextAlign(Paint.Align.CENTER); 99 | textPaint.setTypeface(Typeface.DEFAULT_BOLD);//采用默认的宽度 100 | textPaint.setAntiAlias(true); //抗锯齿 101 | textPaint.setStrokeWidth(3); 102 | textPaint.setAlpha(15); 103 | textPaint.setStyle(Paint.Style.STROKE); //空心 104 | textPaint.setColor(Color.WHITE);//采用的颜色 105 | textPaint.setShadowLayer(1f, 0f, 3f, Color.LTGRAY); 106 | // textPaint.setShadowLayer(3f, 1, 1,getResources().getColor(android.R.color.white));//影音的设置 107 | canvas.drawText(str, destWidth/2, destHeight-45, textPaint);//绘制上去字,开始未知x,y采用那只笔绘制 108 | canvas.save(Canvas.ALL_SAVE_FLAG); 109 | canvas.restore(); 110 | bitmap.recycle(); 111 | imageView.setImageBitmap(icon); 112 | return FileUtil.getInstance().saveMyBitmap(icon,String.valueOf(new Date().getTime())); //保存至文件 113 | // return true; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/huahua/su/bitmapwithwatermark/SelectPicActivity.java: -------------------------------------------------------------------------------- 1 | package com.huahua.su.bitmapwithwatermark; 2 | 3 | import android.app.Activity; 4 | import android.content.ContentValues; 5 | import android.content.Intent; 6 | import android.database.Cursor; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.os.Environment; 10 | import android.provider.MediaStore; 11 | import android.util.Log; 12 | import android.view.MotionEvent; 13 | import android.view.View; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | import com.huahua.su.bitmapwithwatermark.util.FileUtil; 17 | 18 | import java.io.File; 19 | import java.util.Date; 20 | 21 | /** 22 | * 23 | */ 24 | public class SelectPicActivity extends Activity implements View.OnClickListener{ 25 | 26 | 27 | /** 28 | * 使用照相机拍照获取图片 29 | */ 30 | public static final int SELECT_PIC_BY_TACK_PHOTO = 1; 31 | /** 32 | * 使用相册中的图片 33 | */ 34 | public static final int SELECT_PIC_BY_PICK_PHOTO = 2; 35 | public static final String KEY_PHOTO_PATH = "photo_path"; 36 | private static final String FILE_PATH = "file_path"; 37 | private Uri photoUri; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.dialog_select_pic); 43 | initView(); 44 | } 45 | 46 | @Override 47 | protected void onResume() { 48 | super.onResume(); 49 | } 50 | @Override 51 | protected void onPause() { 52 | super.onPause(); 53 | } 54 | @Override 55 | protected void onStop() { 56 | super.onStop(); 57 | } 58 | 59 | /** 60 | * 初始化加载View 61 | */ 62 | private void initView() { 63 | TextView tvTakePhoto = (TextView) findViewById(R.id.tv_take_photo); 64 | TextView tvPhonePic = (TextView) findViewById(R.id.tv_phone_pic); 65 | tvTakePhoto.setOnClickListener(this); 66 | tvPhonePic.setOnClickListener(this); 67 | } 68 | 69 | @Override 70 | public void onClick(View v) { 71 | switch (v.getId()) { 72 | case R.id.tv_take_photo: 73 | takePhoto(); 74 | break; 75 | case R.id.tv_phone_pic: 76 | pickPhoto(); 77 | break; 78 | default: 79 | finish(); 80 | break; 81 | } 82 | } 83 | 84 | /** 85 | * 拍照获取图片 86 | */ 87 | private void takePhoto() { 88 | //执行拍照前,应该先判断SD卡是否存在 89 | String SDState = Environment.getExternalStorageState(); 90 | if (SDState.equals(Environment.MEDIA_MOUNTED)) { 91 | try { 92 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//"android.media.action.IMAGE_CAPTURE" 93 | File file = new File(FileUtil.getInstance().getImageFile(new Date().getTime() + "")); 94 | if (!file.exists()) { 95 | file.mkdirs(); 96 | } 97 | photoUri = Uri.fromFile(file); 98 | 99 | intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); 100 | intent.putExtra(FILE_PATH, file.getAbsoluteFile()); 101 | startActivityForResult(intent, SELECT_PIC_BY_TACK_PHOTO); 102 | Log.v("tag", "filepath = " + file.getAbsoluteFile()); 103 | } catch (Exception e) { 104 | Toast.makeText(this, getString(R.string.no_camera_power), Toast.LENGTH_SHORT).show(); 105 | } 106 | } else { 107 | Toast.makeText(this, getString(R.string.no_sd_card), Toast.LENGTH_LONG).show(); 108 | } 109 | } 110 | 111 | /** 112 | * 从相册中取图片 113 | */ 114 | private void pickPhoto() { 115 | Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 116 | startActivityForResult(intent, SELECT_PIC_BY_PICK_PHOTO); 117 | } 118 | 119 | @Override 120 | public boolean onTouchEvent(MotionEvent event) { 121 | finish(); 122 | return super.onTouchEvent(event); 123 | } 124 | 125 | 126 | @Override 127 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 128 | if (resultCode == Activity.RESULT_OK) { 129 | doPhoto(requestCode, data); 130 | } 131 | super.onActivityResult(requestCode, resultCode, data); 132 | } 133 | 134 | /** 135 | * 选择图片后,获取图片的路径 136 | * 137 | * @param requestCode 138 | * @param data 139 | */ 140 | private void doPhoto(int requestCode, Intent data) { 141 | 142 | /** 143 | * 获取到的图片路径 144 | */ 145 | String picPath = null; 146 | 147 | if (requestCode == SELECT_PIC_BY_PICK_PHOTO) { 148 | //if(true){ //从相册取图片,有些手机有异常情况,请注意 149 | if (data == null) { 150 | Toast.makeText(this, getString(R.string.chose_imagefile_error), Toast.LENGTH_LONG).show(); 151 | return; 152 | } 153 | photoUri = data.getData(); 154 | if (photoUri == null) { 155 | Toast.makeText(this, getString(R.string.chose_imagefile_error), Toast.LENGTH_LONG).show(); 156 | return; 157 | } 158 | Log.v("tag", "photoUri = " + photoUri); 159 | } 160 | 161 | String[] pojo = {MediaStore.Images.Media.DATA}; 162 | Cursor cursor = getContentResolver().query(photoUri, pojo, null, null, null); 163 | if (cursor != null) { 164 | int columnIndex = cursor.getColumnIndexOrThrow(pojo[0]); 165 | cursor.moveToFirst(); 166 | picPath = cursor.getString(columnIndex); 167 | cursor.close(); 168 | } else { //小米4上取不到图片路径 169 | try { 170 | String[] strPaths = photoUri.toString().split("//"); 171 | picPath = strPaths[1]; 172 | } catch (Exception e) { 173 | e.printStackTrace(); 174 | } 175 | } 176 | if (picPath != null && (picPath.toLowerCase().endsWith(".png") || picPath.toLowerCase().endsWith(".jpg"))) { 177 | Intent lastIntent = getIntent(); 178 | lastIntent.putExtra(KEY_PHOTO_PATH, picPath); 179 | setResult(Activity.RESULT_OK, lastIntent); 180 | Log.v("tag", "picPath = " + picPath); 181 | finish(); 182 | } else { 183 | Toast.makeText(this, getString(R.string.chose_imagefile_error), Toast.LENGTH_LONG).show(); 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /app/src/main/java/com/huahua/su/bitmapwithwatermark/util/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.huahua.su.bitmapwithwatermark.util; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Rect; 9 | import android.graphics.Typeface; 10 | import android.os.Environment; 11 | import android.text.TextUtils; 12 | import android.util.Base64; 13 | import android.util.Log; 14 | 15 | import java.io.ByteArrayInputStream; 16 | import java.io.ByteArrayOutputStream; 17 | import java.io.File; 18 | import java.io.FileInputStream; 19 | import java.io.FileNotFoundException; 20 | import java.io.FileOutputStream; 21 | import java.io.IOException; 22 | import java.util.Date; 23 | 24 | /** 25 | * FIleUtil 26 | */ 27 | public class FileUtil { 28 | 29 | private FileUtil() { 30 | } 31 | 32 | private static FileUtil fileUtil; 33 | public synchronized static FileUtil getInstance() { 34 | if (fileUtil == null) { 35 | return new FileUtil(); 36 | }else{ 37 | return fileUtil; 38 | } 39 | } 40 | 41 | private final String LOCAL = "watermark"; 42 | /** 43 | * 图片目录 44 | */ 45 | public final String IMAGE_PATH = Environment.getExternalStorageDirectory().getPath() + File.separator + LOCAL + File.separator; 46 | 47 | /** 48 | * 判断是否存在存储空间 * 49 | * 50 | * @return 51 | */ 52 | public boolean isExitSDCard() { 53 | return Environment.getExternalStorageState().equals( 54 | Environment.MEDIA_MOUNTED); 55 | } 56 | 57 | private boolean hasFile(String fileName) { 58 | File f = createFile(fileName); 59 | return null != f && f.exists(); 60 | } 61 | 62 | public File createFile(String fileName) { 63 | 64 | File myCaptureFile = new File(IMAGE_PATH + fileName); 65 | if (myCaptureFile.exists()) { 66 | myCaptureFile.delete(); 67 | } 68 | try { 69 | myCaptureFile.createNewFile(); 70 | } catch (IOException e) { 71 | e.printStackTrace(); 72 | } 73 | return myCaptureFile; 74 | } 75 | 76 | public String getImageFile(String imageName) { 77 | File dirFile = new File(IMAGE_PATH); 78 | if (!dirFile.exists()) { 79 | dirFile.mkdirs(); 80 | } 81 | File myCaptureFile = new File(IMAGE_PATH + imageName + ".jpg"); 82 | if (!myCaptureFile.exists()) { 83 | try { 84 | myCaptureFile.createNewFile(); 85 | return myCaptureFile.getAbsolutePath(); 86 | } catch (IOException e) { 87 | e.printStackTrace(); 88 | return ""; 89 | } 90 | } 91 | return myCaptureFile.getAbsolutePath(); 92 | } 93 | 94 | 95 | public Bitmap getLocalBitmap(String url) { 96 | try { 97 | FileInputStream fis = new FileInputStream(url); 98 | return BitmapFactory.decodeStream(fis); ///把流转化为Bitmap图片 99 | 100 | } catch (FileNotFoundException e) { 101 | e.printStackTrace(); 102 | return null; 103 | } 104 | } 105 | 106 | /** 107 | * 获取压缩后图片的二进制数据 108 | * @param srcPath 109 | * @return 110 | */ 111 | public byte[] getCompressedImage(String srcPath) { 112 | if (!new File(srcPath).exists()){ 113 | return null; 114 | } 115 | 116 | BitmapFactory.Options newOpts = new BitmapFactory.Options(); 117 | //开始读入图片,此时把options.inJustDecodeBounds 设回true了 118 | newOpts.inJustDecodeBounds = true; 119 | Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bm为空 120 | 121 | newOpts.inJustDecodeBounds = false; 122 | int w = newOpts.outWidth; 123 | int h = newOpts.outHeight; 124 | float hh = 800f;//这里设置高度为800f 125 | float ww = 480f;//这里设置宽度为480f 126 | //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 127 | int be = 1;//be=1表示不缩放 128 | if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 129 | be = (int) (newOpts.outWidth / ww); 130 | } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 131 | be = (int) (newOpts.outHeight / hh); 132 | } 133 | if (be <= 0) { 134 | be = 1; 135 | } 136 | newOpts.inSampleSize = be;//设置缩放比例 137 | //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 138 | bitmap = BitmapFactory.decodeFile(srcPath, newOpts); 139 | 140 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 141 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 142 | int options = 100; 143 | while (baos.toByteArray().length / 1024 > 300) { //循环判断如果压缩后图片是否大于300kb,大于继续压缩 144 | baos.reset();//重置baos即清空baos 145 | options -= 15;//每次都减少15 146 | bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中 147 | } 148 | return baos.toByteArray(); 149 | } 150 | 151 | public Bitmap compressImage(Bitmap image) { 152 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 153 | image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 154 | int options = 100; 155 | while (baos.toByteArray().length / 1024 > 300) { //循环判断如果压缩后图片是否大于300kb,大于继续压缩 156 | baos.reset();//重置baos即清空baos 157 | options -= 15;//每次都减少15 158 | image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中 159 | 160 | } 161 | ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中 162 | return BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片 163 | } 164 | 165 | 166 | public Bitmap getImage(String srcPath, int width, int height) { 167 | Log.v("getImage","width = " + width+" height = "+height); 168 | BitmapFactory.Options newOpts = new BitmapFactory.Options(); 169 | //开始读入图片,此时把options.inJustDecodeBounds 设回true了 170 | newOpts.inJustDecodeBounds = true; 171 | Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bm为空 172 | 173 | newOpts.inJustDecodeBounds = false; 174 | int w = newOpts.outWidth; 175 | int h = newOpts.outHeight; 176 | //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 177 | int be = 1;//be=1表示不缩放 178 | if (w > h && w > width) {//如果宽度大的话根据宽度固定大小缩放 179 | be = (int) (newOpts.outWidth / width); 180 | } else if (w < h && h > height) {//如果高度高的话根据宽度固定大小缩放 181 | be = (int) (newOpts.outHeight / height); 182 | } 183 | if (be <= 0) { 184 | be = 1; 185 | } 186 | Log.v("getImage","be = " + be); 187 | newOpts.inSampleSize = be;//设置缩放比例 188 | //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 189 | bitmap = BitmapFactory.decodeFile(srcPath, newOpts); 190 | if (bitmap != null) { 191 | // return compressImage(bitmap);//压缩好比例大小后再进行质量压缩 192 | return bitmap;//压缩好比例大小后再进行质量压缩 193 | } else { 194 | return null; 195 | } 196 | } 197 | 198 | private boolean saveMyBitmap(Bitmap bitmap,String name ,String... str) { 199 | int destWidth = bitmap.getWidth(); //此处的bitmap已经限定好宽高 200 | int destHeight = bitmap.getHeight(); 201 | Log.v("addWatermarkBitmap","width = " + destWidth+" height = "+destHeight); 202 | Bitmap icon = Bitmap.createBitmap(destWidth, destHeight, Bitmap.Config.ARGB_8888); //定好宽高的全彩bitmap 203 | Canvas canvas = new Canvas(icon);//初始化画布绘制的图像到icon上 204 | 205 | Paint photoPaint = new Paint(); //建立画笔 206 | photoPaint.setDither(true); //获取跟清晰的图像采样 207 | photoPaint.setFilterBitmap(true);//过滤一些 208 | 209 | Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());//创建一个指定的新矩形的坐标 210 | Rect dst = new Rect(0, 0, destWidth, destHeight);//创建一个指定的新矩形的坐标 211 | canvas.drawBitmap(bitmap, src, dst, photoPaint);//将photo 缩放或则扩大到 dst使用的填充区photoPaint 212 | 213 | Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);//设置画笔 214 | textPaint.setTextSize(destWidth/30);//字体大小 215 | textPaint.setTextAlign(Paint.Align.CENTER); 216 | textPaint.setTypeface(Typeface.DEFAULT_BOLD);//采用默认的宽度 217 | textPaint.setAntiAlias(true); //抗锯齿 218 | textPaint.setStrokeWidth(1); 219 | textPaint.setAlpha(115); 220 | textPaint.setStyle(Paint.Style.STROKE); //空心 221 | textPaint.setColor(Color.WHITE);//采用的颜色 222 | textPaint.setShadowLayer(1f, 0f, 1f, Color.LTGRAY); 223 | int i = 0; 224 | for (String s : str) { 225 | if(!TextUtils.isEmpty(s)) { 226 | i++; 227 | canvas.drawText(s, destWidth / 2, destHeight - 45 * i, textPaint);//绘制上去字,开始未知x,y采用那只笔绘制 228 | } 229 | } 230 | canvas.save(Canvas.ALL_SAVE_FLAG); 231 | canvas.restore(); 232 | bitmap.recycle(); 233 | return saveMyBitmap(icon,name); //保存至文件 234 | // return true; 235 | } 236 | 237 | public boolean saveMyBitmap(Bitmap bmp,String name){ 238 | if (!isExitSDCard()) { 239 | return false; 240 | } 241 | FileOutputStream outputStream = null; 242 | try { 243 | outputStream = new FileOutputStream(new File(getImageFile(name))); 244 | bmp.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); 245 | } catch (FileNotFoundException e) { 246 | e.printStackTrace(); 247 | return false; 248 | } finally { 249 | if (outputStream != null) { 250 | try { 251 | outputStream.flush(); 252 | outputStream.close(); 253 | } catch (IOException e) { 254 | e.printStackTrace(); 255 | } 256 | } 257 | } 258 | return true; 259 | 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_select_pic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 |