понедельник, 28 мая 2012 г.

Обзор русскоязычных изданий по программированию для Mac OS, iPad, iPhone.

Печатную книгу приятно в руках держать, оставлять закладки, поставить на полку и вернутся через месяц. Но увы, с покупкой iPad стал очень внимательно относится к покупке бумажных изданий. Цифра дает о себе знать, покупаются действительно интересные и нужны книги.

Приведу краткий обзор литературы с небольшим описанием и краткими заметками.

Разработка приложений для iPhone, iPad и iPod touch с использованием iOS SDK
Автор: Дэйв Марк, Джек Наттинг, Джефф Ламарш
Переводчики И. Берштейн, Дмитрий Клюшин, Игорь Красиков, Н. Ручко


Издательство: Вильямс
ISBN 978-5-8459-1725-6, 978-1-43-023024-3; 2011 г.
Страниц 624 стр.
Переплет Твердый переплет

Добротная книга с хорошо поданным материалом. Видно что переводчики старались. Много картинок с примерами. Есть объяснение некоторым тонкостям в сносках. Плотная бумага, приятно держать в руках. Книгу я бы отнес порекомендовал людям у которых есть опыт разработки и есть желание разрабатывать под эти платформы.

Минус данной книги, в том что повсеместно используется Xcode 4.0, а материал рассчитан для более старой версии. Хорошая новость что на сайте издательства есть информация о переиздании книги для iOS 5.0.

Разработка и продажа программ для iPhone и iPad
Автор: Дмитрий Елисеев
Издательство: БХВ-Петербург
ISBN 978-5-9775-0687-8; 2011 г.
Страниц 336 стр.
Переплет Мягкая обложка

Книги о разработке должны быть именно о ней, а не о чем то другом. Сто страниц о том как засабмитить программу в Apple Store, это перебор. В целом отвратное качество бумаги. Материал подан таким образом всего по немного из разных мест. Знаний особых не добавит.

Программируем для iPhone и iPad
Автор: Д. Пайлон, Т. Пайлон
Издательство: Питер 
ISBN 978-5-459-00375-8; 2012 г.


Страниц 624 стр.
Переплет Мягкая обложка

Книга-комикс. Манера изложения весьма интересна. Если покупать то стоит хотя бы для начала полистать. Единственная книга в которой уже есть XCode 4, но прошлая версия iOS.
Хорошая полиграфия. Книга оставляет приятное впечатление. Рекомендую для начинающих разработчиков.

Профессиональное программирование приложений для iPhone и iPad
Professional iPhone and iPad Application Development
Автор: Джин Баклин
ISBN 978-5-699-55828-5; 2012 г.
Страниц 672 стр.
Переплет Твердый переплет

Перевод издания от 2010 года. морально устарел. Не знаю чем думает издательство когда издает такие книги. Для фундаментных книг, это имело бы смысл. Для изданий по такой тематике, где платформа раз в год обновляется весьма критично. Рекомендовано для тех кому нужно поддерживать старую платформу.


Разработка приложений под iPhone. Полное руководство
Автор: Крейг Хоккенбери
Переводчик В. Порицкий
Издательство: Питер
ISBN 978-5-4237-0055-3, 978-0596809775; 2011 г.

Страниц 336 стр.
Переплет Мягкая обложка
Перевод откровенно говоря ужасен. Материал книги уже устарел. Не рекомендовал бы к покупке.

iPhone. Разработка приложений с открытым кодом
Автор: Джонатан Здзиарски
ISBN 978-5-9775-0397-6, 978-0-596-15519-3; 2009 г.
Страниц 368 стр.
Тираж 2000 экз.

Ужасная бумага и высокая цена для такой книги. Материал весьма любопытный. Рекомендовать особого смысла нету. Полистайте если будет интерес можно приобрести.


Objective-C 2.0 и программирование для Mac
Автор: Марк Далримпл, Скотт Кнастер
ISBN 978-5-8459-1607-5; 2010 г.
Страниц 320 стр.
Переплет Твердый переплет


Если нет опыта вообще в программировании. Эта книга даст некоторые ориентиры. Рекомендуется нубам в программировании. Хорошая полиграфия. ООП разжевано на основе Objective-C.

Книги в идеале лучше читать на английском. Переводов действительно нужных книг мало. Например ни одного издания по OpenGL ES. У издательства Addison-Wesley есть несколько книг по графике, так и весьма полезная книга Cocoa Design Patterns (обязательно к прочтению).


Update - Готовится к изданию книга


Разработка приложений для Mac OS X Lion
Майкл Приват, Роберт Уорнер.

Посмотрел вариант на английском языке. Весь материал построен в виде небольших зарисовок на тему как можно сделать ту или иную фишку UI для 10.7.

четверг, 26 апреля 2012 г.

Загрузка произвольного шрифта из файла средствами CoreText

В  Snow Leopard загрузка произвольного шрифта осуществлялась установкой его в системную папку всех шрифтов. В Lion такое решение deprecated. Тем более с приходом песочницы в 10.8 установка или попытка лезть в систему будет жестко подавлена. Решение в использовании Core Text API.

Последовательность действий File -> CGFontRef -> CTFontRef -> NSFont
Такая схема не работает в SL, разумно использовать старый функционал с заглушками.

Пример загрузки кастомного шрифта из бандла программы.
Для начала, добавим в проект ApplicationServices.framework (уже по умолчанию содержит ссылку на CoreText.framework).

  1. + (CTFontRef) fontFromBundle : (NSString*) fontName 
  2.                   withHeight : (CGFloat) height
  3. {  
  4.     //  
  5.     NSString* fontPath = [[NSBundle mainBundle] pathForResource : fontName 
  6.                                                          ofType : @"ttf" ];   
  7.     if (nil==fontPath)  
  8.         return NULL;  
  9.       
  10.     CGDataProviderRef dataProvider =
  11.     CGDataProviderCreateWithFilename ([fontPath UTF8String]);  
  12.     if (NULL==dataProvider)  
  13.         return NULL;  
  14.       
  15.     //   
  16.     CGFontRef fontRef = CGFontCreateWithDataProvider ( dataProvider );  
  17.     if (NULL == fontRef)  
  18.     {  
  19.         CGDataProviderRelease (dataProvider);   
  20.         return NULL;  
  21.     }      
  22.       
  23.     CTFontRef fontCore = CTFontCreateWithGraphicsFont (fontRef,height,NULL,NULL);  
  24.     CGDataProviderRelease (dataProvider);   
  25.     CGFontRelease (fontRef);  
  26.       
  27.     return fontCore;  
  28. }  

Как использовать в коде.

  1. CTFontRef bundleFont = [CustomFonts fontFromBundle : @"MavenPro-Regular"
  2.                                         withHeight : 25 ];  
  3. NSFont* font = (NSFont*)bundleFont;  
  4. ....  
  5. // use font in application  
  6. ....  
  7. CFRelease(bundleFont);  
  8.    

На заметку.
CoreText можно использовать для рендера сложного текста в UI. В фрэймворке реализована полноценная поддержка Unicode. Поэтому можно использовать прозрачно CTFontRef вместо CGFontRef  при рендере текста в Quartz 2D.

среда, 28 марта 2012 г.

Маркетинг, которого нет...

Прошел ровно год с публикации программы в MAS. Есть желание собрать ворох мыслей, образов и прочей чепухи в стройную концепцию. Что же получилось в итоге.

Выделим основной моменты 


Двигаем машинки...

Сайт. Блог. Персональня страница. Твитер. Фэйсбук. Такие знакомые слова. (с)

Любая ссылка на ваш продукт, пост, обзор, твит, конвертируется в пользователя. Разумно, везде оставлять свой след. Использовать принцип, чем громче крикнешь, тем больше услышат ! (с)

Бесплатные обзоры, с большой вероятностью поднимают волну интереса к вашему продукту.
Важно иметь контакт с блогерами, писать письма, давать промо коды, prerelease версии продуктов. Если вам предлагают платные программы продвижения, за 10 баксов мы напишем в нашем блоге статью или за 20 баксов мы твитнем 1 миллиону наших пользователям. Можете попробовать но эффекта будет ноль. Хорошее продвижение стоит не малых денег.

Промо акции, не делают большой выручки, но определенно создают вокруг вас Booth.
Социальный маркетинг, как теория больших чисел. Почти ни какого эффекта для малых компаний.

Есть такая категория продвижения, как рассылка пресс-релизов. Срабатывает в том случае, если такая рассылка делается за весьма внушительную сумму. То что если вам предлагают за 100 баксов сделать рассылку по по тысячам сайтов, результат вообще ни какой. Рассылка у таких компаний идет по сайтам которые никто не читает.

Сайт - это ваше лицо. Если он перегружен или в нем можно запутаться, увы вы теряете потенциального клиента. Расскажите о том что делает ваш продукт и как вы можете сделать счастливее пользователя или решить его проблему.

Для маленьких компаний упор надо делать на пользователей. Они ваше все ! Прямая связь с людьми которые постоянно пользуются вашим ПО. Персональные тестеры, вдохновители, люди которые могут взглянуть на ваш продукт под другим углом. Определенно надо иметь активных пользователей. Огромный ресурс.

Локализация продукта, вопрос спорный нужна она ? Да. Определенно стоит попробовать. Французы и немцы терпеть не могут English. Японцы... Заниматься этим делом должен профессионал, а не онлайн переводчик.

Пишем коды...

Как это ни банально программа не должна падать.
Если программа выдала сrash, хуже только, если вообще не запускается. От программных ошибок никто не застрахован.

Плавность UI и быстрый отклик.
Для примера нажимаем на кнопку запуска какой то операции - интерфейс не должен несколько секунд быть в ступоре. Что угодно делать, выполнять работу в отдельных потоках, асинхронных очередях, по таймеру, но ни какого дергающегося UI. По поводу отклика, если есть длительная операция, каким то образом показывать что процесс пошел, например Spinner.

Желание впихнуть много функциональных возможностей, пагубно влияет на результат.
Программа должна делать то для чего она сделана, максимально эффективно и понятно пользователю. Важно на этапе проектирования отсечь все лишнее и оставить то что реально нужно. В первой версии, показать хорошие стороны и сделать на них акценты.

Корректная обработка ошибок. Пример из личной практики. Программа при определенных условиях конектится к определенному ресурсу и получает некоторые список данных (условно какой то контент пользователя на определенном ресурсе) и по каким то причинам не можут получить доступ, очень важно это все показать и проинформировать так что бы у пользователя не было вопросов. Получилось сумбурно, аспектов проектирование, не буду касаться, возможно будет целая статья посвященная этой весьма интересной теме.

Агрессивная смена поколений операционных систем.
После выходом новой OS программа должна корректно в ней работать, без вылетов, падений и прочих неприятностей. API постоянно изменяются, а возможность маркировать дистрибутив программы конечной версией OS остается, то у нас есть выбор какую минимальную версию OS поддерживать.

Ох уж этот, Apple Mac Store...


Внятное описание функций программы. Понятные скриншоты. Красивая иконка.
Все в сумме дает положительный эффект. Важно понимать что MAS - это как витрина хорошего магазина, вопрос в том как завлечь пользователя, приобрести ваш продукт. Любая мелочь, например невнятное описание, странные скриншоты или нету доступа к сайту разработчика, могут влиять на пользователя.

Фидбеки. Как было замечено, если у вас программа упала. Или по каким то причинам не запустилась. Вам об этом напишут в красноречивой форме. Пробуйте найти этого пользователя через интернет и исправить возможное недопонимание.

Поддержка новой OS, важно комплексно добавить все фичи новой операционной системы в вашу программу до ее выпуска.

Ваш ядерный контингент, это реальные пользователи. Дайте им возможность без особого напряжение доступ к полному описанию функций вашей программы, FAQ, быстро отписать или получить интересующею их информацию (для этого есть сайт или внутренняя справка).

Выпуск апдейтов, агрессивная смена OS, многие другие факторы вынуждают выпускать продукт с мелкими незначительными изменениями.

Скидки. Опытным путем было выведено, что они полезные. Дают небольшой процент к продажам. Небольшая скидка дает в результате большую прибыль, при сравнение с вариантом без скидки. Такой фактор имеет место быть. С чем это связано, пользователи любят покупать по скидками возможно.

Leitgedanke...
Важно постоянно создавать вокруг вашего продукта движение.

воскресенье, 22 января 2012 г.

Рендер в текстуру на основе opengl fbo

Разнообразие вендоров железа "обогатило" в прекрасном смысле этого слова рендеринг в текстуру. Какая только экзотика не была ( p-buffer ). На данный момент есть вменяемый вариант RTT через расширение EXT_framebuffer_object.  Вся идея данного расширения сводится к добавлению нового объекта FBO ( frame buffer object ). К этому объекту можно сделать привязку различных объектов, будь то буфер цвета, глубины, трафарет или RBO (renderbuffer object).

Приступим к написанию кода

Для начала проверяем поддержку данного расширения 

  1. - (BOOL) initFBO  
  2. {  
  3.     // check extension  
  4.     const GLubyte* extensions = glGetString ( GL_EXTENSIONS );  
  5.     if ( extensions )  
  6.     {     
  7.       if(gluCheckExtension((GLubyte*)("GL_EXT_framebuffer_object"), extensions))  
  8.         return YES;  
  9.     }  
  10.     return NO;  
  11. }  

Создаем текстуру в которую будем рендерить

  1. GLuint textureId      
  2. glGenTextures ( 1, &textureId );  
  3. glBindTexture ( GL_TEXTURE_2D, textureId );  
  4. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );  
  5. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );  
  6. glTexImage2D ( GL_TEXTURE_2D, 0, 4, TextureWidth, TextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );  

Создаем FBO объект

  1. GLuint frameBufferId;  
  2.   
  3. glGenFramebuffersEXT ( 1, &frameBufferId ); // 0 - это главный буфер, очевидно что id > 0  
  4. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, frameBufferId );  
  5. glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,  
  6.  GL_TEXTURE_2D, textureId, 0 ); //привязываем тексту к фрэймбуфер  
  7.   
  8. // проверяем буфер ( код ниже )  
  9. // ...  
  10.   
  11. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, 0 ); // восстанавливаем главный буфер  

Проверка буфера

  1. GLenum status = glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT );  
  2. if ( status != GL_FRAMEBUFFER_COMPLETE_EXT )  
  3. {  
  4.     switch ( status )  
  5.     {  
  6.         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:  
  7.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");  
  8.             break;  
  9.         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:  
  10.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");  
  11.             break;  
  12.         case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:  
  13.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");  
  14.             break;  
  15.         case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:  
  16.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");  
  17.             break;  
  18.         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:  
  19.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");                            
  20.             break;  
  21.         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:  
  22.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");  
  23.             break;  
  24.         case GL_FRAMEBUFFER_UNSUPPORTED_EXT:  
  25.             NSLog(@"FBO GL_FRAMEBUFFER_UNSUPPORTED_EXT");  
  26.             break;  
  27.         default:  
  28.             NSLog(@"FBO Unknown error");  
  29.               
  30.             break;  
  31.     }  
  32.         
  33.     return NO;  
  34. }  

Разумеется можно еще добавить создание буфера глубины или трафарета, сделать привязку к данному FBO. Если все успешно создалось то можно рендерить в текстуру.

  1. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, frameBufferId ); // выставляем нужный нам буфер  
  2.   
  3. glClearColor ( 0.0f, 0.0f, 1.0f, 1.0f );   
  4. glClear ( GL_COLOR_BUFFER_BIT );  
  5.   
  6. // что-то рисуем в текстуру ( корректируем все матрицы )
  7. // ...  
  8.   
  9. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, 0 );      // восстанавливаем буфера окна  

Теперь у нас в текстуре которая была привязана к данному framebuffer объекту находится то что нам нужно. Можем с ней работать как с обычной текстурой. Отрисовать всю сцену в текстуру и применить эфффект блюра.  И конечно не забывайте удалять текстуры и буфера ;-)

Example OpenGL FBO (github) готовый пример показывает наглядно как с этим работать


воскресенье, 8 января 2012 г.

Забавный баг XCode 4.2

На данный момент xcode до той же visal studio далеко. Не факт, что это изменится в ближайшем будущем. Виной тому, весьма плохое отношение разработчиков к более плотному тестирование IDE. В четверке сделали приятное разработчикам разрешили иметь некий аналог солюшенов. Но есть одна фича которой приятно пользоваться, потому как она автоматизирует процесс привязки gui контролов с кодом (actions & properties).

Взглянем на солюшен с двуми проектами один из которых вложенный.
Добавим для формы из второго проекта кнопку. Проведем связь из IB в код для создания @property-кнопки ( не так важно свойство или метод ).


Теперь посмотрим чего же там в итоге то получается. О! В хедер корректно добавлось свойство-кнопка. Но где же описание ? Увы оно в другой проект прописалось.


Возможно этот баг уже поправили. Критичным его назвать сложно. Но в целом можно судить что работа с солюшенами по аналогии с той же студией от микрософт, пока реализована не так хорошо.
Новую морду нацепили, а в результата одни мелкие недоработки.

воскресенье, 1 января 2012 г.

Железяка Amazon Kindle Touch

Прогресс не стоит на месте. Цены падают, устройства становятся более доступныеми для простых смертных. Первая книга с тачем от амазона. Психологический барьер в 100 баксов преодолен ( мне по такой цене удалось заполучить перед НГ девайс, увы c рекламой правда ). Несоменно сравнивать с другими аналогими смысла нету. C тем же Nook, где после некоторых усилий читалку можно превратить в псевдо планшет на электронной бумаге с полноценным андройдом на борту. Но это все лирика. Вернемся к киндлу четвертого поколения.

В общих чертах плюсы

+ сенсорный экран ( это удобно после ipad, iphone и прочих устройств подобной тематики )
+ перелистывание теперь более шустрое ( если сравнивать с третьим поколением )
+ заметки
+ качественная сборка ( ничего не хрустит, не скользит приятный на ощупь пластик )
+ цена ( вы получаете то что вам нужно без всяких не нужных наворотов )

 В числе минусов хотелось бы отметить

- пока сырая прошивка ( мало настроек, поворачивать экран нельзя )
- прощаю что нету поддержки fb2, но где поддержка epub ????
- официально киндл в нашей стране не продается, поэтому ощутить все прелести от платного  контента не получится

Киндл четвертого поколение, эволюционное устройство. Плюсом стало что убрали не нужную механическую клавиатуру. Решать что взять либо киндл с пятью кнопками или с тачем, остается на предпочтениях конечного пользователя.


Update (30.06.2012) 
Обновил прошивку на девайсе до 5.1.0.
Тяжелые книжки стали открываться без подглючивания устройства. Интерфейс стал более отзывчив. Был глюк на 5.0.0 если много закинуть книгу на устройство с устройством происходило странное, переодическое подвисание. После обновление залил более 50 книг большого размера, устройство открывает книги без проблем. Из дополнительных плюсов добавился Landscape Mode, дополнительные настройки форматирование вывода текста (больше текста на экране), поддержка защищенных WI-FI сетей. Добавили кучу локализаций, но увы русского языка нету, видимо его вообще не будет. Кому надо скачают поделки народных умельцев.

Kindle Touch Software Update Version 5.1.0

В итоге имеем более стабильную работу устройства.  Перед прошивкой весь контент лучше удалить.

воскресенье, 2 октября 2011 г.

Немного "the aperture"

Получили отзыв, что не плохо было бы иметь поддержку Aperture. До этого конечно были письма в том же ключе. Отзыв в сторе это намного серьезнее. Скачал, установил творение apple. Программа очень удобная в плане хранения фототеки, фильтры, поддержка raw, в общем все фишки серьезного продукта для работы с фотографиями. Посмотрел как устроено описание фототеки. Аналогия iphoto - xml файлы с описанием всего и вся. Особой сложности при разборе нету, прочесть список ключей фотографий и по ним получить пути к файлам, дальше разбор по альбомам или проектам. Сказано - сделано. Реализовал поддержку aperture - медиа библиотек. Все прекрасно работало пока не отослал для тестирования программу заинтересованым лицам. Итог - ничего не показывается и ничего не работает. В результате неспешной переписки, выясняется что есть несколько способов импорта контента и разумеется несколько способов использования этих самых фототек. Приведу парочку вариантов, один от человека у которого aperture - программа номер один на компе. Второй фотолюбитель со стажем.

Например, пользователь имеет внушительную коллекцию фотографий (750GB), но каждый раз таскать дополнительный винт с базой не комильфо, поэтому он создает фототеку с генерацией превьюшек на пару гигов и может с удобством иметь ее в своем распоряжении. Если у вапс мак бук айр, это актуально. Упс, о таком и не думал.

Несколько иной интерпритации импорт фотографий, при котором не создается файл описания базы в xml формате. Связан с тем что если в фототека очень внушительная, при добавлении фотографий, на создание превьюшек подвисает самым наглым образом. Пользователь об этом отписал, поэтому он отключает все настройки создани превьюшек и апертура показывает оригинальные изображение. Если вы фотограф, то для вас это актуально.

Все это настораживало. Пришлось немного углубиться в aperture. В фототеке (aplibrary) были обнаружены файлы sqllite. О Бинго ! Внутри баз даных была найдена вся информация по фотографиям. Подключил sqlite3 в проект, пару строк кода и имеем полноценную поддержку фототек для разных вариантов импорта.

Мысли приходят, такого характера. Опыт использования программ сторонними пользователями очень важен, когда интегрируешь поддержку других продуктов со своими.

Спасибо Максу, что он внимательно билд за билдом тестил программу.

суббота, 24 сентября 2011 г.

Два месяца с XCode 4

Перешли на новую ide от apple. Можно подвести некоторые итоги.

Понравилось
+ концепция all-in-one ( на большом мониторе чертовски удобно )
+ поддержка workspace ( огромный шаг вперед на встречу с visual studio )
+ переработанный debuger ( мета информация для типов, переключение по потокам )
+ редактор ( tab-интерфейс в редакторе, snippets )
+ help ( удобно интегрирован - Quick Help )
+ инструменты статического анализа и Fix-it (утилиты полезные)
+ Instruments - классно, только железо нужно приличное

Минусы
- сочетания клавиш стали другие
- для разработки нужен монитор желательно 23+ дюйма и достаточно шустрое железо ( разработка не макбуке 13дюймов, будет полным адом )
- иногда вылетает, подвисает ( возможно версия 4.1 на которой работаем глюкавая, надо попробовать 4.2, статус который увы beta )
- редактор ресурсов при сохранении по прежнему создает "тысячу изменений" на одно действие ( поэтому работа с gui по большей части в коде )
- refactoring - лучше не использовать

В целом стало лучше, много мелких улучшений. В 3.x меня напрягал момент набора текста и debuger, в новой версии все это довели до приемлемого уровня. Со всем остальным можно жить и даже получать от этого profit.

понедельник, 5 сентября 2011 г.

Полноэкранный режим в Mac OS X Lion 10.7

Новая операционная система. Новые проблемы и приятные неожиданности.
Переход приложения в полноэкранный режим в новой ОС выглядит гармонично. Анимация, плавное скольжения окна и т.д. Прекрасно в реальности, но пока сыро в плане разработки. Увы сделать свой интересный анимированый переход пока не получилось. Первое на чем споткнулся принудительно запускать  приложение в полноэкранный режим. Есть механизм сохранения состояния программы (мощная штука, но избыточная). Простое решение в коде получилось методом проб и ошибок. 


  1. ................  
  2.  
  3. #import <CoreServices/CoreServices.h>  
  4.   
  5. @implementation NSApplication (SystemVersion)  
  6.   
  7. + (BOOL) usingLionOSX  
  8. {  
  9.     SInt32 minorVersion = 0;  
  10.     SInt32 majorVersion = 0;  
  11.       
  12.     Gestalt(gestaltSystemVersionMajor, &majorVersion);  
  13.     Gestalt(gestaltSystemVersionMinor, &minorVersion);  
  14.       
  15.     return majorVersion == 10 && minorVersion >= 7;      
  16. }  
  17.   
  18. @end  
  19.   
  20. ................  
  21.   
  22. IBOutlet NSWindow*  _mainWindow;    //  in h-file  
  23.   
  24. ................  
  25.   
  26. - (void) applicationDidFinishLaunching : (NSNotification*) notification  
  27. {         
  28. #if (defined(MAC_OS_X_VERSION_10_7)) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7  
  29.       
  30.     if ( [ NSApplication usingLionOSX ] )  
  31.     {  
  32.         [ [ NSApplication sharedApplication ] setPresentationOptions : NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock ];  
  33.           
  34.         NSWindowCollectionBehavior collection = [ _mainWindow collectionBehavior ];  
  35.         collection |= NSWindowCollectionBehaviorFullScreenPrimary;  
  36.          
  37.         [ _mainWindow setCollectionBehavior : collection ];  
  38.         [ _mainWindow toggleFullScreen : self ];  
  39.     }  
  40.      
  41. #endif  
  42. }  

среда, 20 июля 2011 г.

Как получить метаданные из NSImage

Получаем метаданные изображения.

+ (NSDictionary*) exif : (NSString*) file  
  1. {  
  2.     NSDictionary* dic = nil;        
  3.     NSURL* url = [ NSURL fileURLWithPath : file ];
  4.     if ( url )  
  5.     {  
  6.         CGImageSourceRef source = 
  7.         CGImageSourceCreateWithURL ( (CFURLRef) url, NULL);  
  8.           
  9.         if ( NULL == source )   
  10.         {  
  11. #ifdef _DEBUG  
  12.             CGImageSourceStatus status = CGImageSourceGetStatus ( source );  
  13.             NSLog ( @"Error: file name : %@ - Status: %d", file, status );  
  14. #endif            
  15.         }  
  16.         else  
  17.         {             
  18.             CFDictionaryRef metadataRef = 
  19.             CGImageSourceCopyPropertiesAtIndex ( source, 0, NULL );  
  20.             if ( metadataRef )   
  21.             {  
  22.                 NSDictionary* immutableMetadata = (NSDictionary *)metadataRef;  
  23.                 if ( immutableMetadata )  
  24.                 {                 
  25.                     dic =   
  26.                 [ NSDictionary dictionaryWithDictionary : (NSDictionary *)metadataRef ];  
  27.                 }                                          
  28.                   
  29.                 CFRelease ( metadataRef );  
  30.             }  
  31.               
  32.             CFRelease(source);  
  33.             source = nil;  
  34.         }  
  35.     }  
  36.       
  37.     return dic;  
  38. }  

Используем в коде - получение ориентации изображения из метаданных.

  1. NSDictionary* dic = [ ImageLoader exif : filename ];  
  2. NSLog(@"exif : %@", dic);  
  3. if ( dic )  
  4. {  
  5.     NSString* s     =   [ dic valueForKey : @"Orientation" ];  
  6.     NSLog(@"Image : %@ - orentation : %d", filename, [ s intValue ] );  
  7. }  


LOG

2011-07-21 00:20:40.990 test.app[12204:8003] exif : {
    ColorModel = RGB;
    DPIHeight = 72;
    DPIWidth = 72;
    Depth = 8;
    Orientation = 7;
    PixelHeight = 2592;
    PixelWidth = 3872;
    "{JFIF}" =     {
        DensityUnit = 1;
        JFIFVersion =         (
            1,
            1
        );
        XDensity = 72;
        YDensity = 72;
    };
    "{TIFF}" =     {
        Orientation = 7;
    };
}

2011-07-21 00:20:40.991 test.app[12204:8003] Image : /Users/alexey/Desktop/Works/EXIF Orientation Sample Images/7.jpg - orentation : 7

Как правильно преобразовать картинку с учетом ориентации
  1. static inline double rad (int alpha)  
  2. {  
  3.     return ((alpha * pi)/180);  
  4. }  
  5.   
  6. static CGImageRef RotateImageWithFlip (CGImageRef source, float angle, 
  7.                                    BOOL flipX, BOOL flipY)  
  8. {  
  9.     float fX    =  fabs ( cos ( rad ( angle ) ) );  
  10.     float fY    =  fabs ( sin ( rad ( angle ) ) );  
  11.       
  12.     float dW    =  (float)CGImageGetWidth  (source) * fX +
  13.                     (float)CGImageGetHeight (source) * fY;  
  14.     float dH    =  (float)CGImageGetWidth  (source) * fY +
  15.                     (float)CGImageGetHeight (source) * fX;  
  16.       
  17.     CGContextRef context = CGBitmapContextCreate (NULL,  
  18.                                           (size_t)dW, (size_t)dH,   
  19.                                           CGImageGetBitsPerComponent(source),   
  20.                                           0,   
  21.                                           CGImageGetColorSpace(source),  
  22.                                           kCGImageAlphaPremultipliedLast);  
  23.       
  24.     CGContextSetAllowsAntialiasing(context, NO);  
  25.     CGContextSetShouldAntialias(context, NO);  
  26.     CGContextSetInterpolationQuality (context, kCGInterpolationLow);  
  27.       
  28.     CGAffineTransform transform =
  29.     CGAffineTransformMakeTranslation(flipX?dW:0.0f,flipY?dH:0.0f);  
  30.     transform = CGAffineTransformScale (transform,flipX?-1.0:1.0f,flipY?-1.0: 1.0f);  
  31.   
  32.     if (0.0f != angle)  
  33.     {  
  34.         CGAffineTransform rot = CGAffineTransformMakeTranslation (dW*0.5f,dH*0.5f);  
  35.         rot                   = CGAffineTransformRotate(rot, rad ( angle ));  
  36.         rot                   = CGAffineTransformTranslate (rot,-dH*0.5f,-dW*0.5f);  
  37.         transform             = CGAffineTransformConcat(rot, transform);  
  38.     }  
  39.       
  40.     CGContextConcatCTM(context, transform);  
  41.       
  42.     CGContextDrawImage(context, CGRectMake (0, 0, CGImageGetWidth (source),   
  43.                                                     CGImageGetHeight (source)), source);      
  44.     CGContextFlush(context);      
  45.     CGImageRef rotated  =   CGBitmapContextCreateImage(context);  
  46.     CGContextRelease(context);  
  47.   
  48.     return rotated;  
  49. }  
  50.   
  51. static CGImageRef RotateWithEXIF (CGImageRef source, int orientation)  
  52. {  
  53.     switch (orientation)  
  54.     {  
  55.         case 2:  
  56.             return RotateImageWithFlip (source, 0, YES, NO);  
  57.             break;  
  58.         case 3:  
  59.             return RotateImageWithFlip (source, 0, YES, YES);  
  60.             break;  
  61.         case 4:  
  62.             return RotateImageWithFlip (source, 0, NO, YES);  
  63.             break;  
  64.   
  65.         case 5:  
  66.             return RotateImageWithFlip (source, 90, NO, YES);  
  67.             break;  
  68.         case 6:  
  69.             return RotateImageWithFlip (source, -90, NO, NO);  
  70.             break;  
  71.               
  72.         case 7:  
  73.             return RotateImageWithFlip (source, 90, YES, NO);  
  74.             break;  
  75.         case 8:  
  76.             return RotateImageWithFlip (source, -90, YES, YES);  
  77.             break;  
  78.               
  79.         default:  
  80.             break;  
  81.     }  
  82.       
  83.     return NULL;  
  84. }