Як зберегти NSImage як новий файл


76

Як я можу зберегти NSImage як новий файл (png, jpg, ...) у певному каталозі?


4
Я додав щедрість, оскільки хтось назвав перший варіант некрасивим хаком, і я, здається, не можу легко знайти на Google правильну і чітку відповідь, більше голосування / відповідей, будь ласка.
Роман А. Тайчер

Відповіді:


49

Зробіть щось подібне:


6
Ви повинні отримати репліка растрового зображення більш надійним способом, ніж припускати, що це перше подання. Ви також не можете припустити, що він є; якщо зображення було завантажено з PDF, наприклад, тоді буде NSPDFImageRep, а не NSBitmapImageRep.
Пітер Хосі,

14
Це глючний хак. Звичайну відповідь див. Нижче.
eonil

6
Якщо ви знайдете [* representationUsingType:properties:]: unrecognized selector sent to instanceобхідне рішення: NSCGImageSnapshotRep, як отримати bitmapData
Joshcodes

163

Ви можете додати категорію до NSImage, як це

Виклик "TIFFRepresentation" є важливим, інакше ви можете не отримати дійсне зображення.


3
Але TIFF - це RGB і викидає будь-яку інформацію про прозорість.
Hot Licks

4
Ні, TIFF чудово робить альфа-зображення та багатосторінкові зображення. Що дало вам ідею, що ні? Це те, що Apple рекомендує як формат призначення для зображень сітківки (TIFF-файли з декількома представленнями).
uliwitness

TIFF повинен підтримувати альфа-програму та прозорість en.wikipedia.org/wiki/Transparency_(graphic)
ColdSteel

Чи підтримуватиме це GIF?
ColdSteel

Що таке ImageProps? яке це значення передано?
ColdSteel

34

Не впевнений у решті вас, але я вважаю за краще їсти свою повну енчиладу. Те, що описано вище, спрацює, і нічого страшного в цьому немає, але я виявив, що кілька речей залишились поза увагою. Тут я виділю свої спостереження:

  • По-перше, забезпечується найкраще зображення, яке здається 72 DPI, навіть якщо роздільна здатність зображення перевищує цю. Отже, ви втрачаєте роздільну здатність
  • По-друге, що стосується багатосторінкових зображень, таких як зображення в анімованих GIF-файлах або PDF-файлах. Вперед, спробуйте анімований GIF, ви знайдете анімацію загубленою
  • Нарешті, будь-які метадані, такі як EXIF, GPS тощо ..., дані будуть втрачені.

Отже, якщо ви хочете перетворити це зображення, ви дійсно хочете програти все це? Якщо ви хочете з’їсти повноцінне харчування, давайте читайте далі ...

Іноді, і я маю на увазі, іноді немає нічого кращого, ніж хороший розвиток старої школи. Так, це означає, що нам доведеться трохи попрацювати!

Давайте розпочнемо:

Я створюю категорію в NSData. Це методи класу, оскільки ви хочете, щоб ці речі були безпечними для потоків, і немає нічого безпечнішого, ніж розміщення ваших речей у стеку. Існує два типи методів, один для виведення зображень, що не є багатосторінковими, і один для виведення багатосторінкових зображень.

Список окремих зображень: JPG, PNG, BMP, JPEG-2000

Список декількох зображень: PDF, GIF, TIFF

Спочатку створіть змінний простір даних у пам'яті.

По-друге, отримайте CGImageSourceRef. Так, вже некрасиво звучить, чи не так. Це не так погано, продовжуймо йти далі ... Ви дійсно хочете, щоб вихідне зображення не було поданням чи шматком даних NSImage. Однак у нас є невеличка проблема. Джерело може бути несумісним, тому переконайтеся, що ви перевіряєте свій UTI на основі перелічених у CGImageSourceCopyTypeIdentifiers ()

Деякий код:

Зачекайте секунду, чому там NSImage? Ну, є деякі формати, які не мають метаданих, і CGImageSource не підтримує, але це дійсні зображення. Прикладом є зображення PICT у старому стилі.

Тепер у нас є CGImageSourceRef, переконайтесь, що він не нульовий, і тоді давайте тепер отримаємо CGImageDestinationRef. Нічого собі, всі ці посилання для відстеження. Поки що ми на 2!

Ми будемо використовувати цю функцію: CGImageDestinationCreateWithData ()

  • 1st Param - це ваші imageData (актори CFMutableDataRef)
  • 2nd Param - це ваш вихідний UTI, пам’ятайте список вище. (наприклад, kUTTypePNG)
  • Третя парама - кількість зображень, які потрібно зберегти. Для окремих файлів зображень це 1, інакше ви можете просто використовувати наступне:

    CGImageSourceGetCount (imageSource);

  • 4-й парам - нуль.

Перевірте, чи є у вас цей CGImageDestinationRef, а тепер давайте додамо в нього наші зображення з джерела ... це також включатиме всі / всі метадані та зберігатиме роздільну здатність.

Для кількох зображень ми циклу:

Для одного зображення це один рядок коду з індексом 0:

Гаразд, доопрацюй, що запише на диск або в контейнер даних:

Тож, щоб „Змінні дані” з самого початку в нас були всі наші дані зображень та метадані.

Ми вже закінчили? Майже навіть при вивозі сміття вам доведеться прибирати! Запам’ятайте два посилання - один для джерела та один для пункту призначення, тому зробіть CFRelease ()

Тепер ми закінчили, і у вас вийде конвертоване зображення, що зберігає всі свої метадані, роздільну здатність тощо ...

Мої методи категорії NSData виглядають так:

А як щодо зміни розміру або ICO / ICNS? Це на інший день, але в підсумку ви спочатку вирішуєте зменшення розміру ...

  1. Створіть контекст із новим розміром: CGBitmapContextCreate ()
  2. Отримати посилання на зображення з індексу: CGImageSourceCreateImageAtIndex ()
  3. Отримайте копію метаданих: CGImageSourceCopyPropertiesAtIndex ()
  4. Намалюйте зображення в контексті: CGContextDrawImage ()
  5. Отримати змінене зображення із контексту: CGBitmapContextCreateImage ()
  6. Тепер додайте зображення та метадані до Dest Ref: CGImageDestinationAddImage ()

Промийте та повторіть для кількох зображень, вбудованих у джерело.

Єдина різниця між ICO та ICNS полягає в тому, що одне - це одне зображення, а інше - кілька зображень в одному файлі. Б'юсь об заклад, ви можете здогадатися, що є яке ?! ;-) Для цих форматів вам доведеться зменшити розмір до певного розміру, інакше виникне ПОМИЛКА. Хоча процес точно такий самий, коли ви використовуєте відповідний UTI, але зміна розміру трохи суворіша.

Добре, сподіваюся, це допомагає іншим, і ти такий же ситий, як і я зараз!

Оппс, забув згадати. Коли ви отримуєте об'єкт NSData, робіть із ним як завгодно, наприклад, writeToFile, writeToURL або, чорт, створіть інший NSImage, якщо хочете.

Щасливого кодування!


2
Це хороший початок, безумовно, кращий за інші відповіді (хоча ті оцінюються вищими), але він не повний. По-перше, логіка, представлена ​​тут, не обробляє файли PDF сама по собі (CGImageDestinationAddImageFromSource не працюватиме, оскільки джерело зображення буде нульовим). PDF-файли та інші джерела зображень, що не можна скопіювати, потребують особливої ​​обробки (щоб отримати зображення за допомогою ескізів або скопіювати дані іншим способом). По-друге, він не буде самостійно копіювати будь-які метадані, вам потрібно зробити це явно, витягнувши словник властивостей із джерела зображення та додавши його до місця призначення зображення.
danielv

Два запитання, будь ласка. 1) як ви можете бути впевнені, що [anImage TIFFRepresentation] завжди щось повертає? чи не є NSImage, які не мають TIFFRepresentation ?. 2) Не могли б ви надати фрагмент коду робочого замовлення принаймні для однієї (скажімо JPEPDataFromURL) з цих функцій повністю? Я намагався слідувати вашим вказівкам, і принаймні для мене - це не спрацює (я намагаюся зберегти вхідний кадр відеоданих як JPEG на диск, і мій вхід надходить із AVSession CMSampleBuffer через NSImage - і я намагаюся використовувати ваш код, щоб зберегти це у файл.
Мотті Шнеор

15

Свіфт 4.2 Рішення


Чи можете ви пояснити, чому ви використовуєте self.selfзамість self? Чи є якась різниця?
MartinW

Виявляється, різниці немає. Можливо, це було в більш ранній версії swift, але я думав, що в ньому було надруковано явне ім'я класу, але схоже, що просто повернути<<Class-Name> <Memory-Address>>
Charlton Provatas

14

зберегти як PNG за допомогою swift3


нехай tiffData = image.tiffRepresentation! нехай imageRep = NSBitmapImageRep (дані: tiffData) нехай data = imageRep? .представлення (з використанням: .PNG, властивості: [:]) робить {спробувати дані? .write (до: URL (fileURLWithPath: path3), параметри: NSData.WritingOptions ())} catch {print ("(помилка)")}
Надія

5

Стрімкий стиль:


2

Щоб допомогти з крос-платформним кодом, я впровадив версію, UIImagePNGRepresentation()яка працює на Mac (і використовує NSImage).

Використання:


1

Ще один гарантовано підхід до роботи за допомогою SWIFT:

У мене є "Колодязь зображень", куди користувач може скинути будь-яке зображення. І цей "Колодязь зображення" має властивість зображення (типу NSImage), доступ до якої здійснюється через розетку:

І код, який зберігає це зображення (ви можете помістити його всередину дії кнопки):

У 1-му рядку даного коду ми перевіряємо, чи є в нашому Image Well зображення.

У 2-му рядку ми робимо растрове зображення цього зображення.

У 3-му рядку ми перетворюємо нашу BitmapRepresentation у тип JPG з коефіцієнтом стиснення, встановленим на "1" (без стиснення).

У 4-му рядку ми зберігаємо дані JPG із заданим шляхом. "atomically: true" означає, що файл зберігається як цілісний фрагмент, і це гарантує нам, що операція буде успішною.

Примітка. Ви можете використовувати інший NSBitmapImageFileType у 3-му рядку, щоб зберегти зображення в іншому форматі. Він має багато:

тощо


0

Розчин OBJC зі стисненням та без нього

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.