Как сохранить bitmap в файл c
Я работаю над функцией загрузки изображения с веб-сервера, отображения его на экране, и если пользователь хочет сохранить изображение, сохраните его на карте SD в определенной папке. Есть ли простой способ взять bitmap и просто сохранить его на карту SD в папке по моему выбору?
Моя проблема в том, что я могу загрузить изображение, отобразить его на экране как Bitmap. Единственный способ, который я смог найти, чтобы сохранить изображение в определенной папке, - это использовать FileOutputStream, но для этого требуется массив байтов. Я не знаю, как преобразовать (если это вообще правильный путь) из Bitmap в байтовый массив, поэтому я могу использовать FileOutputStream для записи данных.
Другой вариант, который у меня есть, - это использовать MediaStore :
Который отлично работает для сохранения на карту SD, но не позволяет настроить папку.
Я делаю приложение, в котором рисую bitmap на холсте в качестве наложения после стирания какой-то части наложения bitmap я хочу сохранить его на sd-карту, но когда он будет сохранен, он будет содержать черный цвет UI как прикрепить экран И мой код ниже:- public EraserView(Context context)
Мне нужно сохранить изображение моего объекта DrawingArea в Bitmap, но я не могу найти, как это сделать. Кто-нибудь может сказать, как сохранить изображение DrawingArea в Bitmap?
Вот пример экземпляра Bitmap, полученного через getImageBitmap(myurl) , который может быть сжат как JPEG со скоростью сжатия 85% :
будет выбрасывать исключение без разрешения в AndroidManifest.xml (по крайней мере, в os2.2):
У меня есть эта функция для хранения bmp-изображения в нужном месте, как показано ниже Мой вопрос заключается в том, как сохранить изображение в папке C:\temp по умолчанию, вместо того чтобы открывать окно filedialog? Я хочу указать sd.fileName=picname+.bmp и сохранить его в c:\temp по умолчанию.
Я работаю над проектом, в котором я использовал canvas, и пользователь может касаться перемещения одного наложения bitmap на другое bitmap. Когда пользователь нажимает кнопку сохранить, оба растровых изображения должны объединиться и стать единым bitmap. Я все сделал, и теперь слияние двух bitmap.
Некоторые форматы, такие как PNG, который является без потерь, будут игнорировать настройку качества.
Вот пример кода для сохранения bitmap в файл :
Теперь вызовите эту функцию, чтобы сохранить bitmap во внутреннюю память.
File newfile = savebitmap(bitmap) ;
Надеюсь, это вам поможет. Счастливая кодирующая жизнь.
Я также хотел бы сохранить фотографию. Но моя проблема (?) в том, что я хочу спасти его от bitmap, который я нарисовал.
Я сделал его таким:
Вы хотите сохранить Bitmap в каталоге по вашему выбору. Я создал библиотеку ImageWorker, которая позволяет пользователю загружать, сохранять и конвертировать bitmaps/drawables/base64 изображения.
Предварительное условие
- Для сохранения файлов потребуется разрешение WRITE_EXTERNAL_STORAGE.
- Для извлечения файлов потребуется разрешение READ_EXTERNAL_STORAGE.
Добавление Зависимостей
На Уровне Проекта Gradle
На Прикладном Уровне Gradle
Создайте миниатюру видео для видео. Он может вернуть null, если видео повреждено или формат не поддерживается.
Чтобы сохранить ваш bitmap на SD-карте, используйте следующий код
Сохранить Изображение
Чтобы получить путь для хранения изображений
Эй, просто назови имя .bmp
После Android 4.4 Kitkat, а по состоянию на 2017 год доля Android 4.4 и меньше составляет около 20% и уменьшается, невозможно сохранить на карту SD, используя класс File и метод getExternalStorageDirectory() . Этот метод возвращает внутреннюю память вашего устройства и изображения, сохраненные видимыми для каждого приложения. Вы также можете сохранять изображения только для вашего приложения и удалять их, когда пользователь удаляет ваше приложение с помощью метода openFileOutput() .
Начиная с Android 6.0, вы можете отформатировать свою карту SD как внутреннюю память, но только личную для вашего устройства.(Если вы форматируете SD car как внутреннюю память, только ваше устройство может получить доступ или увидеть его содержимое) Вы можете сохранить эту карту SD, используя другие ответы, но если вы хотите использовать съемную карту SD, вы должны прочитать мой ответ ниже.
Вы должны использовать рамки доступа к хранилищу , чтобы получить uri в папку способ onActivityResult активности, чтобы получить папку, выбранную пользователем, и добавить извлечь разрешения persistiable, чтобы быть в состоянии получить доступ к папке после перезагрузки устройства.
Теперь сохраните папку save в общих настройках, чтобы не просить пользователя выбирать папку каждый раз, когда вы хотите сохранить изображение.
Вы должны использовать класс DocumentFile для сохранения вашего изображения, а не File или ParcelFileDescriptor , для получения дополнительной информации вы можете проверить этот поток для сохранения изображения на карту SD с помощью метода compress(CompressFormat.JPEG, 100, out); и классов DocumentFile .
Некоторые новые устройства не экономят bitmap, поэтому я объяснил немного больше..
убедитесь, что вы добавили ниже разрешение
и создайте файл xml под именем папки xml provider_paths.xml
а в AndroidManifest году под
тогда просто позвоните saveBitmapFile(passYourBitmapHere)
и другие методы
Сохраните Bitmap в своей галерее без сжатия.
// | = = / создайте файл PNG из Bitmap :
// | = = / получить Bimap из файла :
Похожие вопросы:
Если у меня есть TBitmap и я хочу получить обрезанное изображение из этого bitmap, могу ли я выполнить операцию обрезки на месте? например, если у меня есть bitmap, который равен 800x600, как я могу.
это мой код, и я хочу сохранить этот bitmap на своем внутреннем хранилище. Public boolean saveImageToInternalStorage-это код от google, но я не знаю, как его использовать. когда я касаюсь кнопки 2.
Я делаю приложение, в котором рисую bitmap на холсте в качестве наложения после стирания какой-то части наложения bitmap я хочу сохранить его на sd-карту, но когда он будет сохранен, он будет.
Мне нужно сохранить изображение моего объекта DrawingArea в Bitmap, но я не могу найти, как это сделать. Кто-нибудь может сказать, как сохранить изображение DrawingArea в Bitmap?
У меня есть эта функция для хранения bmp-изображения в нужном месте, как показано ниже Мой вопрос заключается в том, как сохранить изображение в папке C:\temp по умолчанию, вместо того чтобы.
Я работаю над проектом, в котором я использовал canvas, и пользователь может касаться перемещения одного наложения bitmap на другое bitmap. Когда пользователь нажимает кнопку сохранить, оба.
У меня есть действие в моем приложении, которое должно сохранить некоторые данные, и эти данные должны быть доступны из другого действия, поэтому я использую SharedPreferences для этого, проблема в.
Я читаю изображение и печатаю на нем какой-то текст, как вы можете видеть . Bitmap bmp = new Bitmap(@d:\a.jpg); RectangleF rectf = new RectangleF(70, 90, 90, 50); Graphics g =.
В настоящее время я делаю приложение для редактирования фотографий. У меня есть упражнение, в котором вы можете добавить текст к изображению. Мне нужно сохранить изображение с текстом в bitmap. Я.
Работа с графикой и рисунками средствами Borland C++ Builder
Графика. Это растровое изображение некоторого файла или ресурса (битового образа, пиктограммы или метафайла). C++Builder определяет производные от базового класса TGraphic объектные классы TBitmap, Ticon и TMetafile, предназначенные для работы с графикой.
Класс TBitmap, определен в Borland C++ Builder как Graphic::TBitmap, имеет свойства и методы, позволяющие создавать графические изображенеия, управлять их атрибутами, читать в память и сохранять как файлы DIB на диске. Graphic::TBitmap поддерживает как растровые графические изображения в виде массива пикселей, так и изображения в формате .bmp. Основное свойство класса - Canvas. Класс TGraphic предоставляет TBitmap минимальный стандартный интерфейс для работой с графикой.
Классы TIcon и TMetafile также являются производными от базового класса TGraphic и имеют свойства и методы для работы с графикой, но в отличии от TBitmap не имеют свойства Canvas, что объясняется спецификой построения и использования изображений в формате *.ico и *.wmf (*.emf).
Рассмотрение вопросов темы будем вести на примерах, в которых последовательно показывается использование основных свойств и методов классов. Работа с ресурсами выделена в отдельный раздел (см. Работа с ресурсами в Borland C++ Builder).
Классы TBitmap, TIcon и TMetafile
В данном параграфе рассматривается использование не инкапсулированных в другие классы и компоненты Borland C++ Builder классов TBitmap, TIcon и TMetafile.
Загрузка и сохранение графики
Первый пример показывает создание объектов соответствующих классов, загрузку в них файлов и сохранение файлов:
Загрузка и отрисовка графики
Следущий код использует класс TBitmap для загрузки изображения из файла и его отрисовки, а также для задания растрового изображения кисти. Из рисунка, показывающего результаты работы программы, видно, что вновь для кисти используется не весь битовый образ, а только первые его 8*8 пикселей.
Параметры всех функций либо нам уже известны, либо прозрачны и не требуют пояснений. Результаты работы кода показаны на рисунке.
Рис 1. Использование класса TBitmap
Полностью аналогичен код и для графики в форматах .ico и .emf:
Для отрисовки графики можно использовать функцию StretchDraw(), которая, в отличие от функция Draw() не только рисует, но и масштабирует изображение. Однако, иконки не масштабируются - им только выделяется указанный в функции кусок канвы
Метод CopyRect() также предназначен для отрисовки графики и переносит указанную область изображения или его часть в канве источника изображения в указанную область изображения данного объекта TCanvas. Копирование производится в режиме, установленном свойством CopyMode канвы, разноообразие которых можно посмотреть в Help Borland C++ Builder.
Модификация графики
Следущий пример показывает как можно создать объект TBitmap, выполнить на нем рисунок и перенести на канву приложения. К сожалению это нельзя сделать не для иконок, не для метафайлов, у которых нет сваойства Canvas.
Нижепреведенный код объединяет два примера, а именно на графическом изображении, полученном из файла выполняется некоторая отрисовка и новое изображение переносится на канву приложения. Результат - прямоугольник с закругленными краями желтого цвета заменяется на круг.
Установка прозрачности
Bitmap может иметь один цвет, как прозрачный, тоесть цвет, который при выводе заменяется на цвет фона канвы отображения, не зависимо от смены ее цвета. Сделать это можно двумя способами. При первом способе определяется как "прозрачный" цвет левого верхнего пиксела Bitmap. При втором способе определяется прозрачным какой либо конкретный цвет. Установка того или иного способа определения прозрачных пикселов задается свойством TransparentMode (возможные значения для него - tmAuto и tmFixed соответственно). И в том, и в другом случае надо установить свойство Transparent для Bitmap в true.
Захват изображений с экрана монитора
В примере, описанном ниже, показано использование классов TCanvas и TBitmap для получения изображения с экрана монитора и сохранения его в файле. функция vPurloin() в зависимости от параметра, переданного ей, получает снимок экрана, окна приложения или клиентской части окна приложения (окна без заголовка) и сохраняет их в файл на диске. В принципе, этот пример использует и функции GDI для получение контекстов устройств и, в частности, экрана монитора, но основа, всеже, использование класса TBitmap.
Использование буфера обмена для работы с графикой
Использование метода Assign позволяет проводить обмен данными между совершенно разнородными компонентами, например, компонентом буфера обмена TClipboard и графическим объектом TBitmap. Отметим, что следущий пример может быть повторен для метафайлов и не подходит для иконок, так как буфер обмена не поддерживает формат .ico. О том, как все же можно поместить в буфер обмена иконку (см. Работа с ресурсами в Borland C++ Builder).
Записать изображение в буфер можно оператором:
Прочитать изображение из буфера изображение оператором:
Следующий пример деманстрирует возможности этих операторов:
После применения метода SaveToClipboardFormat() надо передать объекту Clipboard полученные значения параметров.
Пример использования метода SaveToClipboardFormat():
Экономия ресурсов
В этом примере показано освобождение ресурсов изображения на различных уровнях (методы Dormant(), FreeImage(), ReleaseHandle()), кроме того в примере показано как преобразовать изображение в монохромное (свойство Monochrome):
Аналогично можно использовать для освобождения ресурсов для графики в формате .ico и .emf.
Другие методы и свойства TBitmap, TIcon, TMetafile
gBitmap->Handle, gBitmap->Palette - дескрипторы битовой карты и ее палитры.
HandleAllocated() - проверяет наличие дескриптора компонента у данного элемента. Если дескриптор имеется, то возвращается true. В отличии от проверки свойства Handle, этот метод не приводит к созданию дескриптора при его отсутствии.
ReleaseHandle() и ReleasePalette() - возвращают (обнуляет) дескриптор изображения и палитры соответственно. Следует отметить, что один объект может иметь несколько дескрипторов. При любом внешнем обращении к дескриптору битовой карты и попытке рисовать на ее канве объект получает собственную копию содержимого дескриптора (тоесть совместного использования дескрипторов нет).
ReleaseMaskHandle() - освобождает дескриптор маски точечного рисунка. Действие аналогично ReleasePalette.
Mask() - конвертирует текущее растровое изображение в одноцветную маску, заменяя TransparentColor белым цветом, остальные черным. Используется когда надо превратить битовую карту в маску для других битовых карт. Для преобразования могут использоваться свойства MaskHandle, и метод ReleaseMaskHandle().
Свойство HandleType - может принимать значения bmDIB или bmDDB и позволяет проверить тип изображение (DDB или DIB).
Свойство PixelFormat - позволяет определить и изменить формат изображения. Возможные значения - pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom. Режим pfDevice соответствует битовой карте DDB. Глубина цвета в 1, 4 и 8 бит на пиксел предусматривает наличие у изображения палитры. Другие режимы хранят значения яркостей точек в каждом из трех основных цветов - красном (R), зеленом (G) и синем (В). Разрядность 15 бит соответствует распределению бит 5-5-5 (RGB555), 16 бит - RGB 565, 24 бит - RGB888. Режим 32 бит похож на 24-битный, но в нем дополнительно добавлен четвертый канал (альфа-канал), содержащий дополнительную информацию о прозрачности каждой точки. Режим pfCustom предназначен для реализации программистом собственных графических конструкций (использовать его целесообразно только в собственных потомках TBitmap).
Простейший пример предбразования:
IgnorePalette - требование игнолировать палитру при значении true, увеличивает скорость работы с изображением, но ведет к потери качества для изображений особенно 16 и 256 цветов.
ScanLine[] - обеспечивает индексированный доступ к строкам пикселов растрового изображения. Метод используется только с форматами растрового изображения DIB.
Внутри строки данные упорядочены в соответствии с форматом (pixelFormat). Для формата pf1bit каждый бит в строке соответствует одному пикселу, для форматов до pf24bit пикселу соответствуют два байта, pf24bit - три байта (по байту на канал), pf32bit - четыре байта.
Класс TImage и работа с изображениями
Визуальный компонент TImage создает на форме контейнер графического изображения (битового образа, пиктограммы или метафайла).
Picture. Контейнер графики. Окно загрузки файлов изображений открывается кнопкой в графе свойства Picture компонента TImage. Кроме того это свойство имеет методы LoadFromFile(), SaveToFile().
AutoSize. Чтобы контейнер изменил свои размеры так, чтобы вместить изображение целиком, устанавливается значение true свойства AutoSize.
Stretch. Чтобы исходное изображение растянулось на весь контейнер, задается значение true свойства Stretch.
Center - если AutoSize=false, то изображение помещается в центре компонента.
IncrementalDisplay - если true, то при загрузке больших файлов они будут показываться по частям по мере загрузки.
Отметим, что класс TImage может создаваться и как невизуальный компонент и использовать теже свойства и методы, что и визуальный компонент. и оба они могут использовать канву:
Рассмотрение вопросов параграфа темы будем вести на примерах, в которых последовательно показывается использование основных свойств и методов компонента и класса TImage. Работа с ресурсами выделена в отдельный раздел (см. Работа с ресурсами в Borland C++ Builder) и здесь опущена.
Кроме того, так как эти классы инкапсулируют в свойстве TPicture классы TBitmap, TIcon и TMetafile, то все, что относится непосредственно к работе с этими классами, более подробно можно посмотреть в предыдущем параграфе. Здесь же основное внимание уделено технологии работе с классами.
Загрузка и сохранение графики
Методы LoadFromFile() и SaveToFile() объектного свойства Picture служат для динамической загрузки и сохранения файлов изображений с помощью инструкций типа, которые могут быть использованы двояко:
Загрузка и отрисовка графики
Отрисовка графики при использовании визуального компонента предельно проста - изображение отображается сразу при загрузке в компонент. При этом можно управлять многими параметрами изображений, например:
Для отображения графики, загруженной в созданный класс TImage, можно как и ранее воспользоваться функциями Draw() и StretchDraw():
Отметим, что масштабирования Bitmap в классе не предусмотрено и это возможно только при отрисовки, например функцией StretchDraw():
Для метафайлов и иконок примеры аналогичены, за некоторыми особенностями, которые хорошо видны из следующих примеров:
Отметим, что класс поддерживает масштабирование для метафайлов.
И для визуальных компонентов:
Обратим внимание на некоторое различие на задание размеров отображаемого рисунка. Такая конструкция не сработает для TImage:
И, как и в случае с объектным классом TIcon, не сработает никакой из способов задания размеров для иконки, в том числе и для визуального компонента. Иконка не изменит своих размеров в следующем коде:
Аналогично и для класса TImage:
Метод CopyRect() также предназначен для отрисовки изображений, переносит указанную область изображения или его часть в канве источника изображения в указанную область данного объекта TCanvas. Копирование производится в режиме, установленном свойством CopyMode канвы, разноообразие которых можно посмотреть в Help Borland C++ Builder.
Следующий код показывает возможность копирования части изображения:
Этот метод позволяет и увеличить размер изображения иконки как показано в следующем примере:
Модификация графики
Следущие примеры показывают возможность выполнить некоторый рисунок на уже загруженном изображении. К сожалению это нельзя сделать не для иконок, не для метафайлов, у которых нет сваойства Canvas.
Для визуального компонента:
Аналогично для класса:
Установка прозрачности
Все сказанное выше равным образом относится и для Timage, поэтому останавливаться на этом не будем. В примерах параграфа "Загрузка и отрисовка изображений" уже использовалось свойство Transparent для TImage. Отметим, что для иконок, если они созданы (например в Tools/Image Editor) как имеющие области прозрачности, установка свойства Transparent в false не поможет.
Пример установки прозрачности для класса TImage:
Тоже для визуального компонента:
Захват изображений с экрана монитора
Самый простой способ получить изображение экрана монитора это присвоить Handle канвы TImage Handle экрана или окна приложения:
Недостаток этого способа в том, что снимки нельзя масштабировать. Поэтому при необходимости масштабирования можно применить подход описанный для TBitmap, что для TImage выглядит так:
Для того, чтобы получить снимок окна приложения в код внесем изменения:
Использование буфера обмена для работы с графикой
Использование буфера обмена для работы с изображением для TImage также ничем не отличается от описанных выше способов для TBitmap, где отмечены и особенности использование методов для различных графических объектов. Поэтому в данном параграфе приведены лишь примеры.
Записать изображение в буфер и прочитать его можно операторами:
И пример, использования функции SaveToClipboardFormat(), описание которой приводилось ранее:
Экономия ресурсов
Этот пример полностью аналогичен, примеру для класса TBitmap:
Аналогично можно использовать для освобождение ресурсов для графики в формате .ico и .emf.
На первом уроке про Bitmap мы обсудили, что для чтения картинки из файла (ресурсов,потока,…) в Bitmap используются decode* методы BitmapFactory. И при чтении мы можем использовать объект BitmapFactory.Options, который позволяет нам задать некоторые параметры. Какие-то из этих параметров весьма специфичны и крайне редко используются, но есть и те, которые могут быть полезны в повседневной работе.
Разберемся, зачем нужны эти параметры, и рассмотрим некоторые из них на примерах.
inJustDecodeBounds
Если включить (true) этот параметр, то система не будет создавать Bitmap, а только вернет информацию о изображение в следующих полях:
outWidth – ширина
outHeight – высота
outMimeType – mimetype
Project name: P1591_BitmapOptions
Build Target: Android 4.4
Application name: BitmapOptions
Package name: ru.startandroid.develop.p1591bitmapoptions
Create Activity: MainActivity
MainActivity.java:
В DrawView указываем inJustDecodeBounds = true, читаем стандартную Android-иконку и выводим в лог информацию о ней.
Запускаем, смотрим лог:
bitmap = null, width = 48, height = 48, mimetype = image/png
У вас ширина и высота могут быть другие, т.к. при чтении картинок из папок res/drawable-*dpi учитывается density устройства.
Bitmap равен null, т.к. система только вернула нам инфу, а Bitmap не создавала, а следовательно и память не занимала.
inSampleSize
Позволяет указать коэффициент уменьшения размера изображения при чтении. Он должен быть кратным 2. Если зададите другое число, то оно будет изменено на ближайшее число меньшее вашего и кратное 2.
Перепишем класс DrawView:
Используем inSampleSize = 2 и в лог выводим размеры, получившегося Bitmap:
width = 24, height = 24
Как и заказывали, картинка при чтении в Bitmap стала в два раза меньше.
Параметры inJustDecodeBounds и inSampleSize можно использовать для чтения больших изображений. Т.е. если вы сразу решите считать большое изображение в Bitmap, вы можете занять, тем самым, слишком много памяти или вообще получить OutOfMemory. Поэтому следует сначала получить данные о размерах картинки, а затем с коэффициентом сжатия считать ее в Bitmap примерно нужного размера. Этот алгоритм мы еще подробно разберем на одном из следующих уроков.
inBitmap
Если передать в этот параметр Bitmap-объект, то он и будет использован для получения результата вместо создания нового Bitmap-объекта.
Тут есть несколько особенностей с версиями Android.
- в Android 4.4 (API 19) передаваемый Bitmap должен быть не меньше по размеру (в байтах), чем читаемое изображение.
- для более ранних версий, передаваемый в inBitmap объект должен быть того же размера (ширина/высота), что и читаемое изображение. Также, в Options необходимо добавлять inSampleSize = 1.
Перепишем DrawView:
Создаем новый Bitmap-объект tempBitmap и передаем его в inBitmap параметр.
bitmap = android.graphics.Bitmap@5281a428 (48,48), tempBitmap = android.graphics.Bitmap@5281a428
Видно, что bitmap и tempBitmap указывают на один объект. Т.е. decode-метод не создавал новый Bitmap, а прочел изображение в tempBitmap и вернул его, как результат. Размер Bitmap стал 48х48. Хотя изначально мы создавали его размером 300х300.
Если систему что-то не устроит, она может вернуть null или сгенерировать IllegalArgumentException.
Еще раз проговорю, что этот пример сработал на Android 4.4, но на более ранних версиях есть нюансы, которые я чуть выше расписал.
inPreferredConfig
Указание желаемой конфигурации Bitmap.Config.
inDensity
Задает density-значение для Bitmap, аналогично методу setDensity. Для задания значения используйте константы DENSITY* класса DisplayMetrics.
inTargetDensity, inScaled
Если inTargetDensity отличен от inDensity, и inScaled = true (по умолчанию), то размер изображения будет скорректирован от inDensity к inTargetDensity.
inScreenDensity
К сожалению, мне не удалось понять, зачем он нужен. Если есть мысли, пишите на форуме.
inPurgeable
Позволяет системе временно удалить содержимое созданного Bitmap из памяти в случае нехватки таковой. Когда изображение снова понадобится (например при выводе на экран), оно будет восстановлено из источника. Т.е. жертвуем производительностью в пользу памяти.
inInputShareable
Если true, то Bitmap хранит ссылку на источник, иначе – данные источника. Но даже если true, то вполне может быть, что по усмотрению системы будут храниться данные, а не ссылка. Этот параметр актуален только при включенном inPurgeable.
inDither
Попытка сгладить цвета, если текущей цветовой палитры не достаточно для отображения оригинальных цветов изображения
inMutable
Если true, то мы получим mutable Bitmap
inPreferQualityOverSpeed
Включение более качественного декодирования в ущерб скорости
inPremultiplied
Доступен с API Level 19. Дает возможность выключить premultiplied-режим. Если режим включен (по умолчанию), то RGB компоненты в пикселах сразу рассчитаны с учетом альфа-компонента (для лучшей производительности). Канва принимает Bitmap только в таком режиме. В хелпе сказано, что выключение режима может понадобиться для специфических задач: RenderScript и OpenGL.
inTempStorage
Здесь можем указать свой временный массив, который будет использован в процессе декодирования
mCancel
По этой метке можно определить был ли процесс декодирования отменен методом requestCancelDecode
Как сохранить Bitmap в файл
Метод compress позволяет сохранить Bitmap в разных форматах в исходящий поток. На вход принимает:
- формат (JPG, PNG, WEBP)
- качество сжатия, от 0 (наихудшее) до 100 (наилучшее)
- поток
Рассмотрим пример, в котором создадим Bitmap, нарисуем на нем что-нибудь и сохраним на SD.
Перепишем DrawView:
В bmpIcon читаем стандартную иконку, затем меняем размер на 500х500. Создаем новый bitmap, заполняем его белым, рисуем в нем bmpIcon и пишем текст.
Далее создаем объект File, который указывает на файл savedBitmap.jpg в стандартной папке Pictures. Для этого файла создаем поток FileOutputStream, который передаем в метод compress. Также в методе указываем формат JPEG и качество = 100.
После запуска приложения идем в папку Pictures, там должен быть файл savedBitmap.jpg.
На следующем уроке:
- читаем и отображаем большие изображения
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
// загружаем картинку
sourceBitmap = (Bitmap) Image.FromFile( "Zap.jpg" );<br/>
// делаем пустую картинку того же размера
targetBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height, sourceBitmap.PixelFormat);<br/>
void NaïveBlackAndWhite()<br/>
for ( int y = 0; y < sourceBitmap.Height; ++y)<br/>
for ( int x = 0; x < sourceBitmap.Width; ++x)<br/>
Color c = sourceBitmap.GetPixel(x, y);<br/>
byte rgb = ( byte )(0.3 * c.R + 0.59 * c.G + 0.11 * c.B);<br/>
targetBitmap.SetPixel(x, y, Color.FromArgb(c.A, rgb, rgb, rgb));<br/>
><br/>
><br/>
Это решение понятное и простое, но к сожалению жуть как неэффективное. Чтобы получить более «резвый» код, можно попробовать написать все это дело на С++. Для начала создадим структурку для хранения цветовых значений пикселя
// структура отражает один пиксель в 32bpp RGBA
struct Pixel
BYTE Blue;<br/>
BYTE Green;<br/>
BYTE Red;<br/>
BYTE Alpha;<br/>
>;<br/>
Теперь можно написать функцию которая будет делать пиксель черно-белым:
Pixel MakeGrayscale(Pixel& pixel)<br/>
const BYTE scale = static_cast < BYTE >(0.3 * pixel.Red + 0.59 * pixel.Green + 0.11 * pixel.Blue);<br/>
Pixel p;<br/>
p.Red = p.Green = p.Blue = scale;<br/>
p.Alpha = pixel.Alpha;<br/>
return p;<br/>
><br/>
Теперь собственно пишем саму функцию обхода:
CPPSIMDLIBRARY_API void AlterBitmap( BYTE * src, BYTE * dst, int width, int height, int stride)<br/>
for ( int y = 0; y < height; ++y)
for ( int x = 0; x < width; ++x)<br/>
int offset = x * sizeof (Pixel) + y * stride;<br/>
Pixel& s = * reinterpret_cast <Pixel*>(src + offset);<br/>
Pixel& d = * reinterpret_cast <Pixel*>(dst + offset);<br/>
// изменяем d
d = MakeGrayscale(s);<br/>
><br/>
><br/>
><br/>
void UnmanagedBlackAndWhite()<br/>
// "зажимаем" байты обеих картинок
Rectangle rect = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);<br/>
BitmapData srcData = sourceBitmap.LockBits(rect, ImageLockMode.ReadWrite, sourceBitmap.PixelFormat);<br/>
BitmapData dstData = targetBitmap.LockBits(rect, ImageLockMode.ReadWrite, sourceBitmap.PixelFormat);<br/>
// отсылаем в unmanaged код для изменений
AlterBitmap(srcData.Scan0, dstData.Scan0, srcData.Width, srcData.Height, srcData.Stride);<br/>
// отпускаем картинки
sourceBitmap.UnlockBits(srcData);<br/>
targetBitmap.UnlockBits(dstData);<br/>
><br/>
Это улучшило быстродействие, но мне захотелось еще большего. Я добавил директиву OpenMP перед циклом по y и получил предсказуемое ускорение в 2 раза. Дальше захотелось поэкспериментировать и попробовать применить еще и SIMD. Для этого я написал вот этот, не очень читабельный, код:
Несмотря на то, что этот код делает 4 операции умножения за раз (инструкция _mm_mul_ps ), все эти конверсии не дали никакого выигрыша по сравнению с обычными операциями – скорее наоборот, алгоритм начал работать медленнее. Вот результаты выполнения функций на картинке 360×480. Использовался 2х-ядерный MacBook с 4Гб RAM, результаты усредненные.
Читайте также: