воскресенье, 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. }  

понедельник, 4 июля 2011 г.

Griffin PowerMate ( манипулятор для компьютера )

Обладаю огромной страстью, к разным прикольным девайсам для компа. На просторах инета был обнаружен, весьма занимательный экземпляр. Чудо колесо, стальное колесо, шайба, как ни называй это устройство Griffin PowerMate. Определенно разнообразит ваш компьютерный быт. Т.к. покупал для своего эппл ноутбука. Не могу сказать, как оно работает под виндой. Под маком все работает, как положено.

Плюсы
- необычность
- неоновая подсветка, можно регулировать, моргание, плавное угасание...
- стальной корпус, подкупает своей "металичностью"
- есть специальное ПО, для удобной настройки

Минусы
- провода usb ( по аналогии с apple track pad, сделать блютуз версию устройства )
- подсветку надо ручками отключать, напрягает что подсветка будет всегда включена при каждой перезагрузке системы
- для разработки под эту штуковину нужен SDK от производителя ( support упорно молчит на предмет, как получить инструментарий разработчика )

воскресенье, 19 июня 2011 г.

NSMutableDictionary to NSUserDefaults

  1. NSMutableDictionary* dic = [ [ NSMutableDictionary alloc ] initWithObjectsAndKeys :   
  2.                             @"500", @"MaxLoadedImages",   
  3.                             @"10",  @"RequestMaxImages",  
  4.                             nil ];   
  5. if ( dic )  
  6. {         
  7.     [ [ NSUserDefaults standardUserDefaults ] setObject : dic forKey : @"flickr.com" ];       
  8.     [ dic release ];  
  9. }  

.............................

  1. NSDictionary* settings          =   [ [ NSUserDefaults standardUserDefaults ] objectForKey : @"flickr.com" ];  
  2. NSInteger maxLoadedImages       =   [ [ settings objectForKey : @"MaxLoadedImages" ] integerValue ];  
  3. NSInteger requestMaxImages      =   [ [ settings objectForKey : @"RequestMaxImages" ] integerValue ];  
  4.   
  5. NSLog(@"settings : %@", settings);  

LOG

2011-06-19 14:07:34.600 test.app[3464:6b03] settings : {
MaxLoadedImages = 500;
RequestMaxImages = 10;
}

вторник, 3 мая 2011 г.

Mac Developer Program регистрация

Получение верицифированого аккаунта занимает от силы несколько дней. В моем случае заняло 3 дня. Первое что необходимо, кредитка для платежей в интернете ( карту заводил в alfa-bank для интернет платежей (master card), apple снимает один раз с нее $99 за Mac Dev Program и больше она нам не нужна). Правильно заполненные данные залог успеха. Поэтому, сначала лучше аккаунт завести на физическое лицо (избавит от бегания по всяким инстанциям). Данные в профиле регистрации, лучше что бы совпадали с данными карты с которой будет снят платеж. 

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

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

Update (11.02.2012) Оплата подписки с пластиковой карты на того кого оформлен аккаунт, избавит от дополнительных телодвижений. По поводу факса, сейчас эта процедура не обязательная, можно отправить письмо. Есть один весьма неприятный момент, название фирмы указывается при регистрации один раз и его вам не могут поменять. Будьте внимательны. (Upd. для физ лица могут поменять на имя продавца, но ни как на другое название).
Продление аккаунт - процедура аналогичная (99 баксов с кредитки с факсом или мэйлом) Если вы проспали момент оплаты, ваша программа автоматически блокируются в сторе.

eurodev@apple(dot)com - для отсылки формы

вторник, 19 апреля 2011 г.

Нотификация между потоками и GUI ( NSNotificationCenter )

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

  1. #pragma mark post thread safe notifity messages   
  2. - (void) sendErrorNotification : (NSString *) message   
  3. {   
  4.   [ [ NSNotificationCenter defaultCenter ] postNotificationName : @"NotifyUser"   
  5.                                                          object : message ];   
  6. }   
  7.    
  8. - (void) postSafeNotifityMessage : (NSString *) message   
  9. {   
  10.        [ self performSelectorOnMainThread : @selector(sendErrorNotification:)   
  11.                                withObject : message     
  12.                             waitUntilDone : NO ];   
  13. }   
  14.    
  15. Пример посылки сообщения об ошибки сети.   
  16.    
  17. - (void) connection : (NSURLConnection *) connection didFailWithError : (NSError *) error   
  18. {   
  19.        [ self postSafeNotifityMessage : [ error localizedDescription ] ];   
  20. }   

воскресенье, 13 февраля 2011 г.

Размышления о mercurial

В силу некоторых обстоятельств, перевели проекты на mercurial.

Первое - сложности при развертываниее сервера для распределенной команды разработчиков. Поэтому сервер имелся только у одного человека.
Второе - у кого нету сервера, создавали свои псевдо мини сервера (отедельны папки).
Было еще несколько проблем, которые доставляли мелкие не удобства при работе с репозиториями.

Выбор пал на mercurial. Децентрализованя система хранения исходников проектов. Сервер в данном случае не нужен. Очень удобно когда можно работать без доступа к центральному репозиторию или когда есть возможность делиться своими экспериментальными ветками с другими участниками разработки.

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


Бесплатный клиент для mac os x MacHG

На данный момент, переход с svn на mercurial, можно считать успешным.

PS. С другой стороны, если у команды разработчиков есть возможность использовать проверенный годами SVN, то было бы глупо откзываться от него ( если еще они сидят в одной комнате, то переход ня mercurial -> just for fun ).

пятница, 21 января 2011 г.

Железяка Amazon Kindle 3 Wi-Fi

Перед Новым Годом решил себя побаловать электронной читалкой книг. Долго не думал выбрал Amazon Kindle 3 Wi-Fi. Цена у него оказалась ниже конкурентов, да и в сравнении с другими аналогами.. Девайс обошелся в 6500 рублей, доставка курьером в руки (купил на ebay.com у дяди, которые уже несколько тыщ распродал ).

Понравилось

- Удобная эргономика приятно держать в руках, небольшой вес
- Идеальный вариант для чтения художественной литературы
- Русский язык в коробке ( понимает русские тексты, плясать с бубном не пришлось )
- Три гига свободного места, в системе определяется как флэшка, достаточно для того что бы не парится. Закинул книгу и читаешь.
- Есть внутренний браузер ( мелочь а приятно )

С этим жить можно

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

Update (14.09.2011) 
Появился тут на днях kindle, который не видит книги прямым копированием из проводника или finder в маке на устройство книг. Желание разбираться с прошивками особо нету. Озадачился программой для с девайсом что бы было все включено.
Как закинуть книгу в kindle ? Используем программу Сalibre ( включает конвертер книг, синхронизацию с устройством, конвертация новостей из сети, управление коллекцией книг ). Программа бесплатная. Проверено работает как на mac os x так и на windows.