복붙노트

[SPRING] 카메라를 통해 사진 찍고 bytearray의 서버로 전송

SPRING

카메라를 통해 사진 찍고 bytearray의 서버로 전송

나는 사용자가 사진을 찍은 다음 그것을 저장하기 위해 서버에 보내고 싶습니다 Andorid 응용 프로그램에서 일하고 있습니다. 이제 그림을 서버에 바이트 배열로 보내고 있습니다. 바이트 배열을 PNG 파일로 파일에 저장하려고 시도한 다음 파일을 열려고하면 이미지 뷰어가 PNG에 오류가있어 표시 할 수 없다는 불만을 표시합니다. PNG 파일 크기는 122Kb였습니다.

Scalr 라이브러리를 사용하여 이미지 크기를 조정하려고 시도했을 때 이미지 소스가 null 일 수 없다고합니다. 바이트 배열을 직접 저장하면 PNG가 손상됩니다. 파일을 변환하여 서버에 제대로 보내면 오류가 발생하지 않습니다. 다음은 내가 사용하고 전송하는 카메라 코드입니다.

public class AddPhotoForUser extends DrawerLoader {

    private static final int CAMERA_PIC_REQUEST = 22;
    Button BtnSelectImage;
    private ImageView ImgPhoto;
    private static volatile Bitmap photo;
    private static volatile ByteArrayOutputStream stream = new ByteArrayOutputStream();

    final PersonServiceImpl personService = new PersonServiceImpl();

    private String[] navMenuTitles;
    private TypedArray navMenuIcons;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.upload_user_photo);

        navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);
        navMenuIcons = getResources()
                .obtainTypedArray(R.array.nav_drawer_icons);

        set(navMenuTitles, navMenuIcons);

        Button uploadImageButton = (Button) findViewById(R.id.uploadUserImageButton);
        uploadImageButton.setVisibility(View.INVISIBLE);

        ImgPhoto = (ImageView) findViewById(R.id.userPhotoImageView);
        BtnSelectImage = (Button) findViewById(R.id.userPhotoButtonSelect);
        BtnSelectImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {

                    Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                    startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);

                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Couldn't load photo", Toast.LENGTH_LONG).show();
                }
            }
        });

        uploadImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!(v == null)) {
                    uploadImage();
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Intent intent = new Intent(AddPhotoForUser.this, RestaurantList.class);
                    startActivity(intent);
                    finish();

                }
            }
        });

    }

    @Override
    public void onBackPressed() {
        Intent intent = new Intent(AddPhotoForUser.this, Login.class);
        startActivity(intent);
        finish();
    }

    @Override
    public void onActivityResult(final int requestCode, int resultCode, Intent data) {
        try {
            switch (requestCode) {
                case CAMERA_PIC_REQUEST:
                    if (resultCode == RESULT_OK) {
                        try {
                            photo = (Bitmap) data.getExtras().get("data");
                            if (!(photo == null)) {
                                ImgPhoto.setImageBitmap(photo);
                                Button uploadImageButton = (Button) findViewById(R.id.uploadUserImageButton);
                                uploadImageButton.setVisibility(View.VISIBLE);

                            }
                        } catch (Exception e) {
                            Toast.makeText(this, "Couldn't load photo", Toast.LENGTH_LONG).show();
                        }
                    }
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    private void uploadImage() {

        if (!(photo == null)) {
            photo.compress(Bitmap.CompressFormat.PNG, 100, stream);
            byte[] byteArray = stream.toByteArray();
            personService.addUserProfilePhoto(byteArray);
        }

    }
}

다음은 이미지를 디스크에 저장하는 서버 측 코드입니다.

 @Override
    public Boolean updateProfilePhoto(byte[] photo) {
        Person person = getCurrentlyAuthenticatedPerson();
        try{
           InputStream in = new ByteArrayInputStream(photo);
            BufferedImage image = ImageIO.read(in);
            image = Scalr.resize(image, Scalr.Method.QUALITY, 100, 100);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            baos.flush();
            File file = new File(userImagePath);
            if (file.exists() && file.isDirectory()) {
                OutputStream outputStream = new FileOutputStream(new File(userImagePath + person.getUserId()+".png"));
                outputStream.write(baos.toByteArray());
                outputStream.close();
            } else {
                File file1 = new File(userImagePath+person.getUserId()+".png");
                if (file1.exists()) {
                    try {
                        OutputStream outputStream = new FileOutputStream(file1);
                        outputStream.write(baos.toByteArray());
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();

                    }
                } else {
                   boolean result = file1.createNewFile();
                    System.out.println("Result of file1 creation is "+result);
                    OutputStream outputStream = new FileOutputStream(file1);
                    outputStream.write(baos.toByteArray());
                    outputStream.close();
                }
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

Scalr 라이브러리를 사용하지 않으면 오류는 없지만 손상된 파일이 있습니다. 다음은 Scalr 오류 로그입니다.

java.lang.IllegalArgumentException: src cannot be null
    at org.imgscalr.Scalr.resize(Scalr.java:1564)
    at org.imgscalr.Scalr.resize(Scalr.java:1415)
    at com.journaldev.spring.service.PersonServiceImpl.updateProfilePhoto(PersonServiceImpl.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy51.updateProfilePhoto(Unknown Source)
    at com.journaldev.spring.Controller.PersonController.addProfilePhotoForUser(PersonController.java:100)

어떤 도움이라도 좋을 것입니다. 고마워. :-)

업데이트 된 코드

public class AddPhotoForUser extends DrawerLoader {


    Button BtnSelectImage;
    private ImageView ImgPhoto;

    private static volatile ByteArrayOutputStream stream = new ByteArrayOutputStream();

    final PersonServiceImpl personService = new PersonServiceImpl();

    private String[] navMenuTitles;
    private TypedArray navMenuIcons;

    private static final int CAMERA_PHOTO = 111;
    private Uri imageToUploadUri;

    Bitmap reducedSizeBitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.upload_user_photo);

        navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);
        navMenuIcons = getResources()
                .obtainTypedArray(R.array.nav_drawer_icons);

        set(navMenuTitles, navMenuIcons);

        Button uploadImageButton = (Button) findViewById(R.id.uploadUserImageButton);
        uploadImageButton.setVisibility(View.INVISIBLE);

        ImgPhoto = (ImageView) findViewById(R.id.userPhotoImageView);
        BtnSelectImage = (Button) findViewById(R.id.userPhotoButtonSelect);
        BtnSelectImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {

                    captureCameraImage();
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Couldn't load photo", Toast.LENGTH_LONG).show();
                }
            }
        });

        uploadImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!(v == null)) {
                    uploadImage();
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Intent intent = new Intent(AddPhotoForUser.this, RestaurantList.class);
                    startActivity(intent);
                    finish();

                }
            }
        });

    }

    private Bitmap getBitmap(String path) {

        Uri uri = Uri.fromFile(new File(path));
        InputStream in = null;
        try {
            final int IMAGE_MAX_SIZE = 12000000; // 12MP
            in = getContentResolver().openInputStream(uri);

            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(in, null, o);
            in.close();


            int scale = 1;
            while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) >
                    IMAGE_MAX_SIZE) {
                scale++;
            }
            Log.d("", "scale = " + scale + ", orig-width: " + o.outWidth + ", orig-height: " + o.outHeight);

            Bitmap b = null;
            in = getContentResolver().openInputStream(uri);
            if (scale > 1) {
                scale--;
                // scale to max possible inSampleSize that still yields an image
                // larger than target
                o = new BitmapFactory.Options();
                o.inSampleSize = scale;
                b = BitmapFactory.decodeStream(in, null, o);

                // resize to desired dimensions
                int height = b.getHeight();
                int width = b.getWidth();
                Log.d("", "1th scale operation dimenions - width: " + width + ", height: " + height);

                double y = Math.sqrt(IMAGE_MAX_SIZE
                        / (((double) width) / height));
                double x = (y / height) * width;

                Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x,
                        (int) y, true);
                b.recycle();
                b = scaledBitmap;
                System.gc();
            } else {
                b = BitmapFactory.decodeStream(in);
            }
            in.close();

            Log.d("", "bitmap size - width: " + b.getWidth() + ", height: " +
                    b.getHeight());
            return b;
        } catch (IOException e) {
            Log.e("", e.getMessage(), e);
            return null;
        }
    }

    private void captureCameraImage() {
        Intent chooserIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File f = new File(Environment.getExternalStorageDirectory(), "POST_IMAGE.jpg");
        chooserIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
        imageToUploadUri = Uri.fromFile(f);
        startActivityForResult(chooserIntent, CAMERA_PHOTO);
    }

    @Override
    public void onBackPressed() {
        Intent intent = new Intent(AddPhotoForUser.this, Login.class);
        startActivity(intent);
        finish();
    }

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

        if (requestCode == CAMERA_PHOTO && resultCode == Activity.RESULT_OK) {
            if(imageToUploadUri != null){
                Uri selectedImage = imageToUploadUri;
                getContentResolver().notifyChange(selectedImage, null);
                reducedSizeBitmap = getBitmap(imageToUploadUri.getPath());
                if(reducedSizeBitmap != null){
                    ImgPhoto.setImageBitmap(reducedSizeBitmap);
                    Button uploadImageButton = (Button) findViewById(R.id.uploadUserImageButton);
                    uploadImageButton.setVisibility(View.VISIBLE);
                }else{
                    Toast.makeText(this,"Error while capturing Image",Toast.LENGTH_LONG).show();
                }
            }else{
                Toast.makeText(this,"Error while capturing Image",Toast.LENGTH_LONG).show();
            }
        }

    }

    private void uploadImage() {
        if(!(reducedSizeBitmap == null)){
            reducedSizeBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
            byte[] byteArray = stream.toByteArray();
            this.personService.addUserProfilePhoto(byteArray);
        }
    }
}

해결법

  1. ==============================

    1.Bundle extras = data.getExtras ();를 사용하는 경우 onActivityResult ()에서 실제 이미지가 아닌 미리보기 이미지를 반환합니다.

    Bundle extras = data.getExtras ();를 사용하는 경우 onActivityResult ()에서 실제 이미지가 아닌 미리보기 이미지를 반환합니다.

    다음은 카메라 이미지 캡처 및 저장에 사용한 코드입니다. ImageView에 표시합니다. 필요에 따라 사용할 수 있습니다.

    카메라 이미지를 특정 위치에 저장 한 다음 해당 위치에서 가져와 바이트 배열로 변환해야합니다.

    다음은 캡처 카메라 이미지 활동을 여는 방법입니다.

    private static final int CAMERA_PHOTO = 111;
    private Uri imageToUploadUri;
    
    private void captureCameraImage() {
            Intent chooserIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File f = new File(Environment.getExternalStorageDirectory(), "POST_IMAGE.jpg");
            chooserIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
            imageToUploadUri = Uri.fromFile(f);
            startActivityForResult(chooserIntent, CAMERA_PHOTO);
        }
    

    onActivityResult () 메소드는 이와 같아야합니다.

    @Override
            protected void onActivityResult(int requestCode, int resultCode, Intent data) {
                super.onActivityResult(requestCode, resultCode, data);
    
                if (requestCode == CAMERA_PHOTO && resultCode == Activity.RESULT_OK) {
                    if(imageToUploadUri != null){
                        Uri selectedImage = imageToUploadUri;
                        getContentResolver().notifyChange(selectedImage, null);
                        Bitmap reducedSizeBitmap = getBitmap(imageToUploadUri.getPath());
                        if(reducedSizeBitmap != null){
                            ImgPhoto.setImageBitmap(reducedSizeBitmap);
                            Button uploadImageButton = (Button) findViewById(R.id.uploadUserImageButton);
                              uploadImageButton.setVisibility(View.VISIBLE);                
                        }else{
                            Toast.makeText(this,"Error while capturing Image",Toast.LENGTH_LONG).show();
                        }
                    }else{
                        Toast.makeText(this,"Error while capturing Image",Toast.LENGTH_LONG).show();
                    }
                } 
            }
    

    다음은 onActivityResult ()에서 사용되는 getBitmap () 메소드입니다. 나는 카메라가 이미지 비트 맵을 얻는 동안 가능할 수있는 모든 성능 향상을 수행했다.

    private Bitmap getBitmap(String path) {
    
            Uri uri = Uri.fromFile(new File(path));
            InputStream in = null;
            try {
                final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
                in = getContentResolver().openInputStream(uri);
    
                // Decode image size
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(in, null, o);
                in.close();
    
    
                int scale = 1;
                while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) >
                        IMAGE_MAX_SIZE) {
                    scale++;
                }
                Log.d("", "scale = " + scale + ", orig-width: " + o.outWidth + ", orig-height: " + o.outHeight);
    
                Bitmap b = null;
                in = getContentResolver().openInputStream(uri);
                if (scale > 1) {
                    scale--;
                    // scale to max possible inSampleSize that still yields an image
                    // larger than target
                    o = new BitmapFactory.Options();
                    o.inSampleSize = scale;
                    b = BitmapFactory.decodeStream(in, null, o);
    
                    // resize to desired dimensions
                    int height = b.getHeight();
                    int width = b.getWidth();
                    Log.d("", "1th scale operation dimenions - width: " + width + ", height: " + height);
    
                    double y = Math.sqrt(IMAGE_MAX_SIZE
                            / (((double) width) / height));
                    double x = (y / height) * width;
    
                    Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x,
                            (int) y, true);
                    b.recycle();
                    b = scaledBitmap;
    
                    System.gc();
                } else {
                    b = BitmapFactory.decodeStream(in);
                }
                in.close();
    
                Log.d("", "bitmap size - width: " + b.getWidth() + ", height: " +
                        b.getHeight());
                return b;
            } catch (IOException e) {
                Log.e("", e.getMessage(), e);
                return null;
            }
        }
    

    편집하다:

    다음은 이미지를 서버에 업로드하는 방법입니다.

    /**
     * Upload Image to server
     *
     * @param file              image to be saved
     * @param compressorQuality quality of image
     * @return path of uploaded image in server
     */
    private String uploadImage(Bitmap file, int compressorQuality) {
        String final_upload_filename = "demo_image.png";
        String response = null;
        HttpURLConnection conn = null;
        try {
            String lineEnd = "\r\n";
            String twoHyphens = "--";
            String boundary = "---------------------------14737809831466499882746641449";
            URL url = new URL("image_upload_url");
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("ENCTYPE", "multipart/form-data");
            conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            conn.setRequestProperty("uploaded_file", final_upload_filename);
            DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
            dos.writeBytes(lineEnd + twoHyphens + boundary + lineEnd);
            dos.writeBytes("Content-Disposition: form-data; name=\"userfile\"; filename=\"" + final_upload_filename + "\"" + lineEnd);
            dos.writeBytes("Content-Type: application/octet-stream" + lineEnd);
            dos.writeBytes(lineEnd);
            file.compress(CompressFormat.PNG, compressorQuality, dos);
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
            dos.flush();
            dos.close();
            InputStream is = conn.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int bytesRead;
            byte[] bytes = new byte[1024];
            while ((bytesRead = is.read(bytes)) != -1) {
                baos.write(bytes, 0, bytesRead);
            }
            byte[] bytesReceived = baos.toByteArray();
            baos.close();
            is.close();
            response = new String(bytesReceived);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return response;
    }
    

    특정 폴더에 이미지 데이터를 저장하려면 백엔드 서버에 업로드 스크립트를 만들어야합니다.

    나는 그것이 도움이되기를 바랍니다!

  2. ==============================

    2.처음에는 파일을 만들고 이미지를 저장해야하며 여기에 코드가 필요합니다.

    처음에는 파일을 만들고 이미지를 저장해야하며 여기에 코드가 필요합니다.

    // 내부 또는 외부 저장소에 이미지를 저장하는 방법

    private void storeImage(Bitmap image,String imageName) {
        File pictureFile = getOutputMediaFile(imageName);
        if (pictureFile == null) {
            Log.d(TAG,"Error creating media file, check storage permissions: ");// e.getMessage());
            return;
        } 
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            image.compress(Bitmap.CompressFormat.PNG, 90, fos);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }  
    }
    

    // 이미지를 저장할 파일을 만드는 메소드

    private  File getOutputMediaFile(String imageName){
        //create folder with name FoursquareAPI
        File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
                + "/FoursquareAPI");
    
        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                return null;
            }
        } 
        File mediaFile;
            String mImageName= imageName +".png";
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);  
        return mediaFile;
    }
    
  3. from https://stackoverflow.com/questions/32245091/taking-a-picture-via-camera-and-sending-it-to-server-in-bytearray by cc-by-sa and MIT license