You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android开发:选图/拍照后如何将图片缩放到1000×600再上传?

嘿,我帮你梳理并完善了这个图片选择、拍照、缩放上传的功能实现,补上了原代码缺失的部分,特别是上传前将图片缩放到1000×600的核心逻辑。下面是完整的方案:

功能需求
  • 支持从系统相册选择图片
  • 调用设备相机拍摄图片
  • 预览选中/拍摄的图片
  • 上传前将图片统一缩放为1000×600尺寸
  • 将处理后的图片上传至服务器
完整实现代码
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;

import com.afollestad.materialdialogs.MaterialDialog;
import com.bumptech.glide.Glide;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class ImageActivity extends AppCompatActivity implements View.OnClickListener {
    ImageView imageView;
    Button pickImage, upload;
    private static final int REQUEST_PICK_PHOTO = 2;
    private static final String TAG = ImageActivity.class.getSimpleName();
    private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100;
    private Uri fileUri;
    private String mImageFileLocation = "";
    private String postPath;
    // 缩放目标尺寸
    private static final int TARGET_WIDTH = 1000;
    private static final int TARGET_HEIGHT = 600;
    // 权限请求码
    private static final int REQUEST_PERMISSIONS = 1001;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.image_layout);
        imageView = findViewById(R.id.preview);
        pickImage = findViewById(R.id.pickImage);
        upload = findViewById(R.id.upload);
        pickImage.setOnClickListener(this);
        upload.setOnClickListener(this);
        // 检查权限
        checkPermissions();
    }

    @Override
    public void onClick(final View v) {
        switch (v.getId()) {
            case R.id.pickImage:
                new MaterialDialog.Builder(this)
                        .title(R.string.uploadImages)
                        .items(R.array.uploadImages)
                        .itemsIds(R.array.itemIds)
                        .itemsCallback((dialog, view, which, text) -> {
                            switch (which) {
                                case 0:
                                    // 选择相册图片
                                    Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                                    startActivityForResult(galleryIntent, REQUEST_PICK_PHOTO);
                                    break;
                                case 1:
                                    // 调用相机
                                    if (isDeviceSupportCamera()) {
                                        captureImage();
                                    } else {
                                        Toast.makeText(this, "设备不支持相机", Toast.LENGTH_SHORT).show();
                                    }
                                    break;
                                case 2:
                                    // 清空预览
                                    imageView.setImageResource(R.drawable.ic_launcher_background);
                                    postPath = null;
                                    break;
                            }
                        })
                        .show();
                break;
            case R.id.upload:
                if (postPath != null) {
                    // 先缩放图片再上传
                    String scaledImagePath = scaleImage(postPath);
                    if (scaledImagePath != null) {
                        uploadFile(scaledImagePath);
                    } else {
                        Toast.makeText(this, "图片缩放失败", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(this, "请先选择或拍摄图片", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    /**
     * 检查并申请必要权限
     */
    private void checkPermissions() {
        String[] permissions = {
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA
        };
        boolean needRequest = false;
        for (String perm : permissions) {
            if (ActivityCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
                needRequest = true;
                break;
            }
        }
        if (needRequest) {
            ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSIONS) {
            boolean allGranted = true;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allGranted = false;
                    break;
                }
            }
            if (!allGranted) {
                Toast.makeText(this, "需要授予权限才能使用功能", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == REQUEST_PICK_PHOTO) {
                if (data != null) {
                    // 获取相册图片路径
                    Uri selectedImage = data.getData();
                    String[] filePathColumn = {MediaStore.Images.Media.DATA};
                    Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
                    if (cursor != null) {
                        cursor.moveToFirst();
                        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                        String mediaPath = cursor.getString(columnIndex);
                        // 预览图片
                        Glide.with(this).load(mediaPath).into(imageView);
                        cursor.close();
                        postPath = mediaPath;
                    }
                }
            } else if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
                // 预览拍摄的图片
                if (Build.VERSION.SDK_INT > 21) {
                    Glide.with(this).load(mImageFileLocation).into(imageView);
                    postPath = mImageFileLocation;
                } else {
                    Glide.with(this).load(fileUri).into(imageView);
                    postPath = fileUri.getPath();
                }
            }
        } else if (resultCode != RESULT_CANCELED) {
            Toast.makeText(this, "抱歉,操作出现错误!", Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 检查设备是否支持相机
     */
    private boolean isDeviceSupportCamera() {
        return getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
    }

    /**
     * 调用相机拍摄图片
     */
    private void captureImage() {
        Intent callCameraApplicationIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException e) {
            Log.e(TAG, "生成图片文件失败: " + e.getMessage());
            e.printStackTrace();
            return;
        }
        // 适配Android 7.0+的FileProvider
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            fileUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
        } else {
            fileUri = Uri.fromFile(photoFile);
        }
        callCameraApplicationIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        startActivityForResult(callCameraApplicationIntent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
    }

    /**
     * 创建图片文件
     */
    private File createImageFile() throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,
                ".jpg",
                storageDir
        );
        mImageFileLocation = image.getAbsolutePath();
        return image;
    }

    /**
     * 将图片缩放至目标尺寸1000×600
     */
    private String scaleImage(String originalPath) {
        try {
            // 先获取原图的宽高,避免加载大图内存溢出
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(originalPath, options);
            int originalWidth = options.outWidth;
            int originalHeight = options.outHeight;

            // 计算缩放比例,保持宽高比,确保不超过目标尺寸
            float scaleWidth = (float) TARGET_WIDTH / originalWidth;
            float scaleHeight = (float) TARGET_HEIGHT / originalHeight;
            float scale = Math.min(scaleWidth, scaleHeight);

            // 加载原图并缩放
            options.inJustDecodeBounds = false;
            options.inSampleSize = calculateInSampleSize(options, TARGET_WIDTH, TARGET_HEIGHT);
            Bitmap originalBitmap = BitmapFactory.decodeFile(originalPath, options);
            Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap,
                    (int) (originalWidth * scale),
                    (int) (originalHeight * scale),
                    true);

            // 保存缩放后的图片到本地
            String scaledFileName = "scaled_" + System.currentTimeMillis() + ".jpg";
            File scaledFile = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), scaledFileName);
            FileOutputStream out = new FileOutputStream(scaledFile);
            scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
            out.flush();
            out.close();

            // 回收Bitmap内存
            if (originalBitmap != scaledBitmap) {
                originalBitmap.recycle();
            }
            scaledBitmap.recycle();

            return scaledFile.getAbsolutePath();
        } catch (Exception e) {
            Log.e(TAG, "图片缩放失败: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 计算采样率,避免加载大图内存溢出
     */
    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    /**
     * 上传图片到服务器
     */
    private void uploadFile(String filePath) {
        new Thread(() -> {
            try {
                File file = new File(filePath);
                OkHttpClient client = new OkHttpClient();
                // 构建Multipart请求
                RequestBody requestBody = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM)
                        .addFormDataPart("image", file.getName(),
                                RequestBody.create(MediaType.parse("image/jpeg"), file))
                        .build();

                Request request = new Request.Builder()
                        .url("你的服务器上传接口地址") // 替换为实际的服务器接口
                        .post(requestBody)
                        .build();

                Response response = client.newCall(request).execute();
                if (response.isSuccessful()) {
                    runOnUiThread(() -> {
                        Toast.makeText(ImageActivity.this, "上传成功", Toast.LENGTH_SHORT).show();
                    });
                } else {
                    runOnUiThread(() -> {
                        Toast.makeText(ImageActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
                    });
                }
            } catch (Exception e) {
                Log.e(TAG, "上传失败: " + e.getMessage());
                e.printStackTrace();
                runOnUiThread(() -> {
                    Toast.makeText(ImageActivity.this, "上传出错", Toast.LENGTH_SHORT).show();
                });
            }
        }).start();
    }
}
关键注意事项
  • 权限配置:在AndroidManifest.xml中添加必要权限,并且配置FileProvider(适配Android 7.0+):
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
    <application>
        <!-- FileProvider配置 -->
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
    
    然后在res/xml目录下创建file_paths.xml
    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-files-path name="my_images" path="Pictures" />
    </paths>
    
  • 服务器接口:替换uploadFile()方法中的服务器地址为实际的上传接口
  • 内存优化:缩放图片时使用inSampleSize采样率,避免加载大图导致内存溢出
  • 图片质量:压缩图片时可以调整compress()方法的质量参数(0-100),平衡文件大小和画质

内容的提问来源于stack exchange,提问作者Dr.Kong

火山引擎 最新活动