Сохранить растровое изображение в местоположении


469

Я работаю над функцией загрузки изображения с веб-сервера, отображения его на экране, и, если пользователь хочет сохранить изображение, сохраните его на SD-карте в определенной папке. Есть ли простой способ взять растровое изображение и просто сохранить его на SD-карту в папке по моему выбору?

Моя проблема в том, что я могу загрузить изображение, отобразить его на экране в виде растрового изображения. Единственный способ найти изображение для сохранения изображения в определенной папке - это использовать FileOutputStream, но для этого требуется байтовый массив. Я не уверен, как преобразовать (если это даже правильный путь) из растрового изображения в байтовый массив, поэтому я могу использовать 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.
Пахарь

1
Следует отметить, что сохранение этого способа для .JPEG со 100% -ным качеством фактически сохранит изображение, отличное от оригинала в Интернете (по крайней мере, займет гораздо больше места). Рассмотрим альтернативный подход.
Warpzit

42
Есть ли одна есть пережать? Я просто хочу сохранить исходное изображение.
Хейн дю Плесси

2
@ HeinduPlessis Не обязательно, но, вероятно, вам следует. Сохранение необработанного растрового изображения займет гораздо больше места, в зависимости от формата (например, ARGB_4444 или ARGB_8888).
irwinb

134

Вы должны использовать Bitmap.compress()метод, чтобы сохранить растровое изображение в виде файла. Он будет сжимать (если позволяет используемый формат) ваше изображение и помещать его в OutputStream.

Вот пример полученного с помощью Bitmap экземпляра, getImageBitmap(myurl)который можно сжать как JPEG с коэффициентом сжатия 85%:

// 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 Я думаю, что вы можете опустить флеш.
Хоакин G

1
Вы должны изменить формулировку с «степень сжатия 85%» на «степень качества 85%» для меньшей неопределенности. Я бы интерпретировал «степень сжатия 85%» как «качество 15%», но параметр int Bitmap.compressуказывает качество.
Тим Кук

getImageBitmap(myurl)
Можете

38
outStream = new FileOutputStream(file);

сгенерирует исключение без разрешения в AndroidManifest.xml (по крайней мере, в os2.2):

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

10
Нет, если ваш файл absolutePath является внутренним путем?
Бланделл

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.
Мустафа Гювен,

13

Некоторые форматы, такие как PNG без потерь, будут игнорировать настройку качества.


2
PNG по-прежнему сжатый формат. Не влияет ли настройка качества на качество сжатия?
Тамас Барта

Состояние документов (выделено мной): Подсказка к компрессору, 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
вам не нужно сбрасывать outStream, если вы передаете это в методе 'compress'. этот метод будет делать для вас.
дхарам

7

Почему бы не вызвать Bitmap.compressметод с 100 (который звучит как без потерь)?


Даже если он игнорируется, он должен быть равен 100. Если когда-нибудь формат сжатия будет изменен на свободный, тогда изображение будет наиболее точно соответствовать этому, будучи свободным. Также обратите внимание, если у вас есть код, который абстрагирует этот вызов, это может быть более важным.
ddcruver

2
100% не без потерь с JPEG, FWIW. Вы можете проверить это, загрузив и сохранив растровое изображение несколько раз.

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();
            }

 }

Ваш метод сохранения работает только для меня .. после тратить несколько часов .. большое спасибо, сэр.
Мухаммед Суфиан

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")));

Значение 85 здесь не имеет смысла, так как PNG без потерь. Документация гласит: «Некоторые форматы, такие как PNG без потерь, будут игнорировать настройку качества»
Minhaz

2

Создать миниатюру видео для видео. Может вернуть ноль, если видео повреждено или формат не поддерживается.

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

Вы хотите сохранить растровое изображение в каталог по вашему выбору. Я сделал библиотеку ImageWorker, которая позволяет пользователю загружать, сохранять и конвертировать растровые изображения / drawables / base64 изображения.

Мин СДК - 14

Предпосылка

  • Для сохранения файлов потребуется разрешение WRITE_EXTERNAL_STORAGE.
  • Для получения файлов потребуется разрешение READ_EXTERNAL_STORAGE.

Сохранение растрового изображения / Drawable / 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**")

это будет звучать так, будто я ПРОСТО ДУМАЛ ВО ВРЕМЯ, но попробуйте, как только он будет сохранен в bmp foramt..Cheers


1

Убедитесь, что каталог создан, прежде чем позвонить bitmap.compress:

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

1

После Android 4.4 Kitkat и доли Android 4.4 и менее в 2017 году, составляющей около 20%, уменьшается, сохранить на SD-карту невозможно, используя Fileкласс и getExternalStorageDirectory()метод. Этот метод возвращает внутреннюю память устройства и сохраненные изображения, видимые для каждого приложения. Вы также можете сохранять изображения только для вашего приложения и удалять, когда пользователь удаляет ваше приложение с помощьюopenFileOutput() методом.

Начиная с Android 6.0, вы можете отформатировать свою SD-карту как внутреннюю память, но только для своего устройства. (Если вы отформатируете SD-автомобиль как внутреннюю память, только ваше устройство может получить доступ или просмотреть его содержимое). Вы можете сохранить на эту SD-карту, используя другие ответы, но если вы хотите использовать съемную SD-карту, вы должны прочитать мой ответ ниже.

Вы должны использовать Storage Access Framework, чтобы получить onActivityResultметод действия URI к папке, чтобы получить папку, выбранную пользователем, и добавить извлекаемое постоянное разрешение, чтобы иметь возможность доступа к папке после того, как пользователь перезапустит устройство.

@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-файл в xmlпапке с именем provider_paths.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может быть бесконечным циклом, если обходной путь не удается.
Раймунд Веге

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);
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.