비트 맵을 위치에 저장


469

웹 서버에서 이미지를 다운로드하여 화면에 표시하는 기능을 연구 중이며 사용자가 이미지를 유지하려면 특정 폴더의 SD 카드에 저장하십시오. 비트 맵을 가져 와서 선택한 폴더의 SD 카드에 저장하는 쉬운 방법이 있습니까?

내 문제는 이미지를 다운로드하여 화면에 비트 맵으로 표시 할 수 있다는 것입니다. 이미지를 특정 폴더에 저장하는 유일한 방법은 FileOutputStream을 사용하는 것이지만 바이트 배열이 필요합니다. Bitmap에서 바이트 배열로 변환하는 방법을 잘 모르므로 FileOutputStream을 사용하여 데이터를 쓸 수 있습니다.

내가 가지고있는 다른 옵션은 MediaStore를 사용하는 것입니다.

MediaStore.Images.Media.insertImage(getContentResolver(), bm,
    barcodeNumber + ".jpg Card Image", barcodeNumber + ".jpg Card Image");

SD 카드에 저장하는 것이 좋지만 폴더를 사용자 정의 할 수는 없습니다.


정확히 내가 앱에서하고있는 일. 나는 그것을 조작하고를 통해 이미지 뷰에 직접 비트 맵을로드 웹 서버 큰 이미지 형태로 다운로드 mImage.setImageBitmap(_result.getBitmap());내에서 onTaskComplete()콜백을. 이제 길게 누르기 컨텍스트 메뉴를 통해 원하는 경우 사용자가 파일을 로컬에 저장할 수 있도록해야합니다. 아래 솔루션을 사용할 수 있어야합니다. 내가 알고 싶은 것은 이것에 대한 더 나은 접근 방법을 발견 했습니까?
wired00

여기에 우아한 방법이 있습니다 : stackoverflow.com/questions/4263375/…
Chepech

답변:


921
try (FileOutputStream out = new FileOutputStream(filename)) {
    bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
    // PNG is a lossless format, the compression factor (100) is ignored
} catch (IOException e) {
    e.printStackTrace();
}

11
또한 이미지를 압축했지만 100 %로 압축했으며 이미지를 캔버스로 가져올 때 이미지가 매우 작습니다. 어떤 이유?
AZ_

3
@Aizaz 이미지의 크기는 변경하지 않으며 형식 및 (잠재적으로) 품질 만 변경합니다. 90위의 예에서 압축 품질 은 PNG로 저장할 때 아무런 영향을 미치지 않지만 JPEG와는 차이가 있습니다. JPEG의 경우 0에서 100 사이의 숫자를 선택할 수 있습니다.
plowman

1
100 % 품질의 .JPEG를 위해이 방법으로 저장하면 실제로 웹에서 원본과 다른 이미지가 저장됩니다 (적어도 더 많은 공간이 필요함). 대체 방법을 고려하십시오.
Warpzit

42
하나는 않습니다 다시 압축? 원본 이미지를 저장하고 싶습니다.
Hein du Plessis

2
@HeinduPlessis 꼭 그럴 필요는 없지만 아마도해야 할 것입니다. 원시 비트 맵을 저장하면 형식 (예 : ARGB_4444 vs ARGB_8888)에 따라 훨씬 더 많은 공간이 필요합니다.
irwinb

134

Bitmap.compress()방법을 사용하여 비트 맵을 파일로 저장 해야 합니다. 사진을 압축하고 (사용 가능한 형식이 허용하는 경우) OutputStream으로 푸시합니다.

getImageBitmap(myurl)압축률이 85 % 인 JPEG로 압축 할 수 있는 비트 맵 인스턴스의 예는 다음과 같습니다 .

// Assume block needs to be inside a Try/Catch block.
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
Integer counter = 0;
File file = new File(path, "FitnessGirl"+counter+".jpg"); // the File to save , append increasing numeric counter to prevent files from getting overwritten.
fOut = new FileOutputStream(file);

Bitmap pictureBitmap = getImageBitmap(myurl); // obtaining the Bitmap
pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut); // saving the Bitmap to a file compressed as a JPEG with 85% compression rate
fOut.flush(); // Not really required
fOut.close(); // do not forget to close the stream

MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());

@JoaquinG 어떤 이유로 든 fOut.flush()그것을 생략 할 수 없습니까?
Niklas

@Niklas 나는 당신이 플러시를 생략 할 수 있다고 생각합니다.
JoaquinG

1
모호함을 줄이려면 문구를 "압축률 85 %"에서 "품질 비율 85 %"로 변경해야합니다. "15 % 품질"을 의미하는 "압축률 85 %"를 해석하지만 int 매개 변수는 Bitmap.compress품질 을 지정합니다.
Tim Cooke

방법을 게시 할 수 있습니까getImageBitmap(myurl)
Aashish

38
outStream = new FileOutputStream(file);

AndroidManifest.xml에서 허가없이 예외가 발생합니다 (적어도 os2.2에서는).

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

10
파일 absolutePath가 내부 경로 인 경우가 아닙니까?
Blundell

24

내부 onActivityResult:

String filename = "pippo.png";
File sd = Environment.getExternalStorageDirectory();
File dest = new File(sd, filename);

Bitmap bitmap = (Bitmap)data.getExtras().get("data");
try {
     FileOutputStream out = new FileOutputStream(dest);
     bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
     out.flush();
     out.close();
} catch (Exception e) {
     e.printStackTrace();
}

7
당신은 그것을 "pippo.jpg"라고 부르지 만 PNG 압축을 사용하고 있습니다
Ralphleon

1
비트 맵의 ​​품질을 변경하려면 압축 형식이 .JPEG이어야합니다. PNG 형식으로 품질을 변경할 수 없습니다.
Mustafa Güven

13

무손실 PNG와 같은 일부 형식은 품질 설정을 무시합니다.


2
PNG는 여전히 압축 형식입니다. 품질 설정이 압축 품질을 수정하지 않습니까?
Tamás Barta

문서 상태 (나에 의해 강조 표시됨) : 압축기에 대한 힌트, 0-100. 0은 작은 크기의 압축을 의미하고 100은 최대 품질의 압축을 의미합니다. 무손실 PNG 같은 일부 형식은, 품질 설정을 무시합니다
스테판 헤 닝센

10

비트 맵을 파일로 저장하기위한 샘플 코드는 다음과 같습니다.

public static File savebitmap(Bitmap bmp) throws IOException {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bmp.compress(Bitmap.CompressFormat.JPEG, 60, bytes);
    File f = new File(Environment.getExternalStorageDirectory()
            + File.separator + "testimage.jpg");
    f.createNewFile();
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
    fo.close();
    return f;
}

이제이 함수를 호출하여 비트 맵을 내부 메모리에 저장하십시오.

File newfile = savebitmap(bitmap);

도움이 되길 바랍니다. 행복한 코딩 생활.


8
Bitmap bbicon;

bbicon=BitmapFactory.decodeResource(getResources(),R.drawable.bannerd10);
//ByteArrayOutputStream baosicon = new ByteArrayOutputStream();
//bbicon.compress(Bitmap.CompressFormat.PNG,0, baosicon);
//bicon=baosicon.toByteArray();

String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
OutputStream outStream = null;
File file = new File(extStorageDirectory, "er.PNG");
try {
    outStream = new FileOutputStream(file);
    bbicon.compress(Bitmap.CompressFormat.PNG, 100, outStream);
    outStream.flush();
    outStream.close();
} catch(Exception e) {

}

1
'compress'메소드로 전달하면 outStream을 플러시 할 필요가 없습니다. 그 방법은 당신을 대신 할 것입니다.
dharam

7

Bitmap.compress100으로 메소드를 호출하지 않는 이유는 무엇 입니까?


압축 형식이 무시 되더라도 100이어야합니다. 언젠가 압축 형식을 느슨하게 변경하면 이미지가 느슨하게 일치하는 것과 가장 일치합니다. 또한이 호출을 추상화하는 코드가 있다면 더 중요 할 수 있습니다.
ddcruver 2018 년

2
JPEG, FWIW의 100 %는 무손실이 아닙니다. 비트 맵을 반복해서로드하고 저장하여이를 확인할 수 있습니다.

5

사진도 저장하고 싶습니다. 그러나 내 문제 (?)는 내가 그린 비트 맵에서 저장하고 싶다는 것입니다.

나는 이것을 다음과 같이 만들었다.

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
            case R.id.save_sign:      

                myView.save();
                break;

            }
            return false;    

    }

public void save() {
            String filename;
            Date date = new Date(0);
            SimpleDateFormat sdf = new SimpleDateFormat ("yyyyMMddHHmmss");
            filename =  sdf.format(date);

            try{
                 String path = Environment.getExternalStorageDirectory().toString();
                 OutputStream fOut = null;
                 File file = new File(path, "/DCIM/Signatures/"+filename+".jpg");
                 fOut = new FileOutputStream(file);

                 mBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
                 fOut.flush();
                 fOut.close();

                 MediaStore.Images.Media.insertImage(getContentResolver()
                 ,file.getAbsolutePath(),file.getName(),file.getName());

            }catch (Exception e) {
                e.printStackTrace();
            }

 }

당신의 저장 방법은 나에게만 효과가 있습니다. 몇 시간을 낭비한 후 .. 고마워요.
Mohammed Sufian

5

PNG와 투명도를 보내는 방법을 찾았습니다.

String file_path = Environment.getExternalStorageDirectory().getAbsolutePath() +
                    "/CustomDir";
File dir = new File(file_path);
if(!dir.exists())
  dir.mkdirs();

String format = new SimpleDateFormat("yyyyMMddHHmmss",
       java.util.Locale.getDefault()).format(new Date());

File file = new File(dir, format + ".png");
FileOutputStream fOut;
try {
        fOut = new FileOutputStream(file);
        yourbitmap.compress(Bitmap.CompressFormat.PNG, 85, fOut);
        fOut.flush();
        fOut.close();
     } catch (Exception e) {
        e.printStackTrace();
 }

Uri uri = Uri.fromFile(file);     
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType("image/*");
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
intent.putExtra(android.content.Intent.EXTRA_TEXT, "");
intent.putExtra(Intent.EXTRA_STREAM, uri);

startActivity(Intent.createChooser(intent,"Sharing something")));

PNG가 무손실이므로 85 값은 의미가 없습니다. 이 문서는 '무손실 PNG와 같은 일부 형식은 품질 설정을 무시합니다'
Minhaz

2

비디오의 비디오 썸네일을 만듭니다. 비디오가 손상되었거나 형식이 지원되지 않으면 null을 반환 할 수 있습니다.

private void makeVideoPreview() {
    Bitmap thumbnail = ThumbnailUtils.createVideoThumbnail(videoAbsolutePath, MediaStore.Images.Thumbnails.MINI_KIND);
    saveImage(thumbnail);
}

sdcard에 비트 맵을 저장하려면 다음 코드를 사용하십시오

매장 이미지

private void storeImage(Bitmap image) {
    File pictureFile = getOutputMediaFile();
    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());
    }  
}

이미지 저장 경로를 얻으려면

/** Create a File for saving an image or video */
private  File getOutputMediaFile(){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this. 
    File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
            + "/Android/data/"
            + getApplicationContext().getPackageName()
            + "/Files"); 

    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            return null;
        }
    } 
    // Create a media file name
    String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
    File mediaFile;
        String mImageName="MI_"+ timeStamp +".jpg";
        mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);  
    return mediaFile;
} 

2

비트 맵을 선택한 디렉토리에 저장하려고합니다. 비트 맵 / 드로어 블 / base64 이미지를로드, 저장 및 변환 할 수있는 라이브러리 ImageWorker를 만들었습니다.

최소 SDK-14

전제 조건

  • 파일을 저장하려면 WRITE_EXTERNAL_STORAGE 권한이 필요합니다.
  • 파일을 검색하려면 READ_EXTERNAL_STORAGE 권한이 필요합니다.

비트 맵 / 드로어 블 / Base64 저장

ImageWorker.to(context).
    directory("ImageWorker").
    subDirectory("SubDirectory").
    setFileName("Image").
    withExtension(Extension.PNG).
    save(sourceBitmap,85)

비트 맵로드

val bitmap: Bitmap? = ImageWorker.from(context).
    directory("ImageWorker").
    subDirectory("SubDirectory").
    setFileName("Image").
    withExtension(Extension.PNG).
    load()

이행

종속성 추가

프로젝트 레벨 Gradle에서

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

응용 프로그램 레벨 Gradle에서

dependencies {
            implementation 'com.github.ihimanshurawat:ImageWorker:0.51'
    }

https://github.com/ihimanshurawat/ImageWorker/blob/master/README.md에서 자세한 내용을 읽을 수 있습니다.


1

그냥 이름을 .bmp해주세요.

이 작업을 수행:

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
_bitmapScaled.compress(Bitmap.CompressFormat.PNG, 40, bytes);

//you can create a new file name "test.BMP" in sdcard folder.
File f = new File(Environment.getExternalStorageDirectory()
                        + File.separator + "**test.bmp**")

IM JUST FOOLING AROUND라는 말이 들리지만 일단 bmp foramt에 저장되면 시도해보십시오.


1

전화하기 전에 디렉토리가 작성되었는지 확인하십시오 bitmap.compress.

new File(FileName.substring(0,FileName.lastIndexOf("/"))).mkdirs();

1

Android 4.4 Kitkat 이후 2017 년 현재 Android 4.4 이하의 점유율이 약 20 %이고 감소하면 File클래스 및 getExternalStorageDirectory()방법을 사용하여 SD 카드에 저장할 수 없습니다 . 이 방법은 장치 내부 메모리를 반환하고 이미지는 모든 앱에 표시됩니다. 또한 앱 전용 이미지를 저장하고 사용자가 openFileOutput()메소드를 사용 하여 앱을 삭제하면 이미지를 삭제할 수도 있습니다 .

Android 6.0부터는 SD 카드를 내부 메모리로 포맷 할 수 있지만 장치 전용으로 만 포맷 할 수 있습니다 (SD 자동차를 내부 메모리로 포맷하면 장치 만 해당 내용에 액세스하거나 내용을 볼 수 있음) 다른 답변이지만 이동식 SD 카드를 사용하려면 아래 답변을 읽으십시오.

Storage Access Framework 를 사용 onActivityResult하여 사용자가 선택한 폴더를 가져 오려면 폴더로 활동 방법을 가져오고 사용자가 장치를 다시 시작한 후 폴더에 액세스 할 수 있도록 검색 가능한 지속 가능한 권한을 추가해야합니다.

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

    if (resultCode == RESULT_OK) {

        // selectDirectory() invoked
        if (requestCode == REQUEST_FOLDER_ACCESS) {

            if (data.getData() != null) {
                Uri treeUri = data.getData();
                tvSAF.setText("Dir: " + data.getData().toString());
                currentFolder = treeUri.toString();
                saveCurrentFolderToPrefs();

                // grantUriPermission(getPackageName(), treeUri,
                // Intent.FLAG_GRANT_READ_URI_PERMISSION |
                // Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                final int takeFlags = data.getFlags()
                        & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                // Check for the freshest data.
                getContentResolver().takePersistableUriPermission(treeUri, takeFlags);

            }
        }
    }
}

이제 저장 폴더를 공유 환경 설정에 저장하여 이미지를 저장할 때마다 폴더를 선택하도록 요청하지 마십시오.

당신은 사용해야 DocumentFile이미지,하지를 저장하는 클래스 File또는 ParcelFileDescriptor확인할 수있는 추가 정보를 원하시면, 이 스레드를 가진 SD 카드에 이미지를 저장하는 compress(CompressFormat.JPEG, 100, out);방법 및 DocumentFile클래스.


1

일부 새로운 장치는 비트 맵을 저장하지 않으므로 조금 더 설명했습니다 ..

아래에 권한 을 추가했는지 확인하십시오

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

xml폴더 이름 provider_paths.xml 아래에 xml 파일을 작성하십시오.

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external_files"
        path="." />
</paths>

아래 AndroidManifest에서

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

그런 다음 saveBitmapFile (passYourBitmapHere)을 호출하십시오.

public static void saveBitmapFile(Bitmap bitmap) throws IOException {
        File mediaFile = getOutputMediaFile();
        FileOutputStream fileOutputStream = new FileOutputStream(mediaFile);
        bitmap.compress(Bitmap.CompressFormat.JPEG, getQualityNumber(bitmap), fileOutputStream);
        fileOutputStream.flush();
        fileOutputStream.close();
    }

어디

File getOutputMediaFile() {
        File mediaStorageDir = new File(
                Environment.getExternalStorageDirectory(),
                "easyTouchPro");
        if (mediaStorageDir.isDirectory()) {

            // Create a media file name
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                    .format(Calendar.getInstance().getTime());
            String mCurrentPath = mediaStorageDir.getPath() + File.separator
                            + "IMG_" + timeStamp + ".jpg";
            File mediaFile = new File(mCurrentPath);
            return mediaFile;
        } else { /// error handling for PIE devices..
            mediaStorageDir.delete();
            mediaStorageDir.mkdirs();
            galleryAddPic(mediaStorageDir);

            return (getOutputMediaFile());
        }
    }

그리고 다른 방법들

public static int getQualityNumber(Bitmap bitmap) {
        int size = bitmap.getByteCount();
        int percentage = 0;

        if (size > 500000 && size <= 800000) {
            percentage = 15;
        } else if (size > 800000 && size <= 1000000) {
            percentage = 20;
        } else if (size > 1000000 && size <= 1500000) {
            percentage = 25;
        } else if (size > 1500000 && size <= 2500000) {
            percentage = 27;
        } else if (size > 2500000 && size <= 3500000) {
            percentage = 30;
        } else if (size > 3500000 && size <= 4000000) {
            percentage = 40;
        } else if (size > 4000000 && size <= 5000000) {
            percentage = 50;
        } else if (size > 5000000) {
            percentage = 75;
        }

        return percentage;
    }

void galleryAddPic(File f) {
        Intent mediaScanIntent = new Intent(
                "android.intent.action.MEDIA_SCANNER_SCAN_FILE");
        Uri contentUri = Uri.fromFile(f);
        mediaScanIntent.setData(contentUri);

        this.sendBroadcast(mediaScanIntent);
    }

더 많은 정보가 있습니까? 해결 방법이 실패하면 error handling for PIE devices..재귀 getOutputMediaFile가 무한 루프가 될 수 있습니다.
Raimund Wege 2016 년

0

압축하지 않고 갤러리에 비트 맵을 저장하십시오.

private File saveBitMap(Context context, Bitmap Final_bitmap) {
    File pictureFileDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Your Folder Name");
    if (!pictureFileDir.exists()) {
        boolean isDirectoryCreated = pictureFileDir.mkdirs();
        if (!isDirectoryCreated)
            Log.i("TAG", "Can't create directory to save the image");
        return null;
    }
    String filename = pictureFileDir.getPath() + File.separator + System.currentTimeMillis() + ".jpg";
    File pictureFile = new File(filename);
    try {
        pictureFile.createNewFile();
        FileOutputStream oStream = new FileOutputStream(pictureFile);
        Final_bitmap.compress(Bitmap.CompressFormat.PNG, 100, oStream);
        oStream.flush();
        oStream.close();
        Toast.makeText(Full_Screen_Activity.this, "Save Image Successfully..", Toast.LENGTH_SHORT).show();
    } catch (IOException e) {
        e.printStackTrace();
        Log.i("TAG", "There was an issue saving the image.");
    }
    scanGallery(context, pictureFile.getAbsolutePath());
    return pictureFile;
}
private void scanGallery(Context cntx, String path) {
    try {
        MediaScannerConnection.scanFile(cntx, new String[]{path}, null, new MediaScannerConnection.OnScanCompletedListener() {
            public void onScanCompleted(String path, Uri uri) {
                Toast.makeText(Full_Screen_Activity.this, "Save Image Successfully..", Toast.LENGTH_SHORT).show();
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
        Log.i("TAG", "There was an issue scanning gallery.");
    }
}

-1

// | == | 비트 맵에서 PNG 파일을 만듭니다.

void devImjFylFnc(String pthAndFylTtlVar, Bitmap iptBmjVar)
{
    try
    {
        FileOutputStream fylBytWrtrVar = new FileOutputStream(pthAndFylTtlVar);
        iptBmjVar.compress(Bitmap.CompressFormat.PNG, 100, fylBytWrtrVar);
        fylBytWrtrVar.close();
    }
    catch (Exception errVar) { errVar.printStackTrace(); }
}

// | == | 파일에서 Bimap 가져 오기 :

Bitmap getBmjFrmFylFnc(String pthAndFylTtlVar)
{
    return BitmapFactory.decodeFile(pthAndFylTtlVar);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.