Apple macbook_pro-13-inch-late-2012-quick_start.pdf Manuel
Apple macbook_pro-13-inch-late-2012-quick_start.pdf Manuel
Apple sur Fnac.com
- Pour voir la liste complète des manuels APPLE, cliquez ici
ou juste avant la balise de fermeture -->
ou juste avant la balise de fermeture -->
TELECHARGER LE PDF sur :
http://manuals.info.apple.com/en_US/macbook_pro-13-inch-late-2012-quick_start.pdf
Commander un produit Apple sur Fnac.com
Voir également d'autres Guides APPLE :
Apple-macbook_pro-retina-mid-2012-important_product_info_f.pdf-manuel
Apple-iOS_Security_May12.pdf-manue
Apple-Mac-Pro-2008-Performance-and-Productivity-for-Creative-Pros
Apple-iPod_shuffle_4thgen_Manuale_utente.pdf-Italie-Manuel
Apple-KernelProgramming.pdf-manuel
Apple-Core-Data-Model-Versioning-and-Data-Migration-Programming-Guide-manuel
Apple-RED_Workflows_with_Final_Cut_Pro_X.pdf-manuel
Apple-Transitioning-to-ARC-Release-Notes-manuel
Apple-iTunes-Connect-Sales-and-Trends-Guide-manuel
Apple-App-Sandbox-Design-Guide-manuel
Apple-String-Programming-Guide-manuel
Apple-Secure-Coding-Guide-manuel
Apple_AirPort_Networks_Early2009.pdf-manuel
Apple-TimeCapsule_SetupGuide_TA.pdf-manuel
Apple-time_capsule_4th_gen_setup.pdf-manuel
Apple-TimeCapsule_SetupGuide.pdf-manuel
Apple-TimeCapsule_SetupGuide_CH.pdf-Chinois-manuel
Apple-CodeSigningGuide.pdf-manuel
Apple-ViewControllerPGforiOS.pdf-manuel
Apple-KeyValueObserving.pdf-manuel
Apple-mac_mini-late-2012-quick_start.pdf-manuel
Apple-OS-X-Mountain-Lion-Core-Technologies-Overview-June-2012-manuel
Apple-OS-X-Server-Product-Overview-June-2012-manuel
Apple-Apple_Server_Diagnostics_UG_109.pdf-manuel
Apple-PackageMaker_UserGuide.pdf-manuel
Apple-Instrumentos_y_efectos_de_Logic_Studio.pdf-Manuel
Apple-ipod_nano_kayttoopas.pdf-Finlande-Manuel
Apple_ProRes_White_Paper_October_2012.pdf-Manuel
Apple-wp_osx_configuration_profiles.pdf-Manuel
Apple-UsingiTunesProducerFreeBooks.pdf-Manuel
Apple-ipad_manual_do_usuario.pdf-Portugais-Manuel
Apple-Instruments_et_effets_Logic_Studio.pdf-Manuel
Apple-ipod_touch_gebruikershandleiding.pdf-Neerlandais-Manuel
AppleiPod_shuffle_4thgen_Manual_del_usuario.pdf-Espagnol-Manuel
Apple-Premiers-contacts-avec-votre-PowerBook-G4-Manuel
Apple_Composite_AV_Cable.pdf-Manuel
Apple-iPod_shuffle_3rdGen_UG_DK.pdf-Danemark-Manuel
Apple-iPod_classic_160GB_Benutzerhandbuch.pdf-Allemand-Manuel
Apple-VoiceOver_GettingStarted-Manuel
Apple-iPod_touch_2.2_Benutzerhandbuch.pdf-Allemand-Manuel
Apple-Apple_TV_Opstillingsvejledning.pdf-Allemand-Manuel
Apple-iPod_shuffle_4thgen_Manuale_utente.pdf-Italie-Manuel
Apple-iphone_prirucka_uzivatela.pdf-Manuel
Apple-Aan-de-slag-Neerlandais-Manuel
Apple-airmac_express-80211n-2nd-gen_setup_guide.pdf-Thailande-Manuel
Apple-ipod_nano_benutzerhandbuch.pdf-Allemand-Manuel
Apple-aperture3.4_101.pdf-Manuel
Apple-Pages09_Anvandarhandbok.pdf-Manuel
Apple-nike_plus_ipod_sensor_ug_la.pdf-Mexique-Manuel
Apple-ResEdit-Reference-For-ResEdit02.1-Manuel
Apple-ipad_guide_de_l_utilisateur.pdf-Manuel
Apple-Compressor-4-Benutzerhandbuch-Allemand-Manuel
Apple-AirPort_Networks_Early2009_DK.pdf-Danemark-Manuel
Apple-MacBook_Pro_Mid2007_2.4_2.2GHz_F.pdf-Manuel
Apple-MacBook_13inch_Mid2010_UG_F.pdf-Manuel
Apple-Xserve-RAID-Presentation-technologique-Janvier-2004-Manuel
Apple-MacBook_Pro_15inch_Mid2010_F.pdf-Manuel
Apple-AirPort_Express-opstillingsvejledning.pdf-Danemark-Manuel
Apple-DEiPod_photo_Benutzerhandbuch_DE0190269.pdf-Allemand-Manuel
Apple-Final-Cut-Pro-X-Logic-Effects-Reference-Manuel
Apple-iPod_touch_2.1_Brugerhandbog.pdf-Danemark-Manuel
Apple-Remote-Desktop-Administratorhandbuch-Version-3.1-Allemand-Manuel
Apple-Qmaster-4-User-Manual-Manuel
Apple-Server_Administration_v10.5.pdf-Manuel
Apple-ipod_classic_features_guide.pdf-Manuel
Apple-Lecteur-Optique-Manuel
Apple-Carte-AirPort-Manuel
Apple-iPhone_Finger_Tips_Guide.pdf-Anglais-Manuel
Apple-Couvercle-Manuel
Apple-battery.cube.pdf-Manuel
Apple-Boitier-de-l-ordinateur-Manuel
Apple-Pile-Interne-Manuel
Apple-atacable.pdf-Manuel
Apple-videocard.pdf-Manuel
Apple-Guide_de_configuration_de_l_Airport_Express_5.1.pdf-Manuel
Apple-iMac_Mid2010_UG_F.pdf-Manuel
Apple-MacBook_13inch_Mid2009_F.pdf-Manuel
Apple-MacBook_Mid2007_UserGuide.F.pdf-Manuel
Apple-Designing_AirPort_Networks_10.5-Windows_F.pdf-Manuel
Apple-Administration_de_QuickTime_Streaming_et_Broadcasting_10.5.pdf-Manuel
Apple-Opstillingsvejledning_til_TimeCapsule.pdf-Danemark-Manuel
Apple-iPod_nano_5th_gen_Benutzerhandbuch.pdf-Manuel
Apple-iOS_Business.pdf-Manuel
Apple-AirPort_Extreme_Installationshandbuch.pdf-Manuel
Apple-Final_Cut_Express_4_Installation_de_votre_logiciel.pdf-Manuel
Apple-MacBook_Pro_15inch_2.53GHz_Mid2009.pdf-Manuel
Apple-Network_Services.pdf-Manuel
Apple-Aperture_Performing_Adjustments_f.pdf-Manuel
Apple-Supplement_au_guide_Premiers_contacts.pdf-Manuel
Apple-Administration_des_images_systeme_et_de_la_mise_a_jour_de_logiciels_10.5.pdf-Manuel
Apple-Mac_OSX_Server_v10.6_Premiers_contacts.pdf-Francais-Manuel
Apple-Designing_AirPort_Networks_10.5-Windows_F.pdf-Manuel
Apple-Mise_a_niveau_et_migration_v10.5.pdf-Manue
Apple-MacBookPro_Late_2007_2.4_2.2GHz_F.pdf-Manuel
Apple-Mac_mini_Late2009_SL_Server_F.pdf-Manuel
Apple-Mac_OS_X_Server_10.5_Premiers_contacts.pdf-Manuel
Apple-iPod_touch_2.0_Guide_de_l_utilisateur_CA.pdf-Manuel
Apple-MacBook_Pro_17inch_Mid2010_F.pdf-Manuel
Apple-Comment_demarrer_Leopard.pdf-Manuel
Apple-iPod_2ndGen_USB_Power_Adapter-FR.pdf-Manuel
Apple-Feuille_de_operations_10.4.pdf-Manuel
Apple-Time_Capsule_Installationshandbuch.pdf-Allemand-Manuel
Apple-F034-2262AXerve-grappe.pdf-Manuel
Apple-Mac_Pro_Early2009_4707_UG_F
Apple-imacg5_17inch_Power_Supply
Apple-Logic_Studio_Installieren_Ihrer_Software_Retail
Apple-IntroductionXserve1.0.1
Apple-Aperture_Getting_Started_d.pdf-Allemand
Apple-getting_started_with_passbook
Apple-iPod_mini_2nd_Gen_UserGuide.pdf-Anglais
Apple-Deploiement-d-iPhone-et-d-iPad-Reseaux-prives-virtuels
Apple-F034-2262AXerve-grappe
Apple-Mac_OS_X_Server_Glossaire_10.5
Apple-FRLogic_Pro_7_Guide_TDM
Apple-iphone_bluetooth_headset_userguide
Apple-Administration_des_services_reseau_10.5
Apple-imacg5_17inch_harddrive
Apple-iPod_nano_4th_gen_Manuale_utente
Apple-iBook-G4-Getting-Started
Apple-XsanGettingStarted
Apple-Mac_mini_UG-Early2006
Apple-Guide_des_fonctionnalites_de_l_iPod_classic
Apple-Guide_de_configuration_d_Xsan_2
Apple-MacBook_Late2006_UsersGuide
Apple-sur-Fnac.com
Apple-Mac_mini_Mid2010_User_Guide_F.pdf-Francais
Apple-PowerBookG3UserManual.PDF.Anglais
Apple-Installation_de_votre_logiciel_Logic_Studio_Retail
Apple-Pages-Guide-de-l-utilisateur
Apple-MacBook_Pro_13inch_Mid2009.pdf.Anglais
Apple-MacBook_Pro_15inch_Mid2009
Apple-Installation_de_votre_logiciel_Logic_Studio_Upgrade
Apple-FRLogic_Pro_7_Guide_TDM
Apple-airportextreme_802.11n_userguide
Apple-iPod_shuffle_3rdGen_UG
Apple-iPod_classic_160GB_User_Guide
Apple-iPod_nano_5th_gen_UserGuide
Apple-ipod_touch_features_guide
Apple-Wireless_Mighty_Mouse_UG
Apple-Advanced-Memory-Management-Programming-Guide
Apple-iOS-App-Programming-Guide
Apple-Concurrency-Programming-Guide
Apple-MainStage-2-User-Manual-Anglais
Apple-iMacG3_2002MultilingualUserGuide
Apple-iBookG3_DualUSBUserGuideMultilingual.PDF.Anglais
Apple-imacG5_20inch_AirPort
Apple-Guide_de_l_utilisateur_de_Mac_Pro_Early_2008
Apple-Installation_de_votre_logiciel_Logic_Express_8
Apple-iMac_Guide_de_l_utilisateur_Mid2007
Apple-imacg5_20inch_OpticalDrive
Apple-FCP6_Formats_de_diffusion_et_formats_HD
Apple-prise_en_charge_des_surfaces_de_controle_logic_pro_8
Apple-Aperture_Quick_Reference_f
Apple-Shake_4_User_Manual
Apple-aluminumAppleKeyboard_wireless2007_UserGuide
Apple-ipod_shuffle_features_guide
Apple-Color-User-Manual
Apple-XsanGettingStarted
Apple-Migration_10.4_2e_Ed
Apple-MacBook_Air_SuperDrive
Apple-MacBook_Late2007-f
ApplePowerMacG5_(Early_2005)_UserGuide
Apple-iSightUserGuide
Apple-MacBook_Pro_Early_2008_Guide_de_l_utilisateur
Apple-Nouvelles-fonctionnalites-aperture-1.5
Apple-premiers_contacts_2e_ed_10.4.pdf-Mac-OS-X-Server
Apple-premiers_contacts_2e_ed_10.4
Apple-eMac_2005UserGuide
Apple-imacg5_20inch_Inverter
Apple-Keynote2_UserGuide.pdf-Japon
Apple-Welcome_to_Tiger.pdf-Japon
Apple-XsanAdminGuide_j.pdf-Japon
Apple-PowerBookG4_UG_15GE.PDF-Japon
Apple-Xsan_Migration.pdf-Japon
Apple-Xserve_Intel_DIY_TopCover_JA.pdf-Japon
Apple-iPod_nano_6thgen_User_Guide_J.pdf-Japon
Apple-Aperture_Photography_Fundamentals.pdf-Japon
Apple-nikeipod_users_guide.pdf-Japon
Apple-QuickTime71_UsersGuide.pdf-Japon
Apple-iMacG5_iSight_UG.pdf-Japon
Apple-Aperture_Performing_Adjustments_j.pdf-Japon
Apple-iMacG5_17inch_HardDrive.pdf-Japon
Apple-iPod_shuffle_Features_Guide_J.pdf-Japon
Apple-MacBook_Air_User_Guide.pdf-Japon
Apple-MacBook_UsersGuide.pdf-Japon
Apple-iPad_iOS4_Brukerhandbok.pdf-Norge-Norvege
Apple-Apple_AirPort_Networks_Early2009_H.pd-Norge-Norvege
Apple-iPod_classic_120GB_no.pdf-Norge-Norvege
Apple-StoreKitGuide.pdf-Japon
Apple-Xserve_Intel_DIY_ExpansionCardRiser_JA.pdf-Japon
Apple-iMacG5_Battery.pdf-Japon
Apple-Logic_Pro_8_Getting_Started.pdf-Japon
Apple-PowerBook-handbok-Norge-Norveg
Apple-iWork09_formler_og_funksjoner.pdf-Norge-Norvege
Apple-MacBook_Pro_15inch_Mid2010_H.pdf-Norge-Norvege
Apple-MacPro_HardDrive_DIY.pdf-Japon
Apple-iPod_Fifth_Gen_Funksjonsoversikt.pdf-Norge-Norvege
Apple-MacBook_13inch_white_Early2009_H.pdf-Norge-Norvege
Apple-GarageBand_09_Komme_i_gang.pdf-Norge-Norvege
Apple-MacBook_Pro_15inch_Mid2009_H.pdf-Norge-Norvege
Apple-imac_mid2011_ug_h.pdf-Norge-Norvege
Apple-iDVD_08_Komme_i_gang.pdf-Norge-Norvege
Apple-MacBook_Air_11inch_Late2010_UG_H.pdf-Norge-Norvege
Apple-iMac_Mid2010_UG_H.pdf-Norge-Norvege
Apple-MacBook_13inch_Mid2009_H.pdf-Norge-Norvege
/Apple-iPhone_3G_Viktig_produktinformasjon_H-Norge-Norvege
Apple-MacBook_13inch_Mid2010_UG_H.pdf-Norge-Norvege
Apple-macbook_air_13inch_mid2011_ug_no.pdf-Norge-Norvege
Apple-Mac_mini_Early2009_UG_H.pdf-Norge-Norvege
Apple-ipad2_brukerhandbok.pdf-Norge-Norvege
Apple-iPhoto_08_Komme_i_gang.pdf-Norge-Norvege
Apple-MacBook_Air_Brukerhandbok_Late2008.pdf-Norge-Norvege
Apple-Pages09_Brukerhandbok.pdf-Norge-Norvege
Apple-MacBook_13inch_Late2009_UG_H.pdf-Norge-Norvege
Apple-iPhone_3GS_Viktig_produktinformasjon.pdf-Norge-Norvege
Apple-MacBook_13inch_Aluminum_Late2008_H.pdf-Norge-Norvege
Apple-Wireless_Keyboard_Aluminum_2007_H-Norge-Norvege
Apple-NiPod_photo_Brukerhandbok_N0190269.pdf-Norge-Norvege
Apple-MacBook_Pro_13inch_Mid2010_H.pdf-Norge-Norvege
Apple-MacBook_Pro_17inch_Mid2010_H.pdf-Norge-Norvege
Apple-Velkommen_til_Snow_Leopard.pdf-Norge-Norvege.htm
Apple-TimeCapsule_Klargjoringsoversikt.pdf-Norge-Norvege
Apple-iPhone_3GS_Hurtigstart.pdf-Norge-Norvege
Apple-Snow_Leopard_Installeringsinstruksjoner.pdf-Norge-Norvege
Apple-iMacG5_iSight_UG.pdf-Norge-Norvege
Apple-iPod_Handbok_S0342141.pdf-Norge-Norvege
Apple-ipad_brukerhandbok.pdf-Norge-Norvege
Apple-GE_Money_Bank_Handlekonto.pdf-Norge-Norvege
Apple-MacBook_Air_11inch_Late2010_UG_H.pdf-Norge-Norvege
Apple-iPod_nano_6thgen_Brukerhandbok.pdf-Norge-Norvege
Apple-iPod_touch_iOS4_Brukerhandbok.pdf-Norge-Norvege
Apple-MacBook_Air_13inch_Late2010_UG_H.pdf-Norge-Norvege
Apple-MacBook_Pro_15inch_Early2011_H.pdf-Norge-Norvege
Apple-Numbers09_Brukerhandbok.pdf-Norge-Norvege
Apple-Welcome_to_Leopard.pdf-Japon
Apple-PowerMacG5_UserGuide.pdf-Norge-Norvege
Apple-iPod_touch_2.1_Brukerhandbok.pdf-Norge-Norvege
Apple-Boot_Camp_Installering-klargjoring.pdf-Norge-Norvege
Apple-MacOSX10.3_Welcome.pdf-Norge-Norvege
Apple-iPod_shuffle_3rdGen_UG_H.pdf-Norge-Norvege
Apple-iPhone_4_Viktig_produktinformasjon.pdf-Norge-Norvege
Apple_TV_Klargjoringsoversikt.pdf-Norge-Norvege
Apple-iMovie_08_Komme_i_gang.pdf-Norge-Norvege
Apple-iPod_classic_160GB_Brukerhandbok.pdf-Norge-Norvege
Apple-Boot_Camp_Installering_10.6.pdf-Norge-Norvege
Apple-Network-Services-Location-Manager-Veiledning-for-nettverksadministratorer-Norge-Norvege
Apple-iOS_Business_Mar12_FR.pdf
Apple-PCIDualAttachedFDDICard.pdf
Apple-Aperture_Installing_Your_Software_f.pdf
Apple-User_Management_Admin_v10.4.pdf
Apple-Compressor-4-ユーザーズマニュアル Japon
Apple-Network_Services_v10.4.pdf
Apple-iPod_2ndGen_USB_Power_Adapter-DE
Apple-Mail_Service_v10.4.pdf
Apple-AirPort_Express_Opstillingsvejledning_5.1.pdf
Apple-MagSafe_Airline_Adapter.pdf
Apple-L-Apple-Multiple-Scan-20-Display
Apple-Administration_du_service_de_messagerie_10.5.pdf
Apple-System_Image_Admin.pdf
Apple-iMac_Intel-based_Late2006.pdf-Japon
Apple-iPhone_3GS_Finger_Tips_J.pdf-Japon
Apple-Power-Mac-G4-Mirrored-Drive-Doors-Japon
Apple-AirMac-カード取り付け手順-Japon
Apple-iPhone開発ガイド-Japon
Apple-atadrive_pmg4mdd.j.pdf-Japon
Apple-iPod_touch_2.2_User_Guide_J.pdf-Japon
Apple-Mac_OS_X_Server_v10.2.pdf
Apple-AppleCare_Protection_Plan_for_Apple_TV.pdf
Apple_Component_AV_Cable.pdf
Apple-DVD_Studio_Pro_4_Installation_de_votre_logiciel
Apple-Windows_Services
Apple-Motion_3_New_Features_F
Apple-g4mdd-fw800-lowerfan
Apple-MacOSX10.3_Welcome
Apple-Print_Service
Apple-Xserve_Setup_Guide_F
Apple-PowerBookG4_17inch1.67GHzUG
Apple-iMac_Intel-based_Late2006
Apple-Installation_de_votre_logiciel
Apple-guide_des_fonctions_de_l_iPod_nano
Apple-Administration_de_serveur_v10.5
Apple-Mac-OS-X-Server-Premiers-contacts-Pour-la-version-10.3-ou-ulterieure
Apple-boot_camp_install-setup
Apple-iBookG3_14inchUserGuideMultilingual
Apple-mac_pro_server_mid2010_ug_f
Apple-Motion_Supplemental_Documentation
Apple-imac_mid2011_ug_f
Apple-iphone_guide_de_l_utilisateur
Apple-macbook_air_11inch_mid2011_ug_fr
Apple-NouvellesfonctionnalitesdeLogicExpress7.2
Apple-QT_Streaming_Server
Apple-Web_Technologies_Admin
Apple-Mac_Pro_Early2009_4707_UG
Apple-guide_de_l_utilisateur_de_Numbers08
Apple-Decouverte_d_Aperture_2
Apple-Guide_de_configuration_et_d'administration
Apple-mac_integration_basics_fr_106.
Apple-iPod_shuffle_4thgen_Guide_de_l_utilisateur
Apple-ARA_Japan
Apple-081811_APP_iPhone_Japanese_v5.4.pdf-Japan
Apple-Recycle_Contract120919.pdf-Japan
Apple-World_Travel_Adapter_Kit_UG
Apple-iPod_nano_6thgen_User_Guide
Apple-RemoteSupportJP
Apple-Mac_mini_Early2009_UG_F.pdf-Manuel-de-l-utilisateur
Apple-Compressor_3_Batch_Monitor_User_Manual_F.pdf-Manuel-de-l-utilisateur
Apple-Premiers__contacts_avec_iDVD_08
Apple-Mac_mini_Intel_User_Guide.pdf
Apple-Prise_en_charge_des_surfaces_de_controle_Logic_Express_8
Apple-mac_integration_basics_fr_107.pdf
Apple-Final-Cut-Pro-7-Niveau-1-Guide-de-preparation-a-l-examen
Apple-Logic9-examen-prep-fr.pdf-Logic-Pro-9-Niveau-1-Guide-de-preparation-a-l-examen
Apple-aperture_photography_fundamentals.pdf-Manuel-de-l-utilisateu
Apple-emac-memory.pdf-Manuel-de-l-utilisateur
Apple-Apple-Installation-et-configuration-de-votre-Power-Mac-G4
Apple-Guide_de_l_administrateur_d_Xsan_2.pdf
Apple-premiers_contacts_avec_imovie6.pdf
Apple-Tiger_Guide_Installation_et_de_configuration.pdf
Apple-Final-Cut-Pro-7-Level-One-Exam-Preparation-Guide-and-Practice-Exam
Apple-Open_Directory.pdf
Apple-Nike_+_iPod_User_guide
Apple-ard_admin_guide_2.2_fr.pdf
Apple-systemoverviewj.pdf-Japon
Apple-Xserve_TO_J070411.pdf-Japon
Apple-Mac_Pro_User_Guide.pdf
Apple-iMacG5_iSight_UG.pdf
Apple-premiers_contacts_avec_iwork_08.pdf
Apple-services_de_collaboration_2e_ed_10.4.pdf
Apple-iPhone_Bluetooth_Headset_Benutzerhandbuch.pdf
Apple-Guide_de_l_utilisateur_de_Keynote08.pdf
APPLE/Apple-Logic-Pro-9-Effectsrfr.pdf
Apple-Logic-Pro-9-Effectsrfr.pdf
Apple-iPod_shuffle_3rdGen_UG_F.pdf
Apple-iPod_classic_160Go_Guide_de_l_utilisateur.pdf
Apple-iBookG4GettingStarted.pdf
Apple-Administration_de_technologies_web_10.5.pdf
Apple-Compressor-4-User-Manual-fr
Apple-MainStage-User-Manual-fr.pdf
Apple-Logic_Pro_8.0_lbn_j.pdf
Apple-PowerBookG4_15inch1.67-1.5GHzUserGuide.pdf
Apple-MacBook_Pro_15inch_Mid2010_CH.pdf
Apple-LED_Cinema_Display_27-inch_UG.pdf
Apple-MacBook_Pro_15inch_Mid2009_RS.pdf
Apple-macbook_pro_13inch_early2011_f.pdf
Apple-iMac_Mid2010_UG_BR.pdf
Apple-iMac_Late2009_UG_J.pdf
Apple-iphone_user_guide-For-iOS-6-Software
Apple-iDVD5_Getting_Started.pdf
Apple-guide_des_fonctionnalites_de_l_ipod_touch.pdf
Apple_iPod_touch_User_Guide
Apple_macbook_pro_13inch_early2011_f
Apple_Guide_de_l_utilisateur_d_Utilitaire_RAID
Apple_Time_Capsule_Early2009_Setup_F
Apple_iphone_4s_finger_tips_guide_rs
Apple_iphone_upute_za_uporabu
Apple_ipad_user_guide_ta
Apple_iPod_touch_User_Guide
apple_earpods_user_guide
apple_iphone_gebruikershandleiding
apple_iphone_5_info
apple_iphone_brukerhandbok
apple_apple_tv_3rd_gen_setup_tw
apple_macbook_pro-retina-mid-2012-important_product_info_ch
apple_Macintosh-User-s-Guide-for-Macintosh-PowerBook-145
Apple_ipod_touch_user_guide_ta
Apple_TV_2nd_gen_Setup_Guide_h
Apple_ipod_touch_manual_del_usuario
Apple_iphone_4s_finger_tips_guide_tu
Apple_macbook_pro_retina_qs_th
Apple-Manuel_de_l'utilisateur_de_Final_Cut_Server
Apple-iMac_G5_de_lutilisateur
Apple-Cinema_Tools_4.0_User_Manual_F
Apple-Personal-LaserWriter300-User-s-Guide
Apple-QuickTake-100-User-s-Guide-for-Macintosh
Apple-User-s-Guide-Macintosh-LC-630-DOS-Compatible
Apple-iPhone_iOS3.1_User_Guide
Apple-iphone_4s_important_product_information_guide
Apple-iPod_shuffle_Features_Guide_F
Liste-documentation-apple
Apple-Premiers_contacts_avec_iMovie_08
Apple-macbook_pro-retina-mid-2012-important_product_info_br
Apple-macbook_pro-13-inch-mid-2012-important_product_info
Apple-macbook_air-11-inch_mid-2012-qs_br
Apple-Manuel_de_l_utilisateur_de_MainStage
Apple-Compressor_3_User_Manual_F
Apple-Color_1.0_User_Manual_F
Apple-guide_de_configuration_airport_express_4.2
Apple-TimeCapsule_SetupGuide
Apple-Instruments_et_effets_Logic_Express_8
Apple-Manuel_de_l_utilisateur_de_WaveBurner
Apple-Macmini_Guide_de_l'utilisateur
Apple-PowerMacG5_UserGuide
Disque dur, ATA parallèle Instructions de remplacement
Apple-final_cut_pro_x_logic_effects_ref_f
Apple-Leopard_Installationshandbok
Manuale Utente PowerBookG4
Apple-thunderbolt_display_getting_started_1e
Apple-Compressor-4-Benutzerhandbuch
Apple-macbook_air_11inch_mid2011_ug
Apple-macbook_air-mid-2012-important_product_info_j
Apple-iPod-nano-Guide-des-fonctionnalites
Apple-iPod-nano-Guide-des-fonctionnalites
Apple-iPod-nano-Guide-de-l-utilisateur-4eme-generation
Apple-iPod-nano-Guide-de-l-utilisateur-4eme-generation
Apple-Manuel_de_l_utilisateur_d_Utilitaire_de_reponse_d_impulsion
Apple-Aperture_2_Raccourcis_clavier
AppleTV_Setup-Guide
Apple-livetype_2_user_manual_f
Apple-imacG5_17inch_harddrive
Apple-macbook_air_guide_de_l_utilisateur
Apple-MacBook_Early_2008_Guide_de_l_utilisateur
Apple-Keynote-2-Guide-de-l-utilisateur
Apple-PowerBook-User-s-Guide-for-PowerBook-computers
Apple-Macintosh-Performa-User-s-Guide-5200CD-and-5300CD
Apple-Macintosh-Performa-User-s-Guide
Apple-Workgroup-Server-Guide
Apple-iPod-nano-Guide-des-fonctionnalites
Apple-iPad-User-Guide-For-iOS-5-1-Software
Apple-Boot-Camp-Guide-d-installation-et-de-configuration
Apple-iPod-nano-Guide-de-l-utilisateur-4eme-generation
Power Mac G5 Guide de l’utilisateur APPLE
Guide de l'utilisateur PAGE '08 APPLE
Guide de l'utilisateur KEYNOTE '09 APPLE
Guide de l'Utilisateur KEYNOTE '3 APPLE
Guide de l'Utilisateur UTILITAIRE RAID
Guide de l'Utilisateur Logic Studio
Power Mac G5 Guide de l’utilisateur APPLE
Guide de l'utilisateur PAGE '08 APPLE
Guide de l'utilisateur KEYNOTE '09 APPLE
Guide de l'Utilisateur KEYNOTE '3 APPLE
Guide de l'Utilisateur UTILITAIRE RAID
Guide de l'Utilisateur Logic Studio
Guide de l’utilisateur ipad Pour le logiciel iOS 5.1
PowerBook G4 Premiers Contacts APPLE
Guide de l'Utilisateur iphone pour le logiciel ios 5.1 APPLE
Guide de l’utilisateur ipad Pour le logiciel iOS 4,3
Guide de l’utilisateur iPod nano 5ème génération
Guide de l'utilisateur iPod Touch 2.2 APPLE
Guide de l’utilisateur QuickTime 7 Mac OS X 10.3.9 et ultérieur Windows XP et Windows 2000
Guide de l'utilisateur MacBook 13 pouces Mi 2010
Guide de l’utilisateur iPhone (Pour les logiciels iOS 4.2 et 4.3)
Guide-de-l-utilisateur-iPod-touch-pour-le-logiciel-ios-4-3-APPLE
Guide-de-l-utilisateur-iPad-2-pour-le-logiciel-ios-4-3-APPLE
Guide de déploiement en entreprise iPhone OS
Guide-de-l-administrateur-Apple-Remote-Desktop-3-1
Guide-de-l-utilisateur-Apple-Xserve-Diagnostics-Version-3X103
Guide-de-configuration-AirPort-Extreme-802.11n-5e-Generation
Guide-de-configuration-AirPort-Extreme-802-11n-5e-Generation
Guide-de-l-utilisateur-Capteur-Nike-iPod
Guide-de-l-utilisateur-iMac-21-5-pouces-et-27-pouces-mi-2011-APPLE
Guide-de-l-utilisateur-Apple-Qadministrator-4
Guide-d-installation-Apple-TV-3-eme-generation
User-Guide-iPad-For-ios-5-1-Software
Let’s get started
When you start your MacBook Pro for the first time, Setup Assistant will help
you get going. Just follow a few simple steps to quickly connect to your Wi-Fi
network, transfer your stuff from another Mac or a PC, and create a user
account for your Mac.
You’ll also be able to log in with your Apple ID. This will allow you to shop
the App Store, iTunes Store, and Apple Online Store. It will let you keep in
touch using Messages and FaceTime. And it will let you access iCloud, which
is automatically set up on your Mac in apps like Mail, Contacts, and Calendar.
If you don’t have an Apple ID, you can create one in Setup Assistant.
Multi-Touch gestures
You can do a lot of things on your MacBook Pro using simple gestures
on the trackpad. Here are some of the most popular ones.
Get to know your desktop
The desktop is where you can find everything and do anything on your Mac.
The Dock at the bottom of the screen is a handy place to keep the apps you
use most. It’s also where you can open System Preferences, which lets you
customize your desktop and other settings on your Mac. Click the Finder
icon to quickly get to all your files and folders.
The menu bar at the top has lots of useful information about your Mac.
To check the status of your wireless Internet connection, click the Wi-Fi icon.
Your Mac automatically connects to the network you chose during setup.
Hello.
Multi-Touch
trackpad
MagSafe 2 power
connector
Power
adapter
AC power
cord
Power
button
Click
Press down anywhere on the trackpad
to click. Or, with Tap to Click enabled,
simply tap the surface.
Secondary click (right click)
Click with two fingers to open shortcut
menus. Or, with Tap to Click enabled, tap
two fingers anywhere.
Swipe to navigate
Swipe with two fingers to flip through
web pages, documents, and more.
Double click
Press down two times anywhere on the
trackpad. Or, with Tap to Click enabled,
double-tap the surface.
Two-finger scroll
Brush two fingers along the trackpad
to scroll in any direction—up, down,
or sideways.
Smart zoom
Double-tap the trackpad with two
fingers to quickly magnify a web page.
Pinch to zoom
Zoom in and out of photos and web
pages more precisely by pinching your
thumb and finger.
Switch between full-screen apps
Swipe with three fingers to move
from one full-screen app to another.
View Launchpad
Pinch with four fingers to view
all your apps in Launchpad.
Rotate
Turn your thumb and finger clockwise
or counterclockwise to rotate an image.
View Mission Control
Swipe up with three fingers to see
every open window on your Mac.
Learn more
Choose System Preferences from the
Apple menu and click Trackpad to learn
more about gestures.
iCloud
iCloud stores your music, photos, documents, calendars, and more. And
it wirelessly pushes them to your Mac, iPhone, iPad, iPod touch, and even
your PC. All without docking or syncing. So when you buy a song on one
device, it’s instantly available on all your other devices. When you adjust
your calendar, all your devices stay up to date. And with Photo Stream,
your latest photos appear everywhere you want to see them, automatically.
To customize your iCloud settings, open the Apple menu, choose System
Preferences, and click iCloud. Then sign in with your Apple ID and choose
the iCloud features you want to use.
An important note
Please read this document and the safety information in the Important
Product Information Guide carefully before you first use your computer.
Learn more
You can find more information, watch demos, and learn even more about
MacBook Pro features at www.apple.com/macbookpro.
Help
You can often find answers to your questions, as well as instructions
and troubleshooting information, in Help Center. Click the Finder icon,
click Help in the menu bar, and choose Help Center.
OS X Utilities
If you have a problem with your Mac, OS X Utilities can help you repair
your computer’s flash storage, restore your software and data from a
Time Machine backup, or erase your flash storage and reinstall OS X
and Apple applications. You can also use Safari to get online help. If your
Mac detects a problem, it opens OS X Utilities automatically. Or you
can open it manually by restarting your computer while holding down
the Command and R keys.
Support
Your MacBook Pro comes with 90 days of technical support and one year
of hardware repair warranty coverage at an Apple Retail Store or an Apple
Authorized Service Provider. Visit www.apple.com/support/macbookpro
for MacBook Pro technical support. Or call 1-800-275-2273. In Canada,
call 1-800-263-3394.
Not all features are available in all areas.
TM and © 2012 Apple Inc. All rights reserved. Designed by Apple in California. Printed in XXXX.
034-6357-A
AC plug
Help
menu
Menu bar
Finder Dock
System
Preferences
Quick Start Guide
Let’s get moving
It’s easy to move files like documents, email, photos, music, and movies
to your new Mac from another Mac or a PC. The first time you start your
new Mac, it will walk you through the process step by step. All you have
to do is follow the onscreen instructions.
Welcome to your new MacBook Pro. We’d like to show you around.
MagSafe 2 USB 3 Headphone
FaceTime HD camera
SDXC HDMI USB 3
Wi-Fi
status
Thunderbolt Dual
microphonesClick the Safari icon in the Dock
and surf the web quickly and easily
with Multi-Touch gestures. Scroll
up or down with two fingers on the
trackpad. Swipe right and left with
two fingers to go back and forth
Safari web browser Mail
Top Sites
Get a quick overview
of the sites you visit
most often.
One-stop email
View all your accounts in
Mail for one-click access.
Conversation view
See all the email
messages from a
conversation thread.
Search
Quickly narrow search
results to find exactly
what you want.
Mail lets you manage all your
email accounts from a single,
ad-free inbox, even when you’re
not connected to the Internet. It
works with most email standards—
including POP3 and IMAP—and
between pages. Double-tap with
two fingers to magnify a page,
then double-tap again to return
to the original size. Or pinch to
zoom in and out.
popular email services like Gmail,
Yahoo! Mail, and AOL Mail. You can
also use Mail for the free me.com
email account you get with iCloud.
The first time you open Mail, Setup
Assistant will help you get started.
Launchpad
Open Launchpad
Click the Launchpad
icon in the Dock.
Folders
Group apps in folders
by dragging one app
on top of another.
Launchpad is the home for all the
apps on your Mac. Just click the
Launchpad icon in the Dock, and
your open windows are replaced by
a full-screen display of all your apps.
Arrange apps any way you want,
group them together in folders,
or delete them from your Mac.
When you download an app from
the Mac App Store, it automatically
appears in Launchpad.
Mission Control
Mission Control gives you a
bird’s-eye view of everything
running on your Mac. Click the
Mission Control icon in the Dock,
and your desktop zooms out to
display all the open windows in
every application, all your fullscreen apps, and Dashboard, the
home of mini-apps called widgets.
Click anything to zoom in on it.
Think of Mission Control as the hub
of your system—view everything
and go anywhere with just a click.
Open Mission Control
Click the Mission Control
icon in the Dock.
Add desktop spaces
Click the + button
to the right of the top
row to add a new space.
Dashboard
Located at the top
left for easy access.
Reading List
Click the glasses icon to
save pages to read later.
Mac App Store
The Mac App Store is the best way
to find and download thousands of
apps for your Mac, from games and
social networking to productivity
apps and more. New apps install
in one step to Launchpad. You can
install apps on every Mac authorized
for your personal use and even
download them again. The Mac
App Store lets you know when app
and OS X updates are available, so
you always have the latest versions.
Open the Mac App Store by clicking
its icon in the Dock.
iTunes
With iTunes, you can organize and
play your digital music and videos
on your Mac. And you can shop in
the iTunes Store for new music,
movies, TV shows, books, and more.
iTunes is also where you’ll find the
App Store for iPad, iPhone, and
iPod touch.
iTunes Store
Discover and buy new music,
movies, and more.
Genius Mixes
Let iTunes search your music
library and group songs that
go great together.
Calendar
Multiple calendars
Access all your calendars
from one place.
Keep track of your busy schedule
with Calendar. You can create
separate calendars—one for home,
another for school, a third for work.
See all your calendars in a single
window or choose to see only the
calendars you want. Create and
send invitations using contact info
from the Contacts app, then see
who has responded. Use iCloud
to update calendars on all your
devices automatically or share
calendars with other iCloud users.
iPhoto
Create
Create books,
cards, and calendars.
Faces
iPhoto can even organize
your photos based on
who’s in them.
Events
Double-click any Event
to browse photos.
iPhoto is the best way to organize,
browse, edit, and share your photos
on your Mac. You can organize your
photo library by Faces, Places, and
Events. To send photos by email
or publish them to Facebook, just
select the photo and click Share
in the bottom right of your screen.
Or click Create to turn your favorite
shots into photo books, calendars,
and cards.
iMovie
Event browser
Your imported videos
appear here so you
can access all your clips.
Project browser
Simply drop your clips
in a project to create
a great movie.
iMovie puts all your video clips
in one place and gives you the
editing tools and special effects
you need to quickly turn them
into something memorable. You
can make great-looking movies
or even Hollywood-style movie
trailers with just a few clicks. And
iMovie lets you import video from
most popular digital video cameras,
your iPhone, iPad, or iPod touch,
or the FaceTime HD camera on
your Mac.
Messages
Just log in with your Apple ID, and
you can send unlimited messages
including text, photos, videos, and
more to your friends on a Mac, iPad,
iPhone, or iPod touch. With iCloud,
you can start a conversation on one
device and pick it up on another.
And if you want to talk to someone
face to face, you can start a video
call* just by clicking the FaceTime
icon in the top-right corner of the
Messages window.
Replies in progress
Three dots mean your
friend is typing a reply.
Delivery receipts
See when your
message has arrived.
FaceTime
Start a video call
right in Messages.
*Requires FaceTime-enabled device for both caller and recipient. Not available in all areas.
Full-screen view
Click the full-screen button
to go full screen.
Always up to date
Updates to your purchased
apps and OS X appear
automatically.
Discover new apps
Browse thousands of
apps and download them
straight to Launchpad.
Calendar view
Select the view you
prefer—day, week,
month, or year.
Add an event
Double-click in a
calendar to create
a new event.
Cocoa Drawing GuideContents
Introduction to Cocoa Drawing Guide 10
At a Glance 10
See Also 11
Overview of Cocoa Drawing 12
Cocoa Drawing Support 12
The Painter’s Model 13
The Drawing Environment 14
The Graphics Context 14
The Graphics State 15
The Coordinate System 16
Transforms 16
Color and Color Spaces 17
Basic Drawing Elements 17
Geometry Support 17
Shape Primitives 18
Images 19
Gradients 20
Text 20
Views and Drawing 21
Common Drawing Tasks 22
Graphics Contexts 24
Graphics Context Basics 24
The Current Context 25
Graphics State Information 27
Screen Canvases and Print Canvases 29
Graphics Contexts and Quartz 30
Modifying the Current Graphics State 30
Setting Colors and Patterns 31
Setting Path Attributes 31
Setting Text Attributes 32
Setting Compositing Options 32
Setting the Clipping Region 35
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
2Setting the Anti-aliasing Options 37
Creating Graphics Contexts 38
Creating a Screen-Based Context 39
Creating a PDF or PostScript Context 39
Threading and Graphics Contexts 40
Coordinate Systems and Transforms 41
Coordinate Systems Basics 41
Local Coordinate Systems 41
Points Versus Pixels 43
Resolution-Independent User Interface 44
Transform Basics 45
The Identity Transform 45
Transformation Operations 46
Transformation Ordering 48
Transform Mathematics 50
Using Transforms in Your Code 51
Creating and Applying a Transform 51
Undoing a Transformation 52
Transforming Coordinates 53
Converting from Window to View Coordinates 53
Flipped Coordinate Systems 55
Configuring Your View to Use Flipped Coordinates 56
Drawing Content in a Flipped Coordinate System 56
Creating a Flip Transform 59
Cocoa Use of Flipped Coordinates 60
Doing Pixel-Exact Drawing 61
Tips for Resolution Independent Drawing in Cocoa 62
Accessing the Current Scale Factor 62
Adjusting the Layout of Your Content 63
Converting Coordinate Values 64
Color and Transparency 65
About Color and Transparency 65
Color Models and Color Spaces 65
Color Objects 66
Color Component Values 66
Transparency 66
Pattern Colors 67
Color Lists 68
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
3
ContentsColor Matching 68
Creating Colors 68
Working with Colors 69
Applying Colors to Drawn Content 69
Applying Color to Text 70
Getting the Components of a Color 70
Choosing Colors 71
Working with Color Spaces 71
Converting Between Color Spaces 71
Mapping Physical Colors to a Color Space 72
Images 74
Image Basics 75
Image Representations 75
Images and Caching 77
Image Size and Resolution 80
Image Coordinate Systems 81
Drawing Versus Compositing 82
Supported Image File Formats 83
Basic Formats 83
TIFF Compression 84
Support for Other File Formats 84
Guidelines for Using Images 86
Creating NSImage Objects 87
Loading an Existing Image 87
Loading a Named Image 87
Drawing to an Image by Locking Focus 88
Drawing Offscreen Images Using a Block-Based Drawing Method to Support High Resolution Displays
89
Creating a Bitmap 89
Creating a PDF or EPS Image Representation 93
Using a Quartz Image to Create an NSImage 95
Working with Images 95
Drawing Images into a View 95
Drawing Resizable Textures Using Images 96
Creating an OpenGL Texture 98
Applying Core Image Filters 100
Getting and Setting Bitmap Properties 100
Converting a Bitmap to a Different Format 100
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
4
ContentsAssociating a Custom Color Profile With an Image 101
Converting Between Color Spaces 102
Premultiplying Alpha Values for Bitmaps 108
Creating New Image Representation Classes 109
Advanced Drawing Techniques 111
Adding Shadows to Drawn Paths 111
Creating Gradient Fills 113
Using the NSGradient Class 114
Using Quartz Shadings in Cocoa 118
Drawing to the Screen 119
Capturing the Screen 119
Full-Screen Drawing in OpenGL 120
Full-Screen Drawing in Cocoa 121
Disabling Screen Updates 124
Using NSTimer for Animated Content 124
Using Cocoa Animation Objects 125
Optimizing Your Drawing Code 125
Draw Minimally 125
Avoid Forcing Synchronous Updates 125
Reuse Your Objects 126
Minimize State Changes 126
Text 127
Text Attributes 127
Simple Text Drawing 128
Advanced Text Drawing 128
Paths 130
Path Building Blocks 130
The NSBezierPath Class 131
Path Elements 131
Subpaths 133
Path Attributes 133
Winding Rules 141
Manipulating Geometric Types 142
Drawing Fundamental Shapes 144
Adding Points 144
Adding Lines and Polygons 145
Adding Rectangles 146
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
5
ContentsAdding Rounded Rectangles 146
Adding Ovals and Circles 147
Adding Arcs 148
Adding Bezier Curves 151
Adding Text 151
Drawing the Shapes in a Path 152
Drawing Rectangles 152
Working with Paths 154
Building Paths 154
Improving Rendering Performance 154
Manipulating Individual Path Elements 156
Transforming a Path 157
Creating a CGPathRef From an NSBezierPath Object 157
Detecting Mouse Hits on a Path 160
Incorporating Other Drawing Technologies 162
Using Quartz in Your Application 162
Using Quartz Features 162
Graphics Type Conversions 163
Getting a Quartz Graphics Context 164
Creating a Cocoa Graphics Context Using Quartz 165
Modifying the Graphics State 165
Using OpenGL in Your Application 165
Using NSOpenGLView 165
Creating an OpenGL Graphics Context 166
Using QuickTime in Your Application 167
Using the QuickTime Kit 168
Using QuickTime C-Based Functions 168
Using Quartz Composer Compositions 168
Choosing the Right Imaging Technology 169
Document Revision History 170
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
6
ContentsFigures, Tables, and Listings
Overview of Cocoa Drawing 12
Figure 1-1 The painter’s model 14
Figure 1-2 Examples of shape primitives 18
Figure 1-3 Examples of bitmap images 19
Figure 1-4 Examples of text 20
Table 1-1 Primitive data types 17
Table 1-2 Common tasks and solutions 22
Graphics Contexts 24
Figure 2-1 Compositing operations in Cocoa 33
Figure 2-2 Clipping paths and winding rules 36
Figure 2-3 A comparison of aliased and anti-aliased content 38
Table 2-1 Graphics state information 27
Table 2-2 Mathematical equations for compositing colors 34
Coordinate Systems and Transforms 41
Figure 3-1 Screen, window, and view coordinate systems on the screen 42
Figure 3-2 Translating content 46
Figure 3-3 Scaling content 47
Figure 3-4 Rotated content 48
Figure 3-5 Transform ordering 49
Figure 3-6 Basic transformation matrix 50
Figure 3-7 Mathematical conversion of coordinates 50
Figure 3-8 Normal and flipped coordinate axes 55
Figure 3-9 Compositing an image to a flipped view 58
Listing 3-1 Flipping the coordinate system manually 60
Color and Transparency 65
Figure 4-1 Drawing with a pattern 67
Table 4-1 Methods for changing color attributes 69
Table 4-2 Quartz rendering intents 72
Images 74
Figure 5-1 Image orientation in an unflipped view 82
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
7Figure 5-2 Drawing a three-part image 97
Figure 5-3 Drawing a nine-part image 97
Table 5-1 Image representation classes 76
Table 5-2 Image caching modes 78
Table 5-3 Implied cache settings 78
Table 5-4 Image interpolation constants 80
Table 5-5 Cocoa supported file formats 83
Table 5-6 TIFF compression settings 84
Table 5-7 Additional formats supported by Cocoa 85
Listing 5-1 Drawing to an image 88
Listing 5-2 Capturing the contents of an existing image 91
Listing 5-3 Drawing to an offscreen window 92
Listing 5-4 Drawing directly to a bitmap 93
Listing 5-5 Creating PDF data from a view 94
Listing 5-6 Creating an OpenGL texture from an image 98
Listing 5-7 Adding a ColorSync profile to an image 101
Listing 5-8 Creating a bitmap with a custom color profile 102
Listing 5-9 Converting a bitmap to a different color space 104
Listing 5-10 Using a CGImageRef object to create an NSImage object 106
Listing 5-11 Creating a color space from a custom color profile 107
Advanced Drawing Techniques 111
Figure 6-1 Shadows cast by rendered paths 111
Figure 6-2 Different types of gradients 114
Figure 6-3 Axial gradient drawn inside a Bezier path 117
Figure 6-4 Gradient created using primitive drawing method 118
Listing 6-1 Adding a shadow to a path 112
Listing 6-2 Clipping an axial gradient to a rounded rectangle 116
Listing 6-3 Drawing a radial gradient using primitive routine 117
Listing 6-4 Creating an OpenGL full-screen context 120
Listing 6-5 Creating a Cocoa full-screen context 122
Paths 130
Figure 8-1 Path elements for a complex path 132
Figure 8-2 Line cap styles 135
Figure 8-3 Line join styles 136
Figure 8-4 Line dash patterns 137
Figure 8-5 Flatness effects on curves 138
Figure 8-6 Miter limit effects 140
Figure 8-7 Applying winding rules to a path 142
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
8
Figures, Tables, and ListingsFigure 8-8 Inscribing the corner of a rounded rectangle 147
Figure 8-9 Creating arcs 149
Figure 8-10 Cubic Bezier curve 151
Figure 8-11 Stroking and filling a path. 152
Table 8-1 Path element commands 131
Table 8-2 Winding rules 141
Table 8-3 Commonly used geometry functions 143
Table 8-4 Rectangle frame and fill functions 153
Listing 8-1 Creating a complex path 133
Listing 8-2 Setting the line width of a path 134
Listing 8-3 Setting the line cap style of a path 136
Listing 8-4 Setting the line join style of a path 137
Listing 8-5 Adding a dash style to a path 137
Listing 8-6 Setting the flatness of a path 139
Listing 8-7 Setting the miter limit for a path 140
Listing 8-8 Drawing a point 144
Listing 8-9 Using lines to draw a polygon 145
Listing 8-10 Drawing a rectangle 146
Listing 8-11 Drawing a rounded rectangle 147
Listing 8-12 Creating three arcs 149
Listing 8-13 Changing the control point of a curve path element 156
Listing 8-14 Creating a CGPathRef from an NSBezierPath 158
Listing 8-15 Detecting hits on a path 160
Incorporating Other Drawing Technologies 162
Table 9-1 Simple data-type conversions 163
Table 9-2 Equivalent Cocoa and Quartz data types 163
Table 9-3 Imaging technologies 169
Listing 9-1 Creating an OpenGL graphics context 166
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
9
Figures, Tables, and ListingsHigh-quality graphics are an important part of a well-designed application. In fact, high-quality graphicsis one
of the things that sets OS X apart from many other operating systems. While some operating systems rely on
flat colors and rectangular objects, OS X uses color, transparency, and its advanced compositing system to give
programs a more fluid and inviting appearance.
At a Glance
This document isintended for developers who are new to drawing custom content using Cocoa. More advanced
Cocoa developers may also want to read this book for tips on how to perform specific tasks.
Before you begin reading this document, you should be familiar with the basic concepts of how to create a
Cocoa application. This includes how to create new projects in Xcode, how to create a simple nib file, and how
to manipulate Cocoa objects. You do not need any understanding of graphics programming in general, although
such knowledge definitely helps.
This document assumesthat you have read Cocoa Fundamentals Guide and are familiar with the basic concepts
for creating a Cocoa application. This book also assumesthat you have a basic understanding of the Objective-C
programming language.
This document has the following chapters:
●
“Overview of Cocoa Drawing” (page 12) introduces drawing-related concepts and the Cocoa support for
drawing.
●
“Graphics Contexts” (page 24) describes the drawing environment and provides examples of how you
configure the environment to suit your needs.
●
“Coordinate Systems and Transforms” (page 41) describes the coordinate systems used for drawing and
provides examples of how you manipulate your content using transforms.
●
“Color and Transparency” (page 65) provides basic information about color and shows you how to use
the color-related Cocoa objects.
●
“Paths” (page 130) describes the basic drawing tools found in Cocoa and provides detailed information
about how to create and manipulate everything from simple shapes to Bezier paths.
●
“Images” (page 74) describes the image classes found in Cocoa and provides examples of how to create
and manipulate images in your application.
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
10
Introduction to Cocoa Drawing Guide●
“Text” (page 127) provides an overview of text and its relationship to the Cocoa drawing environment.
●
“Advanced Drawing Techniques” (page 111) demonstrates some advanced drawing-related techniques,
including full-screen drawing, animation, gradients, and performance tuning.
●
“Incorporating Other Drawing Technologies” (page 162) provides information and examples on how to
integrate advanced technologies, such as Quartz, OpenGL, and QuickTime, into your Cocoa application.
See Also
Drawing is only one step in the process of creating a fully functional Cocoa view. Understanding view hierarchies
and how events interact with views are two other critical steps. For information about these other subjects,
consult the following documents:
● View Programming Guide—for information about creating and managing views
● Cocoa Event Handling Guide—for information about event handling
To ensure the drawing in your app looks great on a Retina display, consult this document:
● High Resolution Guidelines for OS X
Because Cocoa drawing is based on Quartz, many Quartz behaviors (though not all) are also relevant to Cocoa.
This document describes the different behaviors provided by Cocoa, but for additional information about
Quartz behavior, consult the following documents:
● Quartz 2D Programming Guide—for conceptual information related to Quartz.
Introduction to Cocoa Drawing Guide
See Also
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
11Drawing is a fundamental part of most Cocoa applications. If your application uses only standard system
controls, then Cocoa does all of the drawing for you. If you use custom views or controls, though, then it is up
to you to create their appearance using drawing commands.
The following sections provide a quick tour of the drawing-related features available in Cocoa. Subsequent
chapters provide more details about each feature, and also include examples for many common tasks you
might perform during drawing.
Cocoa Drawing Support
The Cocoa drawing environment is available to all applications built on top of the Application Kit framework
(AppKit.framework). This framework defines numerous classes and functions for drawing everything from
primitive shapes to complex images and text. Cocoa drawing also relies on some primitive data types found
in the Foundation framework (Foundation.framework).
The Cocoa drawing environment is compatible with all of the other drawing technologies in OS X, including
Quartz, OpenGL, Core Image, Core Video, Quartz Composer, PDF Kit, and QuickTime. In fact, most Cocoa classes
use Quartz extensively in their implementations to do the actual drawing. In cases where you find Cocoa does
not have the features you need, it is no problem to integrate other technologies where necessary to achieve
the desired effects.
Because it is based on Quartz, the Application Kit framework provides most of the same features found in
Quartz, but in an object-oriented wrapper. Among the features supported directly by the Application Kit are
the following:
● Path-based drawing (also known as vector-based drawing)
●
Image creation, loading and display
● Text layout and display
● PDF creation and display
● Transparency
● Shadows
● Color management
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
12
Overview of Cocoa Drawing● Transforms
● Printing support
● Anti-aliased rendering
● OpenGL support
Like Quartz, the Cocoa drawing environment takes advantage of graphics hardware wherever possible to
accelerate drawing operations. This support is automatic. You do not have to enable it explicitly in your code.
For information about the classes available in Cocoa, see Application Kit Framework Reference and Foundation
Framework Reference . For information on how to integrate C-based technologies into your Cocoa application,
see “Incorporating Other Drawing Technologies” (page 162).
The Painter’s Model
Like Quartz, Cocoa drawing uses the painter’s model for imaging. In the painter’s model, each successive
drawing operation applies a layer of “paint” to an output “canvas.” As new layers of paint are added, previously
painted elements may be obscured (either partially or totally) or modified by the new paint. This model allows
you to construct extremely sophisticated images from a small number of powerful primitives.
Overview of Cocoa Drawing
The Painter’s Model
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
13Figure 1-1 shows how the painter’s model works and demonstrates how important drawing order can be when
rendering content. In the first result, the wireframe shape on the left is drawn first, followed by the solid shape,
obscuring all but the perimeter of the wireframe shape. When the shapes are drawn in the opposite order, the
results are very different. Because the wireframe shape has more holes in it, parts of the solid shape show
through those holes.
Figure 1-1 The painter’s model
The Drawing Environment
The drawing environment encompasses the digital canvas and graphics settings that determine the final look
of your content. The canvas determines where your content is drawn, while the graphics settings control every
aspect of drawing, including the size, color, quality, and orientation of your content.
The Graphics Context
You can think of a graphics context as a drawing destination. A graphics context encapsulates all of the
information needed to draw to an underlying canvas, including the current drawing attributes and a
device-specific representation of the digital paint on the canvas. In Cocoa, graphics contexts are represented
by the NSGraphicsContext class and are used to represent the following drawing destinations:
● Windows (and their views)
●
Images (including bitmaps of all kinds)
Overview of Cocoa Drawing
The Drawing Environment
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
14● Printers
● Files (PDF, EPS)
● OpenGL surfaces
By far, the most common drawing destination is your application's windows, and by extension its views. Cocoa
maintains graphics context objects on a per-window, per-thread basis for your application. This means that
for a given window, there are as many graphics contextsfor that window asthere are threadsin your application.
Although most drawing occurs on your application's main thread, the additional graphics context objects make
it possible to draw from secondary threads as well.
For most other drawing operations, Cocoa creates graphics contexts as needed and configures them before
calling your drawing code. In some cases, actions you take may create a graphics context indirectly. For example,
when creating a PDF file, you might simply request the PDF data for a certain portion of your view object.
Behind the scenes, Cocoa actually creates a graphics context object and calls your view's drawing code to
generate the PDF data.
You can also create graphics contexts explicitly to handle drawing in special situations. For example, one way
to create a bitmap image is to create the bitmap canvas and then create a graphics context that draws directly
to that canvas. There are other waysto create graphics context objects explicitly, although most involve drawing
to the screen or to an image. It is very rare that you would ever create a graphics context object for printing
or generating PDF or EPS data.
For information about graphics contexts, see “Graphics Contexts” (page 24).
The Graphics State
In addition to managing the drawing destination, an NSGraphicsContext object also manages the graphics
state associated with the current drawing destination. The graphics state consists of attributes that affect the
way content is drawn,such asthe line width,stroke color, and fill color. The current graphicsstate can be saved
on a stack that is maintained by the current graphics context object. Any subsequent changes to the graphics
state can then be undone quickly by simply restoring the previous graphics state. This ability to save and
restore the graphics state provides a simple way for your drawing code to return to a known set of attributes.
Cocoa manages some attributes of the graphics state in a slightly different way than Quartz does. For example,
the currentstroke and fill color are set using the NSColor class, and most path-based parameters are set using
the NSBezierPath class. This shift of responsibility reflects the more object-oriented nature of Cocoa.
For more information about the attributes that comprise the current graphics state, and the objects that
manage them, see “Graphics State Information” (page 27).
Overview of Cocoa Drawing
The Drawing Environment
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
15The Coordinate System
The coordinate system supported by Cocoa is identical to the one used in Quartz-based applications. All
coordinates are specified using floating-point valuesinstead of integers. Your code drawsin the user coordinate
space. Your drawing commands are converted to the device coordinate space where they are then rendered
to the target device.
The user coordinate space uses a fixed scale for coordinate values. In this coordinate space, one unit is
effectively equal to 1/72 of an inch. Although it seems like this might imply a 72 dots-per-inch (dpi) resolution
for drawing, it is a mistake to assume that. In fact, the user coordinate space has no inherent notion of pixels
or dpi. The use of floating-point values makes it possible for you to do precise layout in the user coordinate
space and let Cocoa worry about converting your coordinates to the device space.
As the name implies, the device coordinate space refers to the native coordinate space used by the target
device, usually a monitor or printer. Unlike the user coordinate space, whose units are effectively fixed, the
units of the device coordinate space are tied to the resolution of the target device, which can vary. Cocoa
handles the conversion of coordinates from user space to the device space automatically during rendering, so
you rarely need to work with device coordinates directly.
For more information about coordinate systems in Cocoa, see “Coordinate Systems Basics” (page 41).
Transforms
A transform is a mathematical construct used to manipulate coordinatesin two-dimensionalspace. Transforms
are used extensively in graphics-based computing to simplify the drawing process. Coordinate values are
multiplied through the transform's mathematical matrix to obtain a modified coordinate that reflects the
transform's properties.
In Cocoa, the NSAffineTransform class implements the transform behavior. You use this class to apply the
following effects to the current coordinate system:
● Translation
● Scaling
● Rotation
You can combine the preceding effectsin different combinationsto achieve interesting results. During drawing,
Cocoa applies the effects to the content you draw, imparting those characteristics on your shapes and images.
Because all coordinates are multiplied through a transform at some point during rendering, the addition of
these effects has little effect on performance. In fact, manipulating your shapes using transforms is often faster
than manipulating your source data directly.
Overview of Cocoa Drawing
The Drawing Environment
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
16For more information about transforms, including how they affect your content and how you use them, see
“Coordinate Systems and Transforms” (page 41).
Color and Color Spaces
Color is an important part of drawing. Before drawing any element, you must choose the colors to use when
rendering that element. Cocoa provides complete support for specifying color information in any of several
different color spaces. Support is also provided for creating colors found in International Color Consortium
(ICC) and ColorSync profiles.
Transparency is another factor that influencesthe appearance of colors. In OS X, transparency is used to render
realistic-looking content and aesthetically appealing effects. Cocoa providesfullsupport for adding transparency
to colors.
In Cocoa, the NSColor and NSColorSpace classes provide the implementation for color objects and color
space objects. For more information on how to work with colors in Cocoa, see “Color and Transparency” (page
65).
Basic Drawing Elements
The creation of complex graphics often has a simple beginning. In Cocoa, everything you draw is derived from
a set of basic elementsthat you assemble in your drawing code. These elements are fundamental to all drawing
operations and are described in the following sections.
Geometry Support
Cocoa provides its own data structures for manipulating basic geometric information such as points and
rectangles. Cocoa defines the data types listed in Table 1-1. The member fields in each of these data structures
are floating-point values.
Table 1-1 Primitive data types
Type Description
A point data type consists of an x and y value. Pointsspecify the coordinatesfor a rendered
element. For example, you use points to define lines, to specify the start of a rectangle,
to specify the angle of an arc, and so on.
NSPoint
A size data type consists of a width and height field. Sizes are used to specify dimensions
of a target. For example, a size data type specifies the width and height of a rectangle or
ellipse.
NSSize
Overview of Cocoa Drawing
Basic Drawing Elements
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
17Type Description
A rectangle data type is a compound structure composed of an origin point and a size.
The origin field specifiesthe location of the rectangle’s bottom-left corner in the current
coordinate system. The size field specifies the rectangle’s height and width relative to
the origin point and extending up and to the right. (Note, in flipped coordinate spaces,
the origin point is in the upper-left corner and the rectangle’s height and width extend
down and to the right.)
NSRect
For information on how to manipulate point, rectangle, and size data types, see “Manipulating Geometric
Types” (page 142).
Shape Primitives
Cocoa provides support for drawing shape primitives with the NSBezierPath class. You can use this class to
create the following basic shapes, some of which are shown in Figure 1-2.
● Lines
● Rectangles
● Ovals and circles
● Arcs
● Bezier cubic curves
Figure 1-2 Examples of shape primitives
Bezier path objects store vector-based path information, making them compact and resolution independent.
You can create paths with any of the simple shapes or combine the basic shapes together to create more
complex paths. To render those shapes, you set the drawing attributes for the path and then stroke or fill it to
“paint” the path to your view.
Overview of Cocoa Drawing
Basic Drawing Elements
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
18Note: You can also add glyph outlinesto a Bezier path object using the methods of NSBezierPath.
For most text handling, though, you should use the Cocoa text system, which is introduced in
“Text” (page 127).
For more information about drawing shapes, see “Paths” (page 130).
Images
Support for images is provided by the NSImage class and its associated image representation classes
(NSImageRep and subclasses). The NSImage class contains the basic interface for creating and managing
image-related data. The image representation classes provide the infrastructure used by NSImage to manipulate
the underlying image data.
Images can be loaded from existing files or created on the fly. Figure 1-3 shows some bitmap images loaded
from files.
Figure 1-3 Examples of bitmap images
Cocoa supports many different image formats, either directly or indirectly. Some of the formats Cocoa supports
directly include the following:
● Bitmap images, including the following image formats:
● BMP
● GIF
●
JPEG
●
JPEG 2000
Overview of Cocoa Drawing
Basic Drawing Elements
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
19● PNG
● TIFF
●
Images based on Encapsulated PostScript (EPS) data
●
Images based on Portable Document Format (PDF) data
●
Images based on PICT data
● Core Image images
Because they support many types of data, you should not think of image objects strictly as bitmaps. Image
objects can also store path-based drawing commands found in EPS, PDF, and PICT files. They can render data
provided to them by Core Image. They can interpolate image data as needed and render the image at different
resolutions as needed.
For detailed information about Cocoa support for images and the ways to use images in your code, see
“Images” (page 74).
Gradients
In OS X v10.5 and later, you can use the NSGradient class to create gradient fill patterns.
Text
Cocoa provides an advanced text system for drawing everything from simple strings to formatted text flows.
Figure 1-4 shows some basic examples of stylized text that you can create.
Figure 1-4 Examples of text
Overview of Cocoa Drawing
Basic Drawing Elements
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
20Because text layout and rendering using the Cocoa text system is a very complicated process, it is already well
documented elsewhere and is not covered in great detail in this document. For basic information about drawing
text and for links to more advanced text-related documents, see “Text” (page 127).
Views and Drawing
Nearly all drawing in Cocoa is done inside views. Views are objects that represent a visual portion of a window.
Each view object is responsible for displaying some visual content and responding to user events in its visible
area. A view may also be responsible for one or more subviews.
The NSView classisthe base classfor all view-related objects. Cocoa definesseveral types of viewsfor displaying
standard content, including text views, split views, tab views, ruler views, and so on. Cocoa controls are also
based on the NSView class and implement interface elements such as buttons, scrollers, tables, and text fields.
In addition to the standard views and controls, you can also create your own custom views. You create custom
views in cases where the behavior you are looking for is not provided by any of the standard views. Cocoa
notifies your view that it needsto draw itself by sending your view a drawRect: message. Your implementation
of the drawRect: method is where all of your drawing code goes.
Note: Although you can also subclassthe standard views and controlsto implement custom behavior,
it isrecommended that you try to use a delegate object whenever possible instead. If you do subclass
a standard control, avoid changing the appearance of that control. Doing so goes against the guidance
in OS X Human Interface Guidelines.
By default, window updates occur only in response to user actions. This means that your view’s drawRect:
method is called only when something about your view has changed. For example, Cocoa calls the method
when a scrolling action causes a previously hidden part of your view to be exposed. Cocoa also calls it in
response to requests from your own code. If the information displayed by your custom view changes, you
must tell Cocoa explicitly that you want the appropriate parts of your view updated. You do so by invalidating
parts of your view’s visible area. Cocoa collects the invalidated regions together and generates appropriate
drawRect: messages to redraw the content.
Although there are numerous ways to draw, a basic drawRect: method has the following structure:
- (void)drawRect:(NSRect)rect
{
// Draw your content
}
Overview of Cocoa Drawing
Views and Drawing
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
21That's it! By the time your drawRect: method is called, Cocoa has already locked the drawing focus on your
view, saved the graphics state, adjusted the current transform matrix to your view's origin, and adjusted the
clipping rectangle to your view's frame. All you have to do is draw your content.
In reality, your drawRect: method is often much more complicated. Your own method might use several
other objects and methodsto handle the actual drawing. You also might need to save and restore the graphics
state one or more times. Because this single method is used for all of your view's drawing, it also has to handle
several different situations. For example, you might want to do more precise drawing during printing or use
heavily optimized code during a live resizing operation. The options are numerous and covered in more detail
in subsequent chapters.
For additional information about views and live resizing, see View Programming Guide . For more information
about printing in Cocoa, see “Customizing a View’s Drawing for Printing” in Printing Programming Guide for OS X .
Common Drawing Tasks
Table 1-2 lists some of the common tasks related to drawing the content of your view and offers advice on
how to accomplish those tasks.
Table 1-2 Common tasks and solutions
Task How to accomplish
Implement a drawRect: method in your custom view. Use your
implementation of this method to draw content using paths, images, text, or
any other tools available to you in Cocoa, Quartz, or OpenGL.
Draw the content for
a custom view.
Send a setNeedsDisplayInRect: or setNeedsDisplay: message to the
view. Sending either of these messages marks part or all of the view as invalid
and in need of an update. Cocoa responds by sending a drawRect: message
to your view during the next update cycle.
Update a custom
view to reflect
changed content.
Use Core Animation, set up a timer, or use the NSAnimation or
NSViewAnimation classes, to generate notifications at a desired frame rate.
Upon receiving the timer notification, invalidate part or all of your view to
force an update. For information about Core Animation, see Core Animation
Programming Guide . For more information about animating with timers, see
“Using NSTimer for Animated Content” (page 124). For information about using
NSAnimation objects, see “Using Cocoa Animation Objects” (page 125).
Animate some
content in a view.
Overview of Cocoa Drawing
Common Drawing Tasks
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
22Task How to accomplish
Use the inLiveResize method of NSView to determine if a live resize is
happening. If it is, draw as little as possible while ensuring your view has the
look you want. For more information about live resizing optimizations, see
Drawing Performance Guidelines.
Draw during a live
resize.
Use the currentContextDrawingToScreen class method or
isDrawingToScreen instancemethod of NSGraphicsContext to determine
if a print operation is underway. Use the attributes method of
NSGraphicsContext to retrieve (as needed) any additional information about
the current print job. Draw images at the best possible resolution. Adjust your
graphics in any other ways you think are appropriate to achieve the best
possible appearance on the target device. For more information about printing,
see Printing Programming Guide for OS X .
Draw during a
printing operation.
Use the dataWithPDFInsideRect: or dataWithEPSInsideRect:method
to obtain the data. In your drawRect: method use the currentContextDrawingToScreen class method or isDrawingToScreen instance method
of NSGraphicsContext to determine if a print operation is underway.
Create PDF or EPS
data from a view.
Overview of Cocoa Drawing
Common Drawing Tasks
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
23Graphics contexts are a fundamental part of the drawing infrastructure in Cocoa applications. As the name
suggests, a graphics context provides the context for subsequent drawing operations. It identifies the current
drawing destination (screen, printer, file, and so on), the coordinate system and boundaries for the underlying
canvas, and any graphics attributes associated with the destination.
For most of the drawing you do in Cocoa, you never need to create a graphics context yourself. The normal
drawing cycle in Cocoa automatically creates and configures a graphics context for you to use. For some
advanced drawing, however, you may need to create your own graphics context prior to drawing.
In a Cocoa application, graphics contexts for nearly all types of canvas are represented by the
NSGraphicsContext class. You use graphics context objects to manipulate graphics attributes and to get
information about the current drawing environment.
Note: For OpenGL drawing, you use the NSOpenGLContext classinstead of NSGraphicsContext
for the graphics context object. OpenGL drawing, and use of the NSOpenGLContext class, are
covered in “Using OpenGL in Your Application” (page 165).
This chapter provides an overview of Cocoa graphics contexts and how you use them in your application. It
includes information on how to create custom graphics contexts and when it might be appropriate to do so.
Graphics Context Basics
The primary job of any graphics context object isto maintain information about the currentstate of the drawing
environment. In Quartz, the graphics context object is associated with a window, bitmap, PDF file, or other
output device and maintains information for that device. The same is true for a Cocoa graphics context, but
because Cocoa drawing is view-based, some additional changes are made to the drawing environment before
your view’s drawRect: method is called.
By the time your view’s drawRect: method is called, Cocoa has made sure that any drawing calls you make
stay within the confines of your view. It saves the graphics state to simplify the process of undoing its changes
later. It adds an appropriate transform to the current transformation matrix to place the drawing origin at the
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
24
Graphics Contextsorigin of your view. It also sets the clipping region to your view's visible boundaries, preventing any rendered
content from straying into other views. Your view is effectively the star of the show, at least until another view’s
drawRect: method is called.
While the current context is focused on your view, you can draw paths, images, text, or any other content you
want. You can also change the attributes of the current drawing environment to achieve the appearance you
want for your content. Eventually, the content you draw is sent to the Quartz Compositor, where it is combined
with the content from other views in the window and flushed to the screen or output device.
After your drawRect: method returns, Cocoa goesthrough the process of resetting the drawing environment
for the next view. It reverts any changes you made to the drawing environment and sets up the coordinate
transform and clipping region for the next view, giving it its own pristine environment in which to work. This
process then repeats itself during each update cycle in your application.
The Current Context
Each thread in a Cocoa application has its own graphics context object for a given window. You can access
this object from your code using the currentContext method of NSGraphicsContext, as shown in the
following example:
NSGraphicsContext* aContext = [NSGraphicsContext currentContext];
The currentContext method always returns the Cocoa graphics context object that is appropriate for the
current drawing environment. This object keeps track of the current graphics state, lets you save and restore
graphics state information, and lets you modify many graphics state attributes. The changes you make to the
graphics state affect all subsequent drawing calls. If you change an attribute more than once, only the most
recent setting is used.
To save the current graphics state, you use the saveGraphicsState method of NSGraphicsContext. This
method essentially pushes a copy of the current state onto a stack, leaving you free to make changes to the
currentstate. When you want to revert back to the previousstate, you simply call the restoreGraphicsState
method to pop the current graphics state (including all changes since the last save) off of the stack and restore
the previous state.
If you plan to change the current graphics state significantly, it is a good idea to save the current state before
making your changes. Modifying one or two attributes usually may not merit saving the graphics state, since
you can reset or change those individual attributes easily. However, if you are changing more than one or two
attributes, it is usually easier to save and restore the entire graphicsstate. You can call the saveGraphicsState
method as often as needed in your code to save snapshots of the current graphics state, but you must be sure
to balance each call with a matching call to restoreGraphicsState.
Graphics Contexts
Graphics Context Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
25Note: The saveGraphicsState and restoreGraphicsState methods are available both as
class methods and as instance methods. The class method versions simply save and restore the
graphicsstate of the current context. The instance methodslet you save the state of a specific context
object, although in most cases this should be the current context.
The following example shows a simple drawRect: method that iterates over an array of developer-defined
objects, each of which is drawn with a differentset of attributes. The graphicsstate issaved and restored during
each loop iteration, ensuring that each object starts from the same graphics state.
- (void)drawRect:(NSRect)rect
{
NSGraphicsContext* theContext = [NSGraphicsContext currentContext];
int i;
int numObjects = [myObjectArray count];
// Iterate over an array of objects
// Set the attributes for each before drawing
for (i = 0; i < numObjects; i++)
{
[theContext saveGraphicsState];
// Set the drawing attributes
// Draw the object
[theContext restoreGraphicsState];
}
}
Warning: When saving and restoring the graphics state, you must balance all calls to
saveGraphicsState with a corresponding call to restoreGraphicsState. Failure to do so can
result in unexpected changes to the appearance of any windows that use that view.
Graphics Contexts
Graphics Context Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
26Graphics State Information
Each Cocoa graphics context object maintainsinformation about the currentstate of the drawing environment.
This information ranges from the global rendering settings to the attributes used to render the current path
and is the same state information saved by Quartz. Whenever you save the current graphics state, you save a
copy of the settings listed in Table 2-1.
Table 2-1 Graphics state information
Attribute Description
Maps points in the view’s coordinate system to points in the destination device's
coordinate system. Cocoa modifies the CTM before calling your view’s drawRect:
method. You can use an NSAffineTransform object to modify the CTM further
to change the drawing origin, scale the canvas, or rotate the coordinate system.
For more information, see “Coordinate Systems and Transforms” (page 41).
Current
transformation
matrix (CTM)
Specifiesthe area of the canvasthat can be painted by drawing calls. Cocoa modifies
the clipping region to the visible area of your view before calling its drawRect:
method. You can use an NSBezierPath object to further clip the visible area. For
more information, see “Setting the Clipping Region” (page 35).
Clipping area
Specifies the width of paths. The default line width is 1.0 but you can modify this
value using an NSBezierPath object. For more information,see “Line Width” (page
134).
Line width
Specifies how two connected lines are joined together. The default join style is
NSMiterLineJoinStyle but you can modify this value using an NSBezierPath
object. For more information, see “Line Join Styles” (page 136).
Line join style
Specifies the appearance of an open end point on a path. The default line cap style
is NSButtLineCapStyle but you can modify this value using an NSBezierPath
object. For more information, see “Line Cap Styles” (page 135).
Line cap style
Defines a broken pattern for lines, including the initial phase for the style. There is
no default dash style, resulting in solid lines. You modify dash styles for a path
using an NSBezierPath object. For more information, see “Setting Path
Attributes” (page 31).
Line dash style
Determines when lines should be joined with a bevel instead of a miter. Applies
only when the line join style is set to NSMiterLineJoinStyle. The length of the
miter is divided by the line width. If the resulting value is greater than the miter
limit, a bevel is used. The default value is 10.0 but you can modify this value using
an NSBezierPath object. For more information, see “Miter Limits” (page 139).
Line miter limit
Graphics Contexts
Graphics Context Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
27Attribute Description
Specifies the accuracy with which curves are rendered. (It is also the maximum
error tolerance, measured in pixels.) Smaller numbers result in smoother curves at
the expense of more calculations. The interpretation of this value may vary slightly
on different rendering devices. The default value is 0.6 but you can modify this
value using an NSBezierPath object. For more information, see “Line
Flatness” (page 138).
Flatness value
Specifies the color used for rendering paths. This color applies only to the path line
itself, not the area the path encompasses. You can specify colors using any of the
system-supported color spaces. This value includes alpha information. Color
information is managed by the NSColor class. For more information, see “Setting
Colors and Patterns” (page 31).
Stroke color
Specifies the color used to fill the area enclosed by a path. You can specify colors
using any of the system-supported color spaces. This value includes alpha
information. Color information is managed by the NSColor class. For more
information, see “Setting Colors and Patterns” (page 31).
Fill color
Specifies the shadow attributes to apply to rendered content. You set shadows
using the NSShadow class. For more information, see “Adding Shadows to Drawn
Paths” (page 111).
Shadow
Specifies the technique used to map in-gamut colors to the gamut of the current
color space. Cocoa does not support setting this attribute directly. Instead, you
must use Quartz. For more information, see “Mapping Physical Colors to a Color
Space” (page 72).
Rendering intent
Specifies the font to use when drawing text. You modify font information using
the NSFont class. For more information on drawing text,see “Text Attributes” (page
127).
Font name
Specifiesthe fontsize to use when drawing text. You modify font information using
the NSFont class. For more information on drawing text,see “Text Attributes” (page
127).
Font size
Specifiesthe characterspacing to use when drawing text. (This attribute issupported
only indirectly by Cocoa.) For more information on drawing text, see “Text
Attributes” (page 127).
Font character
spacing
Specifies how to render the text. (This attribute is supported only indirectly by
Cocoa.) For more information on drawing text, see “Text Attributes” (page 127).
Text drawing
mode
Specifies the process used to interpolate images during rendering. You use the
NSGraphicsContext class to change this setting. For more information, see
“Image Size and Resolution” (page 80)
Image
interpolation
quality
Graphics Contexts
Graphics Context Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
28Attribute Description
Specifies the process used to composite source and destination material together.
(The compositing operations supported by Cocoa are related to the Quartz blend
modes but differ in their usage and behavior.) You use the NSGraphicsContext
classto set the default value for thissetting. Some rendering methods and functions
may let you specify a different option. For more information, see “Setting
Compositing Options” (page 32).
Compositing
operation
Specifies a global alpha (transparency) value to apply in addition to the alpha value
for a given color. Cocoa does not support this attribute directly. If you want to set
it, you must use the CGContextSetAlpha function in Quartz.
Global alpha
Specifies whether paths use aliasing to smooth lines asthey cross pixel boundaries.
You use the NSGraphicsContext class to change this setting. For more
information, see “Setting the Anti-aliasing Options” (page 37).
Anti-aliasing
setting
Note: The winding rule used to fill paths is not stored as part of the current graphics state. You can
set a default winding rule for NSBezierPath objects but doing so affects content rendered using
those objects. For more information, see “Winding Rules” (page 141).
Screen Canvases and Print Canvases
In a broad sense, Cocoa graphics context objects serve two types of canvases: screen-based canvases and
print-based canvases. A screen-based graphics context renders content to a window, view, or image with the
results usually appearing on a screen. A print-based graphics context is used to render content to a printer
spool file, PDF file, PostScript file, EPS file, or other medium usually associated with the printing system.
For nearly all screen-based and print-based drawing, Cocoa provides an appropriate graphics context object
automatically. Cocoa provides a graphics context object during all view updates and in response to the user
printing a document. There are situations, however, where you must create a graphics context object manually,
including the following:
● Using OpenGL commands to render your view content
● Drawing to an offscreen bitmap
● Creating PDF or EPS data
●
Initiating a print job programmatically
Using the class methods of NSGraphicsContext, you can create graphics context objects for drawing to
screen-based canvases. You cannot use these methods for print-based canvas, however. Cocoa routes all
printing operations through the Cocoa printing system, which handles the task of setting up the graphics
Graphics Contexts
Graphics Context Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
29context object for you. This means that if you want to generate PDF data, EPS data, or print to a printer, you
must use the methods of the NSPrintOperation class to create a print job for your target. It also means that
your views should provide some minimal printing support if you want to produce well-formatted output for
print-based canvases.
Note: Although Cocoa does provide some support for creating OpenGL graphics contexts
automatically, the default pixel format options are usually limited. In most cases, you will want to
create a custom OpenGL graphics context with the pixel format options you need for drawing. For
more information, see “Creating an OpenGL Graphics Context” (page 166).
You can determine the type of canvas being managed by the current graphics context using the
isDrawingToScreen instance method or currentContextDrawingToScreen class method of
NSGraphicsContext. For print-based canvases, you can use the attributes method to get additional
information about the canvas, such as whether it is being used to generate a PDF or EPS file.
For more information about obtaining contexts for both screen-based and print-based canvases, see “Creating
Graphics Contexts” (page 38).
Graphics Contexts and Quartz
The NSGraphicsContext class in Cocoa is a wrapper for a Quartz graphics context (CGContextRef data
type). Both types manage the same basic information, and in fact, many methods of NSGraphicsContext
simply call their Quartz equivalents. This relationship makes it easy to perform any Quartz-related drawing in
your application. It also means that any time you have a Cocoa graphics context (an instance of the
NSGraphicsContext class), you have a Quartz graphics context as well.
For information on how to use Cocoa graphics contexts to call Quartz functions, see “Using Quartz in Your
Application” (page 162).
Modifying the Current Graphics State
In your view’s drawRect: method, one of the first things you may want to do is modify the current drawing
environment. For example, you might want to configure the current drawing colors, modifying the clipping
region, transform the coordinate system, and so on. Many attributes can be set directly using the methods of
NSGraphicsContext but some require the use of other objects. The following sections list the available
drawing attributes and how you modify them.
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
30Important: Saving and restoring the current graphics state is a relatively expensive operation that should
done as little as possible. In general, you should try to save and restore the graphics state only to undo
several changes at once or when there is no alternative, such as to reset the clipping path. For individual
changes, setting a new value directly is often more efficient than saving and restoring the entire graphics
state.
Setting Colors and Patterns
Cocoa providessupport for colorsin a variety of different colorspaces. The NSColor classsupports RGB, CMYK,
and grayscale color spaces by default but can also support custom color spaces defined by ICC and ColorSync
profiles. The colors you specify include the color channels appropriate for the color space and an optional
alpha component to define the transparency of the color.
To set the currentstroke or fill attributes, create an NSColor object and send it a set, setStroke, or setFill
message. The stroke and fill attributes define the color or pattern for paths and the areas they enclose. The
currentstroke and fill colors affect all drawn content except text, which requiresthe application of text attributes;
see “Applying Color to Text” (page 70).
For more information about colors and how to create them, see “Color and Transparency” (page 65).
Setting Path Attributes
To modify the value of path attributes, you use the NSBezierPath class. Using the methods of this class, you
can set the line width, line join style, line dash style, line cap style, miter limit, flatness, and winding rule
attributes. All of these attributes affect the way paths are rendered by Cocoa.
Path attributes come in two flavors: global and path-specific. When you use the class methodsin NSBezierPath
to set the "default" value for an attribute, you are setting the global attribute. Global attributes are global to
path objects (as opposed to the graphics state), so setting a global attribute affects all paths you render using
the NSBezierPath class, but does not affect Quartz-based paths. To override a global attribute for an individual
path object, you should set a path-specific value. For example, to set the global line width, you use the
setDefaultLineWidth: class method of NSBezierPath. To set the line width for a specific NSBezierPath
object, you use its setLineWidth: instance method.
For information on how to set both default and path-specific attributes, and to see the resulting appearance
of rendered content, see “Path Attributes” (page 133).
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
31Setting Text Attributes
For most string-based drawing in Cocoa, you apply text attributes directly to the strings, rather than relying
on the global font settings. The Cocoa string objects and the Cocoa text system both support the use of
attributesfor modifying the appearance ofstring. For NSAttributedString objects, you apply the attributes
directly to character ranges in the string. For regular NSString objects, you apply the attributes to the entire
string when you draw it.
If you want to set the global fontsettingsstored in the graphicsstate, perhapsfor drawing strings using Quartz,
you can use the NSFont object to set the font family and size. After creating a font object, you use its set
method to apply the font information to the current graphics state.
For more information about drawing options for text, see “Text” (page 127). For more information about the
Cocoa text system, see Cocoa Text Architecture Guide .
Setting Compositing Options
When you render each visual element, you need to decide how that element interacts with any surrounding
content. You might want the element to be layered on top of or behind the current content or be merged
with it in interesting ways. You specify this behavior using different compositing options.
Compositing options specify how the colors in source content are blended with the existing content in the
drawing destination. With fully opaque colors, most compositing optionssimply mask or overlay different parts
of the source and destination content. With partially transparent colors, however, you can achieve interesting
blending effects.
The Cocoa compositing options differ from the blend modes used in Quartz, although the two perform basically
the same task. The Cocoa options are inherited from the NextStep environment, whereas the Quartz blend
modes are part of the newer PDF-based rendering model. Despite their historical legacy, the Cocoa options
are still a very powerful way to composite content, and may even be a little easier to understand than their
Quartz counterparts.
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
32Important: Despite their similarities, there is no direct mapping between the Cocoa compositing options
and the Quartz blend modes. In addition, when drawing to a print-based canvas, you should use only the
NSCompositeCopy or the NSCompositeSourceOver operators. (For PDF content, you should use only
the NSCompositeSourceOver operator or the Quartz blend modes.) If you need to use any other
compositing operators, you should render your content to an image and then draw the image to the printing
context using one of the supported operators. If your application relies heavily on PDF blend modes, you
may want to use Quartz for your drawing instead.
Figure 2-1 shows the Cocoa compositing options and how they affect rendered content. At the top of the
figure are the source and destination content being rendered. The veins of the leaf are completely transparent
while the rest of the leaf is opaque. In the destination image, the color is rendered at partial opacity. Below
that are the results for each of the supported compositing operations.
Figure 2-1 Compositing operations in Cocoa
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
33Table 2-2 lists the mathematical equations used to compute pixel colors during compositing operations. In
each equation, R is the resulting (premultiplied) color, S is the source color, D is the destination color, Sa is the
alpha value of the source color, and Da is the alpha value of the destination color. All color component values
and alpha values are in the range 0 to 1 for these computations.
Table 2-2 Mathematical equations for compositing colors
Para Para
NSCompositeClear R = 0
NSCompositeCopy R = S
NSCompositeSourceOver R = S + D*(1 - Sa)
NSCompositeSourceIn R = S*Da
NSCompositeSourceOut R = S*(1 - Da)
NSCompositeSourceAtop R = S*Da + D*(1 - Sa)
NSCompositeDestinationOver R = S*(1 - Da) + D
NSCompositeDestinationIn R = D*Sa
NSCompositeDestinationOut R = D*(1 - Sa)
NSCompositeDestinationAtop R = S*(1 - Da) + D*Sa
NSCompositeXOR R = S*(1 - Da) + D*(1 - Sa)
NSCompositePlusDarker R = MAX(0, (1 - D) + (1 - S))
NSCompositePlusLighter R = MIN(1, S + D)
To set the current compositing operation, you use the setCompositingOperation: method of
NSGraphicsContext. This sets the global compositing option to use if no other operator is specified. The
default compositing option is NSCompositeSourceOver.
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
34Setting the Clipping Region
The clipping region is a useful way to limit drawing to a specific portion of your view. Instead of creating
complex graphics offscreen and then compositing them precisely in your view, you can use a clipping region
to mask out the portions of your view you do not want modified. For example, you might use a clipping region
to prevent drawing commands from drawing over some already rendered content. Similarly, you might use a
clipping region to cut out specific portions of an image you want to render.
Before invoking your view’s drawRect: method, Cocoa configures the clipping region of the current graphics
context to match the visible area of your view. This prevents your view's drawing code from rendering content
outside of your view's boundaries, possibly on top of other views.
You can restrict the drawable region of your view even further by adding shapesto the current clipping region.
Whenever you add a new shape to the current clipping region, Cocoa determinesthe intersection of the shape
with the current clipping region and uses the result as the new clipping region. This behavior means that you
should generally add only one shape to the clip region before doing your drawing. The shape you add can be
a single rectangle, multiple rectangles, or a combination of multiple complex subpathsin a single NSBezierPath
object.
For simple rectangular shapes, the easiest way to clip is using the NSRectClip function. To specify multiple
rectangular regions, use the NSRectClipList function instead. To clip your view to a nonrectangular region,
you must use an NSBezierPath object. The path you create can be arbitrarily complex and include multiple
rectangular and nonrectangular regions. Once you have the path you want, use the object’s addClip method
to add the resulting shape to the current clipping region. (For information on how to create paths,see “Drawing
Fundamental Shapes” (page 144).)
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
35Figure 2-2 shows the effects of applying a clipping path to an image. The top images show the image to be
clipped and the path to use for the clip shape, which in this case consists of two shapes inside a single
NSBezierPath object. Although the clip shape is the same in both cases, the resulting clip region is different.
This is because clipping takes into account the current winding rule when calculating the clipping region.
Figure 2-2 Clipping paths and winding rules
The following example shows you how to create the clip region shown in Figure 2-2. The clip region is composed
of an overlapping square and circle, so you simply add a rectangle and oval with the appropriate sizes to a
Bezier path object and call the addClip method.
// If you plan to do more drawing later, it's a good idea
// to save the graphics state before clipping.
[NSGraphicsContext saveGraphicsState];
// Create the path and add the shapes
NSBezierPath* clipPath = [NSBezierPath bezierPath];
[clipPath appendBezierPathWithRect:NSMakeRect(0.0, 0.0, 100.0, 100.0)];
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
36[clipPath appendBezierPathWithOvalInRect:NSMakeRect(50.0, 50.0, 100.0, 100.0)];
// Add the path to the clip shape.
[clipPath addClip];
// Draw the image.
[NSGraphicsContext restoreGraphicsState];
Warning: Although you can also use the setClip method of NSBezierPath to modify the clipping
region, doing so is not recommended. The setClip method replaces the entire clipping region with
the area you specify. If the new clipping region extends beyond the bounds of your view, this could
lead to portions of your content spilling over into neighboring views.
Setting the Anti-aliasing Options
Cocoa graphics contextssupport anti-aliasing in the same way that their Quartz counterparts do. Anti-aliasing
is the process of artificially correcting the jagged (or aliased) edges surrounding text or shapes in bitmap
images. These jagged edges occur primarily in lower-resolution bitmaps where it is easier to see individual
pixels. To remove the jagged edges, Cocoa uses different colors for the pixels that surround a shape’s outline.
Graphics Contexts
Modifying the Current Graphics State
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
37The colors it uses are a blend of the original pixel color and the color of the shape’s outline. By blending colors
in this way, the edges of the shape appear much smoother. Figure 2-3 shows the same image aliased and
anti-aliased.
Figure 2-3 A comparison of aliased and anti-aliased content
To enable or disable anti-aliasing, use the setShouldAntialias: method of NSGraphicsContext. Even
with anti-aliasing disabled, it may still appears as if Cocoa is drawing content using aliasing. When drawing
content on non-pixel boundaries, Cocoa may opt to split the line over multiple pixels, which can give the
impression of aliasing. For more information about how to avoid this situation, see “Doing Pixel-Exact
Drawing” (page 61).
Creating Graphics Contexts
The type of drawing you do in your application will determine whether you need to create any graphics context
objects explicitly orsimply use the one Cocoa provides you. If all you do is draw in your views, you can probably
just use the Cocoa-provided context. This is true both for screen-based and print-based drawing. If your
application performs any other type of drawing, however, you may need to create a graphics context yourself.
The following sections provide information on how and when to create Cocoa graphics contexts for your
content.
Graphics Contexts
Creating Graphics Contexts
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
38Creating a Screen-Based Context
If you want to do any drawing outside of the normal update cycle of your view, you must create a graphics
context object explicitly. You might use this technique to draw in an offscreen window or bitmap and then
copy the resulting bits elsewhere. You could also use it to draw to a window from a secondary thread. The
NSGraphicsContext classincludes methodsfor creating new graphics context objectsspecifically for windows
and bitmap images.
To draw to a window, you can use the graphicsContextWithWindow: method of NSGraphicsContext.
The context you get back is initialized to the window itself, and not to a specific view. In fact, you may not
want to use this technique if the window contains many subviews. In order to draw the views properly, you
would need to walk the list of subviews manually and configure the drawing environment for each one, which
is not recommended. Instead, you would use this technique for drawing to an offscreen buffer.
Important: Because most OS X windows are already double-buffered, do not use offscreen windows or
bitmaps simply to update the contents of a window. Doing so wastes memory (by adding a third buffer)
and requires an extra copy operation to transfer the bits from the offscreen window to the window buffer.
To draw to a bitmap, you have two options. If your code runs in OS X v10.4 and later, you can use the
graphicsContextWithBitmapImageRep: method to create a context object focused on an
NSBitmapImageRep object. The drawing you do is then rendered directly to the bitmap. If your code must
run on earlier versions of OS X, you must either lock focus on a view or use an offscreen window and then
capture the contents of the view or window. For information and examples on how to create bitmaps, see
“Creating a Bitmap” (page 89)
Creating a PDF or PostScript Context
Unlike screen-based contexts, if you want to create a graphics context for a PDF, EPS, or print-based canvas,
you do not do so directly. All print-based operations must go through the Cocoa printing system, which handles
the work required for setting up the printed pages and running the print job.
The simplest way to create a PDF or EPS file is to use the dataWithPDFInsideRect: and
dataWithEPSInsideRect: methods of NSView. These methods configure a print job automatically and use
your view's existing drawing code to generate the PDF or EPS data. For more information and an example of
how to use these methods, see “Creating a PDF or EPS Image Representation” (page 93).
To create a print job manually, you use the NSPrintOperation class. This class offers several class methods
for creating print jobs for a particular view and outputting the job to a printer, PDF file, or EPS file. Once you
have an instance of the NSPrintOperation class, you can set the print information and use the runOperation
method to start the print job, at which point Cocoa takes over.
Graphics Contexts
Creating Graphics Contexts
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
39Important: You cannot create a viable graphics context for PDF or PostScript canvases using the
graphicsContextWithAttributes: method. You must go through the Cocoa Printing system instead.
During the execution of a print job, Cocoa calls several methods of your view to handle page layout and
drawing. These methods are called for all printing paths, so implementing them for printing will also support
PDF and EPS. For information on how to implement these methods, see Printing Programming Guide for OS X .
Threading and Graphics Contexts
The Application Kit maintains a unique graphics context for each window and thread combination. Because
each thread has its own graphics context object for a given window, it is possible to use secondary threads to
draw to that window. There are some caveats, however.
During the normal update cycle for windows, all drawing requests are sent to your application’s main thread
for processing. The normal update cycle happens when a user event triggers a change in your user interface.
In this situation, you would call the setNeedsDisplay: or setNeedsDisplayInRect: method (or the
display family of methods) from your application’s main thread to invalidate the portions of your view that
require redrawing. You should not call these methods from any secondary threads.
If you want to update a window or view from a secondary thread, you must manually lock focus on the window
or view and initiate drawing yourself. Locking focus configures the drawing environment for that window's
graphics context. Once locked, you can configure the drawing environment, issue your drawing commands
as usual, and then flush the contents of the graphics context to the window buffer.
In order to draw regularly on a secondary thread, you must notify the thread yourself. The simplest way to
send regular notifications is using an NSTimer or NSAnimation object. For more information on how to
animate content, see “Advanced Drawing Techniques” (page 111).
Creating bitmaps on secondary threads is one way to thread your drawing code. Because bitmaps are
self-contained entities, they can be created safely on secondary threads. From your thread, you would need
to create the graphics context object explicitly (as described in “Creating a Screen-Based Context” (page 39))
and then issue drawing calls to draw into the bitmap buffer. For more information on how to create bitmaps,
including sample code, see “Creating a Bitmap” (page 89).
Important: Although drawing on secondary threads is allowed, you should always handle events and
other user-requested actions from your application’s main thread only. Using multiple threads to handle
events can lead to processing those events out of sequence, which can cause inconsistencies in your
application’s behavior.
Graphics Contexts
Threading and Graphics Contexts
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
40Coordinate spaces simplify the drawing code required to create complex interfaces. In a standard Mac app,
the window represents the base coordinate system for drawing, and all content must eventually be specified
in that coordinate space when it is sent to the window server. For even simple interfaces, however, it is rarely
convenient to specify coordinates relative to the window origin. Even the location of fixed items can change
and require recalculation when the window resizes. This is where Cocoa makes things simple.
Each Cocoa view you add to a window maintains its own local coordinate system for drawing. Rather than
convert coordinate valuesto window coordinates, you simply draw using the local coordinate system, ignoring
any changes to the position of the view. Before sending your drawing commands to the window server, Cocoa
automatically corrects coordinate values and puts them in the base coordinate space.
Even with the presence of local coordinate spaces, it is often necessary to change the coordinate space
temporarily to affect certain behaviors. Changing the coordinate space is done using mathematical
transformations (also known as transforms). Transforms convert coordinate values from one coordinate space
to another. You can use transforms to alter the coordinate system of a view in a way that affects subsequent
rendering calls, or you can use them to determine the location of points in the window or another view.
The following sections provide information about how Cocoa manages the local coordinate systems of your
views and how you can use transforms to affect your drawing environment.
Coordinate Systems Basics
Cocoa and Quartz use the same base coordinate system model. Before you can draw effectively, you need to
understand this coordinate space and how it affects your drawing commands. It also helps to know the ways
in which you can modify the coordinate space to simplify your drawing code.
Local Coordinate Systems
Cocoa uses a Cartesian coordinate system asits basic model forspecifying coordinates. The origin in thissystem
is located in the lower-left corner of the current drawing space, with positive values extending along the axes
up and to the right of the origin point. The root origin for the entire system is located in the lower-left corner
of the screen containing the menu bar.
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
41
Coordinate Systems and TransformsIf you were forced to draw all your content in screen coordinates—the coordinate system whose origin is
located at the lower-left corner of the computer’s primary screen—your code would be quite complex. To
simplify things, Cocoa sets up a local coordinate system whose origin is equal to the origin of the window or
view that is about to draw. Subsequent drawing calls inside the window or view take place relative to this local
coordinate system. Once the code finishes drawing, Cocoa and the underlying graphics system convert
coordinates in the local coordinates back to screen coordinates so that the content can be composited with
content from other applications and sent to the graphics hardware.
Note: If a computer has multiple monitors attached, those monitors can be set to mirror each other
or to display one contiguous desktop. In mirroring mode, every screen has an origin of (0, 0). In
contiguous mode, one screen has an origin of (0, 0) but other screens have origins that are offset
from that of the first screen.
Figure 3-1 shows the coordinate-system origin points of the screen, a window, and a view. In each case, the
value to the bottom-left of each point is the coordinate measured in its parent coordinate system. (The screen
does not have a parent coordinate system, so both coordinate values are 0). The window’s parent is the screen
and the view’s parent is the window.
Figure 3-1 Screen, window, and view coordinate systems on the screen
Coordinate Systems and Transforms
Coordinate Systems Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
42Mapping from screen coordinatesto local window or view coordinatestakes place in the current transformation
matrix (CTM) of the Cocoa graphics context object. Cocoa applies the CTM automatically to any drawing calls
you make,so you do not need to convert coordinate values yourself. You can modify the CTM though to change
the position and orientation of the coordinate axesinside your view. (For more information,see “Transformation
Operations” (page 46).)
Points Versus Pixels
The drawing system inOS X is based on a PDF drawing model, which is a vector-based drawing model. Compared
to a raster-based drawing model, where drawing commands operate on individual pixels, drawing commands
in OS X are specified using a fixed-scale drawing space, known as the user coordinate space. The system then
maps the coordinates in this drawing space onto the actual pixels of the corresponding target device, such as
a monitor or printer. The advantage of this model is that graphics drawn using vector commands scale nicely
to any resolution device. As the device resolution increases, the system is able to use any extra pixels to create
a crisper look to the graphics.
In order to maintain the precision inherent with a vector-based drawing system, drawing coordinates are
specified using floating-point values instead of integers. The use of floating-point values for OS X coordinates
makes it possible for you to specify the location of your program's content very precisely. For the most part,
you do not have to worry about how those values are eventually mapped to the screen or other output device.
Instead, Cocoa takes care of this mapping for you.
Even though the drawing model is based on PDF, there are still times when you need to render pixel-based
content. Bitmap images are a common way to create user interfaces, and your drawing code may need to
make special adjustmentsto ensure that any bitmap images are drawn correctly on different resolution devices.
Similarly, you may want to ensure that even your vector-based graphics align properly along pixel boundaries
so that they do not have an anti-aliased appearance. OS X provides numerous facilities to help you draw
pixel-based content the way you want it.
The following sections provide more detail about the coordinate spaces used for drawing and rendering
content. There also follows some tips on how to deal with pixel-specific rendering in your drawing code.
User Space
The user coordinate space in Cocoa is the environment you use for all your drawing commands. It represents
a fixed scale coordinate space, which means that the drawing commands you issue in this space result in
graphics whose size is consistent regardless of the resolution of the underlying device.
Units in the user space are based on the printer's point, which was used in the publishing industry to measure
the size of content on the printed page. A single point is equivalent to 1/72 of an inch. Points were adopted
by earlier versions of Mac OS as the standard resolution for content on the screen. OS X continues to use the
same effective “resolution” for user-space drawing.
Coordinate Systems and Transforms
Coordinate Systems Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
43Although a single point often corresponded directly to a pixel in the past, in OS X, that may not be the case.
Points are not tied to the resolution of any particular device. If you draw a rectangle whose width and height
are exactly three points, that does not mean it will be rendered on the screen as a three-pixel by three-pixel
rectangle. On a 144 dpi screen, the rectangle might be rendered using six pixels per side, and on a 600-dpi
printer, the rectangle would require 25 pixels per side. The actual translation from points to pixels is device
dependent and handled for you automatically by OS X.
For all practical purposes, the user coordinate space is the only coordinate space you need to think about.
There are some exceptions to this rule, however, and those are covered in “Doing Pixel-Exact Drawing” (page
61).
Device Space
The device coordinate space refers to the native coordinate space used by the target device, whether it be a
screen, printer, file, or some other device. Units in the device coordinate space are specified using pixels and
the resolution of this space is device dependent. For example, most monitors have resolutions in the 100 dpi
range but printers may have resolutions exceeding 600 dpi. There are some devices that do not have a fixed
resolution, however. For example, PDF and EPS files are resolution independent and can scale their content
to any resolution.
For Cocoa users, the device coordinate space is something you rarely have to worry about. Whenever you
generate drawing commands, you always specify positions using user space coordinates. The only time that
you might need to know about device space coordinates is when you are adjusting your drawn content to
map more cleanly to a specific target device. For example, you might use device coordinates to align a path
or image to specific pixel boundaries in order to prevent unwanted anti-aliasing. In such a situation, you can
adjust your user space coordinates based on the resolution of the underlying device. For information on how
to do this, see “Doing Pixel-Exact Drawing” (page 61)
Resolution-Independent User Interface
In OS X v10.4 and earlier, Quartz and Cocoa always treated screen devices as if their resolution were always 72
dpi, regardless of their actual resolution. This meant that for screen-based drawing, one point in user space
was always equal to one pixel in device space. As screens advanced well past 100 dpi in resolution, the
assumption that one point equaled one pixel began to cause problems. Most noticeably, everything became
much smaller. In OS X v10.4, the first steps at decoupling the point-pixel relationship took place.
In OS X v10.4, support was added for resolution independence in application user interfaces. The initial
implementation of this feature provides a way for you to decouple your application’s user space from the
underlying device space manually. You do this by choosing a scale factor for your user interface. The scale
factor causes user space content to be scaled by the specified amount. Code that is implemented properly for
resolution independence should look fine (albeit bigger). Code that is not implemented properly may see
Coordinate Systems and Transforms
Coordinate Systems Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
44alignment problems or pixel cracks along shape boundaries. To enable resolution independence in your
application, launch Quartz Debug and choose Tools > Show User Interface Resolution, then set your scale
factor. After changing the resolution, relaunch your application to see how it responds to the new resolution.
For the most part, Cocoa applicationsshould not have to do anything special to handle resolution-independent
UI. If you use the standard Cocoa views and drawing commands to draw your content, Cocoa automatically
scales any content you draw using the current scale factor. For path-based content, your drawing code should
require little or no changes. For images, though, you may need to take steps to make sure those images look
good at higherscale factors. For example, you might need to create higher-resolution versionsto take advantage
of the increased screen resolution. You might also need to adjust the position of images to avoid pixel cracks
caused by images being drawn on non-integral pixel boundaries.
For tips on how to make sure your content draws well at any resolution, see “Doing Pixel-Exact Drawing” (page
61). For more information about resolution independence and how it affects your code, see High Resolution
Guidelines for OS X .
Transform Basics
Transforms are a tool for manipulating coordinates (and coordinate systems) quickly and easily in your code.
Consider a rectangle whose origin is at (0, 0). If you wanted to change the origin of this rectangle to (10, 3), it
would be fairly simple to modify the rectangle’s origin and draw it. Suppose, though, that you wanted to
change the origin of a complex path that incorporated dozens of points and several Bezier curves with their
associated control points. How easy would it be to recalculate the position of each point in that path? It would
probably take a lot of time and require some pretty sophisticated calculations. Enter transforms.
A transform is two-dimensional mathematical array used to map points from one coordinate space to another.
Using transforms, you can scale, rotate, and translate content freely in two-dimensional space using only a few
methods and undo your changes just as quickly.
Support for transformsin Cocoa is provided by the NSAffineTransform class. The following sections provide
background information about transforms and their effects. For additional information about how to use
transforms in your code, see “Using Transforms in Your Code” (page 51).
The Identity Transform
The simplest type of transform is the identity transform. An identity transform maps any point to itself—that
is, it does not transform the point at all. You always start with an identity transform and add transformations
to it. Starting with the identity transform guarantees that you start from a known state. To create an identity
transform, you would use the following code:
Coordinate Systems and Transforms
Transform Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
45NSAffineTransform* identityXform = [NSAffineTransform transform];
Transformation Operations
For two-dimensional drawing, you can transform content in several different ways, including translating,scaling,
and rotating. Transforms modify the coordinate system for the current drawing environment and affect all
subsequent drawing operations. Before applying a transform, it is recommended that you save the current
graphics state.
The following sections describe each type of transformation and how it affects rendered content.
Translation
Translation involvesshifting the origin of the current coordinate system horizontally and vertically by a specific
amount. Translation is probably used the most because it can be used to position graphic elements in the
current view. For example, if you create a path whose starting point is always (0, 0), you could use a translation
transform to move that path around your view, as shown in Figure 3-2.
Figure 3-2 Translating content
To translate content, use the translateXBy:yBy: method of NSAffineTransform. The following example
changes the origin of the current context from (0, 0) to (50, 20) in the view's coordinate space:
NSAffineTransform* xform = [NSAffineTransform transform];
[xform translateXBy:50.0 yBy:20.0];
[xform concat];
Coordinate Systems and Transforms
Transform Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
46Scaling
Scaling lets you stretch or shrink the units of the user space along the x and y axes independently. Normally,
one unit in user space is equal to 1/72 of an inch. If you multiple the scale of either axis by 2, one unit on that
axis becomes equal to 2/72 of an inch. This makes content drawn with scale factors greater than 1 appear
magnified and content drawn with scale factors less than 1 appear shrunken.
Figure 3-3 shows the effects of scaling on content. In the figure, a translation transform has already been
applied so that the origin is located at (1, 1) in the original user space coordinate system. After applying the
scaling transform, you can see the modified coordinate system and how it maps to the original coordinate
system.
Figure 3-3 Scaling content
Although you might normally scale proportionally by applying the same scale factor to both the horizontal
and vertical axes, you can assign different scale factors to each axis to create a stretched or distorted image.
To scale content proportionally, use the scaleBy: method of NSAffineTransform. To scale content differently
along the X and Y axes, use the scaleXBy:yBy: method. The following example demonstrates the scale
factors shown in Figure 3-3:
NSAffineTransform* xform = [NSAffineTransform transform];
[xform scaleXBy:2.0 yBy:1.5];
[xform concat];
Coordinate Systems and Transforms
Transform Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
47Note: Scaling does not change the origin of the coordinate system.
Rotation
Rotation changes the orientation of the coordinate axes by rotating them around the current origin, as shown
in Figure 3-4. You can change the orientation through a full circle of motion.
Figure 3-4 Rotated content
To rotate content, use the rotateByDegrees: or rotateByRadians: methods of NSAffineTransform.
Positive rotation values proceed counterclockwise around the current origin. For example, to rotate the current
coordinate system 45 degrees around the current origin point (as shown in Figure 3-4), you would use the
following code:
NSAffineTransform* xform = [NSAffineTransform transform];
[xform rotateByDegrees:45];
[xform concat];
Note: Combining a non-uniform scaling transform with a rotation transform can also give your
content a skewed effect.
Transformation Ordering
The implementation of transforms uses matrix multiplication to map an incoming coordinate point to a modified
coordinate space. Although the mathematics of matrices are covered in “Transform Mathematics” (page 50),
an important factor to note is that matrix multiplication is not always a commutative operation—that is, a
times b does not always equal b times a. Therefore, the order in which you apply transforms is often crucial
to achieving the desired results.
Coordinate Systems and Transforms
Transform Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
48Figure 3-5 shows the two transformations applied to a path in two different ways. In the top part of the figure,
the content is translated by 60 points along the X axis and then rotated 45 degrees. In the bottom part of the
figure, the exact same transformations are reversed with the rotation preceding the translation. The end result
is two different coordinate systems.
Figure 3-5 Transform ordering
The preceding figure demonstrates the key aspect of transformation ordering. Each successive transformation
is applied to the coordinate system created by the previous transformations. When you translate and then
rotate, the rotation begins around the origin of the translated coordinate system. Similarly, when you rotate
and then translate, the translation occurs along the axes of the rotated coordinate system.
For transformations of the same type, the order of the transformations does not matter. For example, three
rotationsin a row creates a coordinate system whose final rotation is equal to the finalsum of the three rotation
angles. There may be other cases (such as scaling by 1.0) where the order of the transforms does not matter,
but you should generally assume that order is significant.
Coordinate Systems and Transforms
Transform Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
49Transform Mathematics
All transform operations contribute to the building of a mathematical matrix that is then used by the graphics
system to compute the screen location of individual points. The NSAffineTransform class uses a 3 x 3 matrix
to store the transform values. Figure 3-6 showsthis matrix and identifiesthe key factors used to apply transforms.
The m11 , m12 , m21 , and m22 values control both the scaling and rotation factors while t
x
and t
y
control
translation.
Figure 3-6 Basic transformation matrix
Using linear algebra, it is possible to multiply a coordinate vector through the transform matrix to obtain a
new coordinate vector whose position is equal to the original point in the new coordinate system. Figure 3-7
shows the matrix multiplication process and the resulting linear equations.
Figure 3-7 Mathematical conversion of coordinates
Coordinate Systems and Transforms
Transform Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
50If you are already familiar with transform structures and the mathematics, you can set the values of a transform
matrix directly using the setTransformStruct: method of NSAffineTransform. This method replaces
the six key transform values with the new ones you specify. Replacing all of the values at once is much faster
than applying individual transformations one at a time. It does require you to precompute the matrix values,
however.
Formore information aboutthemathematics behindmatrixmultiplications,seeQuartz 2DProgrammingGuide .
Using Transforms in Your Code
When it is time to draw, the code in your view’s drawRect: method must determine where to draw individual
pieces of content. The position of some elements, such as images and rectangles, can be specified easily, but
for complex elements like paths, transforms are an easy way to change the current drawing location.
Creating and Applying a Transform
To create a new transform object, call the transform class method of NSAffineTransform. The returned
transform object is set to the identity transform automatically. After you have added all of the desired
transformations to the transform object, you call the concat method to apply them to the current context.
Calling concat adds your transformations to the CTM of the current graphics context. The modifications stay
in effect until you explicitly undo them, as described in “Undoing a Transformation” (page 52), or a previous
graphics state is restored.
The following example creates a new transform object and adds several transformations to it.
NSAffineTransform* xform = [NSAffineTransform transform];
// Add the transformations
[xform translateXBy:50.0 yBy:20.0];
[xform rotateByDegrees:90.0]; // counterclockwise rotation
[xform scaleXBy:1.0 yBy:2.0];
// Apply the changes
[xform concat];
Coordinate Systems and Transforms
Using Transforms in Your Code
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
51Undoing a Transformation
Once applied, a transform affects all subsequent drawing calls in the current context. To undo a set of
transformations, you can either restore a previous graphicsstate or apply an inverse transform. Both techniques
have their advantages and disadvantages, so you should choose a technique based on your needs and the
available information.
Restoring a previous graphics state is the simplest way to undo a transformation but has other side effects. In
addition to undoing the transform, restoring the graphicsstate reverts all other attributesin the current drawing
environment back to their previous state.
If you want to undo only the current transformation, you can add an inverse transform to the CTM. An inverse
transform negates the effects of a given set of transformations using a complementary set of transformations.
To create an inverse transform object, you use the invert method of the desired transform object. You then
apply this modified transform object to the current context, as shown in the following example:
NSAffineTransform* xform = [NSAffineTransform transform];
// Add the transformations
[xform translateXBy:50.0 yBy:20.0];
[xform rotateByDegrees:90.0]; // counterclockwise rotation
[xform concat];
// Draw content...
// Remove the transformations by applying the inverse transform.
[xform invert];
[xform concat];
You might use this latter technique to draw multiple items using the same drawing attributes but at different
positions in your view. Depending on the type of transformations you use, you might also be able to do
incremental transformations. For example, if you are calling translateXBy:yBy: only to reposition the origin,
you could move the origin incrementally for each successive item. The following example, shows how you
might position one item at (10, 10) and the next at (15, 10):
[NSAffineTransform* xform = [NSAffineTransform transform];
// Draw item 1
[xform translateXBy:10.0 yBy:10.0];
Coordinate Systems and Transforms
Using Transforms in Your Code
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
52[xform concat];
[item1 draw];
//Draw item 2
[xform translateXBy:5.0 yBy:0.0]; // Translate relative to the previous element.
[xform concat];
[item2 draw];
Remember that the preceding techniques are used in cases where you do not want to modify your original
items directly. Cocoa provides ways to modify geometric coordinates without modifying the current
transformation matrix. For more information, see “Transforming Coordinates” (page 53).
It is also worth noting that the effectiveness of an inverse transform is limited by mathematical precision. For
rotation transforms, which involve taking sines and cosines of the desired rotation angle, an inverse transform
may not be precise enough to undo the original rotation completely. In such a situation, you may want to
simply save and restore the graphics state to undo the transform.
Transforming Coordinates
If you do not want to change the coordinate system of the current drawing environment, but do want to
change the position or orientation of a single object, you have several options. The NSAffineTransform
classincludesthe transformPoint: and transformSize: methodsfor changing coordinate values directly.
Using these methods does not change the CTM of the current graphics context.
If you want to alter the coordinates in a path, you can do so using the transformBezierPath: method of
NSAffineTransform. This method returns a transformed copy of the specified Bezier path object. This method
differs slightly from the transformUsingAffineTransform: method of NSBezierPath, which modifies
the original object.
Converting from Window to View Coordinates
Events sent to your view by the operating system are sent using the coordinate system of the window. Before
your view can use any coordinate values included with the event, it must convert those coordinates to its own
local coordinate space. The NSView class provides several functions to facilitate the conversion of NSPoint,
NSSize, and NSRect structures. Among these methods are convertPoint:fromView: and
convertPoint:toView:, which convert pointsto and from the view’slocal coordinate system. For a complete
list of conversion methods, see NSView Class Reference .
Coordinate Systems and Transforms
Using Transforms in Your Code
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
53Important: Cocoa event objects return y coordinate values that are 1-based (in window coordinates)
instead of 0-based. Thus, a mouse click on the bottom left corner of a window or view would yield the point
(0, 1) in Cocoa and not (0, 0). Only y-coordinates are 1-based.
The following example converts the mouse location of a mouse event from window coordinates to the
coordinates of the local view. To convert to the view’s local coordinate space, you use the
convertPoint:fromView: method. The second parameter to this method specifies the view in whose
coordinate system the point is currently specified. Specifying nil for the second parameter tells the current
view to convert the point from the window’s coordinate system.
NSPoint mouseLoc = [theView convertPoint:[theEvent locationInWindow] fromView:nil];
Coordinate Systems and Transforms
Using Transforms in Your Code
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
54Flipped Coordinate Systems
One topic that comes up frequently in Cocoa and Quartz is the use of flipped coordinate systems for drawing.
By default, Cocoa uses a standard Cartesian coordinate system, where positive values extend up and to the
right of the origin. It is possible, however, to “flip” the coordinate system, so that positive values extend down
and to the right of the origin and the origin itself is positioned in the top-left corner of the current view or
window, as shown in Figure 3-8.
Figure 3-8 Normal and flipped coordinate axes
Flipping the coordinate system can make drawing easier in some situations. Text systems in particular use
flipped coordinates to simplify the placement of text lines, which flow from top to bottom in most writing
systems. Although you are encouraged to use the standard Cartesian (unflipped) coordinate system whenever
possible, you can use flipped coordinates if doing so is easier to support in your code.
Configuring a view to use flipped coordinates affects only the content you draw directly in that view. Flipped
coordinate systems are not inherited by child views. The content you draw in a view, however, must be oriented
correctly based on the current orientation of the view. Failing to take into account the current view orientation
may result in incorrectly positioned content or content that is upside down.
Coordinate Systems and Transforms
Flipped Coordinate Systems
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
55The following sections provide information about Cocoa support for flipped coordinates and some of the issues
you may encounter when using flipped coordinate systems. Wherever possible, these sections also offer
guidance on how to solve issues that arise due to flipped coordinate systems.
Configuring Your View to Use Flipped Coordinates
The first step you need to take to implement flipped coordinates is to decide the default orientation of your
view. If you prefer to use flipped coordinates, there are two ways to configure your view’s coordinate system
prior to drawing:
● Override your view’s isFlipped method and return YES.
● Apply a flip transform to your content immediately prior to rendering.
If you plan to draw all of your view’s content using flipped coordinates, overriding the view’s isFlipped
method is by far the preferred option. Overriding this method lets Cocoa know that your view wants to use
flipped coordinates by default. When a view’s isFlipped method returns YES, Cocoa automatically makes
several adjustments for you. The most noticeable change is that Cocoa adds the appropriate conversion
transform to the CTM before calling your view’s drawRect: method. This behavior eliminates the need for
your drawing code to apply a flip transform manually. In addition, many Cocoa objects automatically adjust
their drawing code to account for the coordinate system of the current view. For example, the NSFont object
automatically takes the orientation of the coordinate system into account when setting the current font. This
prevents text from appearing upside down when drawn in your view.
If you draw only a subset of your view’s content using flipped coordinates, you can use a flip transform (instead
of overriding isFlipped) to modify the coordinate system manually. A flip transform lets you adjust the
current coordinate system temporarily and then undo that adjustment when it is no longer needed. You would
apply thistransform to your view’s coordinate system immediately prior to drawing the relevant flipped content.
For information on how to create a flip transform, see “Creating a Flip Transform” (page 59).
Drawing Content in a Flipped Coordinate System
Most of the work you do to support flipped coordinates occurs within your application’s drawing code. If you
chose to use flipped coordinates in a particular view, chances are it was because it made your drawing code
easier to implement. Drawing in a flipped coordinate system requires you to position elements differently
relative to the screen but is otherwise fairly straightforward. The following sections provide some tips to help
you ensure any rendered content appears the way you want it.
Coordinate Systems and Transforms
Flipped Coordinate Systems
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
56Drawing Shape Primitives
There are no real issues with drawing shape primitives in flipped coordinate systems. Shape primitives, such
as rectangles, ovals, arcs, and Bezier curves can be drawn just as easily in flipped or unflipped coordinate
systems. The only differences between the two coordinate systems is where the shapes are positioned and
their vertical orientation. Laying out your shapes in advance to determine their coordinate points should solve
any orientation issues you encounter.
Drawing With Application Kit Functions
The Application Kit framework contains numerousfunctionsfor quickly drawing specific content. Among these
functions are NSRectFill, NSFrameRect, NSDrawGroove, NSDrawLightBezel, and so on. When drawing
with these functions, Cocoa takesinto account the orientation of the target view. Thus, if your view usesflipped
coordinates, these functions continue to render correctly in that flipped coordinate space.
Drawing Images
When rendering images in your custom views, you must pay attention to the relative orientation of your view
and any images you draw in that view. If you draw an image in a flipped view using the
drawInRect:fromRect:operation:fraction: method, your image would appear upside down in your
view. You could fix this problem using one of several techniques:
● You could apply a flip transform immediately prior to drawing the image; see “Creating a Flip
Transform” (page 59).
● You could use one of the compositeToPoint methods of NSImage to do the drawing.
● You could invert the image data itself. (Although a suitable fix, this is usually not very practical.)
Using a flip transform to negate the effects of a flipped view ensures that your image contents are rendered
correctly in all cases. This technique retains any previous transformations to the coordinate system, including
scales and rotations, but removes the inversion caused by the view being flipped. You should especially use
thistechnique if you needed to draw your image using the drawInRect:fromRect:operation:fraction:
method of NSImage. This method lets you scale your image to fit the destination rectangle and is one of the
more commonly used drawing methods for images.
Although the compositeToPoint methods of NSImage provide you with a way to orient images properly
without a flip transform, their use is not recommended. There are some side effects that make drawing with
these methods more complicated. The compositeToPoint methods work by removing any custom scaling
or rotation factors that you applied to the CTM. These methods also remove any scaling (but not translations)
applied by any flip transforms, whether the transform was supplied by you or by Cocoa. (The methods also do
not remove the scale factor in effect from resolution independence.) Any custom translation factors you applied
Coordinate Systems and Transforms
Flipped Coordinate Systems
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
57to the CTM are retained, however. Although this behavior is designed to ensure that images are not clipped
by your view’s bounding rectangle, if you do not compensate for the flip transform’stranslation factor, clipping
may still occur.
Figure 3-9 shows what happens when you render an image in an unflipped view, and then in a flipped view,
using the compositeToPoint:fromRect:operation: method. In the unflipped view, the image renders
as expected at the specified point in the view. In the flipped view, the scale factor for the y-axis is removed
but the translation factor is not, which results in the image being clipped because it appears partially outside
the view’s visible bounds. To compensate, you would need to adjust the y-origin of the image by subtracting
the original value from the view height to get the adjusted position.
Figure 3-9 Compositing an image to a flipped view
The issues related to the drawing of images in a flipped coordinate system are essentially independent of how
you create those images in the first place. Images use a separate coordinate system internally to orient the
image data. Whether you load the image data from an existing file or create the image by locking focus on it,
Coordinate Systems and Transforms
Flipped Coordinate Systems
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
58once the image data is loaded or you unlock focus, the image data is set. At that point, you must choose the
appropriate drawing method or adjust the coordinate system yourself prior to drawing to correct for flipped
orientation issues.
Important: Although the setFlipped: method of NSImage might seem like a good way to change the
orientation of an image after the fact, that is not actually the case. The setFlipped: method is there to
let you specify the orientation of the image data before you issue a lockFocus call and draw into the
image. Using that method to correct for flipped coordinate systems during drawing might seem to work
at times, but it is not a reliable way to flip images and its use in that capacity is highly discouraged.
For more information about images and their internal coordinate systems,see “Image Coordinate Systems” (page
81).
Important: Regardless of whether the contents of the image are flipped or unflipped, you always specify
the location and size of the image using the coordinate system of the current context.
Drawing Text
The text rendering facilities in Cocoa take their cues for text orientation from the current view. If your view’s
isFlipped method returns YES, Cocoa automatically inverts the text drawn in that view to compensate for
its flipped coordinate system. If you apply a flip transform manually from your drawing code, however, Cocoa
does not know to compensate when drawing text. Any text you render after applying a flip transform manually
therefore appears upside down in your view. These rules apply whether you are using the Cocoa text system
or the drawing facilities of NSString to draw your text.
If you lock focus on an image and draw some text into it, Cocoa uses the internal coordinate system of the
NSImage object to determine the correct orientation for the text. As with other image content, if you
subsequently render the image in a flipped view, the text you drew is flipped along with the rest of the image
data.
For more information about working with text, see “Text” (page 127).
Creating a Flip Transform
If you want to flip the coordinate system of your view temporarily, you can create a flip transform and apply
it to the current graphics context. A flip transform is an NSAffineTransform object configured with two
transformations: a scale transformation and a translate transformation. The flip transform works by flipping
the direction of the y axis (using the scale transformation) and then translating the origin to the top of the
view.
Coordinate Systems and Transforms
Flipped Coordinate Systems
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
59Listing 3-1 shows a drawRect: method that creates a flip transform and applies it to the current context. The
flip transform shown here translatesthe origin first before reversing the direction of the vertical axis. You could
also implement this transform by reversing the vertical axis first and then translating the origin in the negative
direction—that is, using the negated value of the frame height.
Listing 3-1 Flipping the coordinate system manually
- (void)drawRect:(NSRect)rect
{
NSRect frameRect = [self bounds];
NSAffineTransform* xform = [NSAffineTransform transform];
[xform translateXBy:0.0 yBy:frameRect.size.height];
[xform scaleXBy:1.0 yBy:-1.0];
[xform concat];
// Draw flipped content.
}
The flip transform merely toggles the orientation of the current coordinate system. If your view already draws
using flipped coordinates, because its isFlipped method returns YES, applying a flip transform reverts the
coordinate system back to the standard orientation.
Cocoa Use of Flipped Coordinates
Some Cocoa classes inherently support flipped coordinates and some do not. If you are using unmodified
Cocoa views and controls in your user interface, it should not matter to your code whether those views and
controls use flipped coordinates. If you are subclassing, however, it isimportant to know the coordinate system
orientation. The following controls and views currently use flipped coordinates by default:
● NSButton
● NSMatrix
● NSProgressIndicator
● NSScrollView
● NSSlider
● NSSplitView
● NSTabView
● NSTableHeaderView
Coordinate Systems and Transforms
Flipped Coordinate Systems
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
60● NSTableView
● NSTextField
● NSTextView
Some Cocoa classes support flipped coordinates but do not use them all the time. The following list includes
the known cases where flipped-coordinate support depends on other mitigating factors.
●
Images do not use flipped coordinates by default; however, you can flip the image’s internal coordinate
system manually using the setFlipped: method of NSImage. All representations of an NSImage object
use the same orientation. For more information about images and flipped coordinates, see “Image
Coordinate Systems” (page 81).
● The Cocoa text system takes cues from the current context to determine whether text should be flipped.
If the text is to be displayed in an NSTextView object, text system objects (such as NSFont) also uses
flipped coordinates to ensure that text is rendered right-side up. If you are drawing text in a custom view
that uses standard coordinate, the text system objects do not use flipped coordinates.
● An NSClipView object determines whether to use flipped coordinates by looking at the coordinate system
of its document view. If the document view uses flipped coordinates, so does the clip view. Using the
same coordinate system ensures that the scroll origin matches the bounds origin of the document view.
● Graphics convenience functions,such asthose declared in NSGraphics.h, take flipped coordinate systems
into account when drawing. For information about the available graphics convenience functions, see
Application Kit Functions Reference .
As new controls and views are introduced in Cocoa, those objects may also support flipped coordinates. Check
the class reference documentation for any subclassing notes on whether a class supports flipped coordinates.
You can also invoke the view’s isFlipped method at runtime to determine if it uses flipped coordinates.
Doing Pixel-Exact Drawing
Although it is possible to create applications using only the views, controls, and images provided by Cocoa, it
is common for applications to use one or more custom views or images. And although Cocoa provides default
behavior for laying out custom content, there are many times when you may want to adjust the position of
individual views or imagesto avoid visual artifacts. Thisis especially true when tiling or drawing bitmap images
on high-resolution devices(such as printers) or devices where resolution independentscale factors are in effect.
The following sections provide guidelines and practical advice for how to prevent visual artifactsthat can occur
during high-resolution drawing. For additional information on resolution independence and how to adapt
your code to support different scale factors, see High Resolution Guidelines for OS X .
Coordinate Systems and Transforms
Doing Pixel-Exact Drawing
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
61Tips for Resolution Independent Drawing in Cocoa
Cocoa applications provide a tremendous amount ofsupport for rendering to high-resolution devices. Although
much of this support is automatic, you still need to do some work to ensure your content looks good. The
following list includes some approaches to take when designing your interface:
● Use high-resolution images.
● During layout, make sure views and images are positioned on integral pixel boundaries.
● When creating tiled background images for custom controls, use the NSDrawThreePartImage and
NSDrawNinePartImage methods to draw your background rather than trying to draw it yourself.
● Use antialiased text rendering modes for non-integral scale factors and be sure to lay out your text views
on pixel boundaries.
● Test your applications with non-integral scale factors such as 1.25 and 1.5. These factors tend to generate
odd numbers of pixels, which can reveal potential pixel cracks.
If you are using OpenGL for drawing, you should also be aware that in OS X v10.5, the bounding rectangle of
a view drawn into an NSOpenGLContext is measured in pixels and not in points (as it is in non OpenGL
situations). This support may change in the future, however, so OpenGL developers should be sure to convert
coordinates directly using the coordinate conversion methods of NSView. For example, the following conversion
code for a view object is guaranteed to return the correct values needed by OpenGL.
NSSize boundsInPixelUnits = [self convertRect:[self bounds] toView:nil];
glViewport(0, 0, boundsInPixelUnits.size.width, boundsInPixelUnits.size.height);
For more information about resolution independence and how it affectsrendered content,see High Resolution
Guidelines for OS X .
Accessing the Current Scale Factor
Knowing the current scale factor can help you make decisions about how best to render your content. The
NSWindow and NSScreen classes both include a userSpaceScaleFactor method that you can call to obtain
the current scale factor, if any, for your application. In OS X v10.5 and earlier, this method usually returns 1.0,
indicating that the user space and device space have the same resolution (where one point equals one pixel).
At some point though, this method may return a value that is greater than 1.0. For example, a value of 1.25
would indicate a screen resolution of approximately 90 dpi, while a value of 2.0 would indicate a screen
resolution of 144 dpi.
Coordinate Systems and Transforms
Doing Pixel-Exact Drawing
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
62If you want to know the actual resolution of a particularscreen, the NSScreen classincludesinformation about
the display resolution in its device description dictionary (accessed using the deviceDescription method).
You can use this information (instead of multiplying scale factors) to determine the appropriate resolution to
use for your images.
Adjusting the Layout of Your Content
Because screens are relatively low-resolution devices, drawing glitches are often more noticeable on a screen
than they are on higher-resolution devices such as printers. Drawing glitches can occur when you render
content in a way that requirestweaking to match the underlying pixelssent to the screen. For example, images
and shapes drawn on non-pixel boundaries might require aliasing and therefore might appear less crisp than
those drawn exactly on pixel boundaries. In addition, scaling an image to fit into a different-sized area requires
interpolation, which can introduce artifacts and graininess.
Although pixel-alignment issues can occur on any version of OS X, they are more likely to occur asthe operating
system changes to support resolution independence. Under resolution independence, units in the user
coordinate space and device coordinate space are no longer required to maintain a one-to-one relationship.
For high-resolution screens, this means that a single unit in user space may be backed by multiple pixels in
device space. So even if your user-space coordinatesfall on integral unit boundaries, they may still be misaligned
in device space. The presence of extra pixels can also lead to pixel cracks, which occur when misaligned shapes
leave small gaps because they do not fill the intended drawing area entirely.
If your images or shapes are not drawing the way you expect, or if your graphics content displays evidence of
pixel cracks, you can remove many of these issues by adjusting the coordinate values you use to draw your
content. The following steps are not required if the current scale factor is 1.0 but would be required for other
scale factors.
1. Convert the user-space point, size, or rectangle value to device space coordinates.
2. Normalize the value in device space so that it is aligned to the appropriate pixel boundary.
3. Convert the normalized value back to user space.
4. Draw your content using the adjusted value.
The best way to get the correct device-space rectangle is to use the centerScanRect: method of NSView.
This method takes a rectangle in userspace coordinates, performsthe needed calculationsto adjust the position
of rectangles based on the current scale factor and device, and returns the resulting user space rectangle. For
layout, you can also use the methods described in “Converting Coordinate Values” (page 64).
If you want more control over the precise layout of items in device space, you can also adjust coordinates
yourself. OS X provides several functions for normalizing coordinate values once they are in device space,
including the NSIntegralRect and CGRectIntegral functions. You can also use the ceil and floor
functions in math.h to round device space coordinates up or down as needed.
Coordinate Systems and Transforms
Doing Pixel-Exact Drawing
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
63Converting Coordinate Values
In OS X v10.5, several methods were added to NSView to simplify the conversion between user space and
device space coordinates:
● convertPointToBase:
● convertSizeToBase:
● convertRectToBase:
● convertPointFromBase:
● convertSizeFromBase:
● convertRectFromBase:
These convenience methods make it possible to convert values to and from the base (device) coordinate
system. They take into account the current backing store configuration for the view, including whether it is
backed by a layer.
To change the coordinate values of an NSPoint structure, the beginning of your view’s drawRect: method
might have code similar to the following:
- (void)drawRect:(NSRect)rect
{
NSPoint myPoint = NSMakePoint(1.0, 2.0);
CGFloat scaleFactor = [[self window] userSpaceScaleFactor];
if (scaleFactor != 1.0)
{
NSPoint tempPoint = [self convertPointToBase:myPoint];
tempPoint.x = floor(tempPoint.x);
tempPoint.y = floor(tempPoint.y);
myPoint = [self convertPointFromBase:tempPoint];
}
// Draw the content at myPoint
}
It is up to you to determine which normalization function is best suited for your drawing code. The preceding
example uses the floor function to normalize the origin of the given shape but you might use a combination
of floor and ceil depending on the position of other content in your view.
Coordinate Systems and Transforms
Doing Pixel-Exact Drawing
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
64One of the keys to creating interesting graphics is the effective use of color and transparency. In OS X, both
are used to convey information and provide an inherent appeal to your creations. Good color usage usually
results in an interface that is pleasing to the user and helps call out information when it is needed.
About Color and Transparency
Support for color in Cocoa is built on top of Quartz. The NSColor class provides the interface for creating and
manipulating colors in a variety of color spaces. Other classes provide color and color space management.
Cocoa also provides classes that present a user interface for selecting colors.
For a more thorough explanation of color, color theory, and color management in OS X,see Color Management
Overview and Color Programming Topics.
Color Models and Color Spaces
The human eye perceives photons in a fairly narrow band of the electromagnetic spectrum. Each photon
vibrates at a frequency that defines the color of the light represented by that photon. The biology of the eye
makes it particularly receptive to red, blue, and green light and these primary colors are often mixed together
to create a broad range of perceptible colors.
A color model is a geometric or mathematical framework that attempts to describe the colors seen by the eye.
Each model contains one or more dimensions, which together represent the visible spectrum of color. Numerical
values are pinned to each dimension making it possible to describe colors in the color model numerically.
Having a numerical representation makes it possible to describe, classify, compare, and order those colors.
A color space is a practical adaptation of a color model. It specifies the gamut (or range) of colors that can be
produced using a particular color model. While the color model determines the relationship between values
in each dimension, the color space defines the absolute meaning of those values as colors. Cocoa supports
the same color spaces as Quartz 2D, although accessor methods of NSColor focus on the following color
spaces:
● RGB
● CMYK
● Gray
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
65
Color and TransparencyIn Cocoa, the NSColorSpace class handles the information associated with a particular color space. You can
create instances of this class to represent individual color spaces. Cocoa provides methods for retrieving color
space objects representing the standard color spaces. You can also create custom color space objects using a
ColorSync profile reference or International Color Consortium (ICC) profile data.
For detailed information about color spaces and color models in OS X, see Color Management Overview.
Color Objects
The NSColor class in Cocoa provides the interface you need to create and manage individual colors. The
NSColor classisitself a factory classfor creating the actual color objects. The class methods of NSColor create
color objects that are actually based on specific subclasses of NSColor, where each subclass implements the
behavior for a specific color space.
Because a color object must represent a single color space, you cannot use all of the methods of NSColor
from the same object. For a given color object, you can use only the methods that are relevant to colors in
that object’s color space. For example, if you create an CMYK-based color object, you cannot use the
getRed:green:blue:alpha: method to retrieve RGB values. Methods that are unsupported in the current
color space raise an exception.
For more information on how to create and use colors, see “Creating Colors” (page 68).
Color Component Values
In Cocoa, color space values, called components, are specified as floating-point values in the range 0.0 to 1.0.
When working with other color values from other systems, you must convert any values that do not fall into
the supported range. For example, if you use a color system whose components have values in the range 0 to
255, you must divide each component value by 255 to get the appropriate value for Cocoa.
You can retrieve the component values of a color object using any of several methods in NSColor. Several
methods exist for retrieving the color values of known color spaces, such as RGB, CMYK, HSV (also known as
HSB), and gray. If you do not know the number of components in the color’s color space, you can use the
numberOfComponents method to find out. You can then use the getComponents: method to retrieve the
component values.
Transparency
In addition to the component values used to identify a particular color in a colorspace, OS X colors also support
an alpha component for identifying the transparency of that color.
Color and Transparency
About Color and Transparency
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
66Transparency is a powerful effect used to give the illusion of light passing through a particular area instead of
reflecting off of it. When you render an object using a partially transparent color, the object picks up some
color from the object directly underneath it. The amount of color it picks up depends on the value of the color’s
alpha component and the compositing mode.
Like color components, the alpha component is specified as a floating-point value in the range 0.0 to 1.0. You
can think of the alpha component as specifying the amount of light being reflected back from the object’s
surface. An alpha value of 1.0 represents a 100% reflection of all light and is equivalent to the object being
opaque. An alpha value of 0.0 represents 0% reflection of light and all color coming from the content underneath.
An alpha value of 0.5 represents 50% reflection, with half the color being reflected off the object and half
coming from the content underneath.
You specify transparency when you create a color object. If you create a color using component values, you
can specify an alpha value directly. If you have an existing color object, you can use the
colorWithAlphaComponent: method to create a new color object with the same color components as the
original but with the alpha value you specify.
Pattern Colors
In addition to creating monochromatic colors, you can also create pattern colors using images. Pattern colors
are most applicable asfill colors but can be used asstroke colors as well. When rendered, the image you specify
is drawn on the path or its fill area instead of a solid color. If an image is too small to fill the given area, it is
tiled vertically and horizontally, as shown in Figure 4-1.
Figure 4-1 Drawing with a pattern
For information on how to create pattern colors, see “Creating Colors” (page 68).
Color and Transparency
About Color and Transparency
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
67Color Lists
A color list is a dictionary-like object (implemented by the NSColorList class) that contains an ordered list
of NSColor objects, identified by keys. You can retrieve colors from the color list by key. You can also organize
the colors by placing them at specific indexes in the list.
Color lists are available as a tool to help you manage any document-specific colors. They are also used to
customize the list of colors displayed in a color panel. You can use the attachColorList: method of
NSColorPanel to add any colors your application uses to the panel.
For more information about using color lists and color panels, see Color Programming Topics.
Color Matching
Cocoa provides automatic color matching whenever possible using ColorSync. Color matching ensures that
the colors you use to draw your content look the same on different devices.
Cocoa provides full support for creating and getting color profile information using the NSColorSpace class.
Cocoa supports both ColorSync profile references and ICC profiles as well as calibrated and device-specific
profiles for the RGB, CMYK, and gray color spaces. Because color matching is automatic, there is nothing to do
in your code except use the colors you want.
For information about ColorSync, see ColorSync Manager Reference . For information on ICC profiles, see the
International Color Consortium website: http://www.color.org/.
Creating Colors
The NSColor class supports the creation of several different types of color objects:
● Commonly used colors, such as red, green, black, or white
● System colors,such asthe current control color or highlight color, whose values are set by user preferences
● Calibrated colors belonging to a designated color space
● Device colors belonging to the designated device color space
● Pattern colors
To create most color objects, simply use the appropriate class method of NSColor. The class defines methods
for creating preset colors or for creating colors with the values you specify. To create a pattern color, load or
create the desired image and pass it to the colorWithPatternImage: method of NSColor. For more
information, see the NSColor class reference. For information on how to load and create images, see
“Images” (page 74).
Color and Transparency
Creating Colors
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
68Important: Never allocate and initialize an NSColor object directly. Because it is a base class, the
implementation of NSColor is minimal and simply throws an exception in situations where actual color
information is required.
In OS X v10.5 and later, Cocoa provides support for gradient fill patterns through the NSGradient class. Prior
to version 10.5, if you want to use a gradient to fill or stroke a path, you must use Quartz instead. For examples
of how to create and use gradients, see “Creating Gradient Fills” (page 113).
Working with Colors
Once you have an NSColor object, you can apply it to the stroke or fill color of the current context. Once set,
any shapes you draw in the current context take on that color. You can also use the color component information
in any calculations you might need for your program.
Applying Colors to Drawn Content
Stroke and fill colors modify the appearance of path-based shapes,such asthose drawn with the NSBezierPath
class or functions such as NSRectFill. The stroke color applies to the path itself, and the fill color applies to
the area bounded by that path.
To set the current stroke or fill attributes, you use one of the NSColor methods listed in Table 4-1.
Table 4-1 Methods for changing color attributes
NSColor method Description
set Sets both the stroke and fill color to the same value.
setFill Sets the fill color.
setStroke Sets the stroke color.
For example, the following code sets the stroke color to black and the fill color to the background color for
controls.
[[NSColor blackColor] setStroke];
[[NSColor controlBackgroundColor] setFill];
Color and Transparency
Working with Colors
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
69All subsequent drawing operations in the current context would use the specified colors. If you do not want
any color to be drawn for the stroke or fill, you can set the current stroke or fill to a completely transparent
color, which you can get by calling the clearColor method of NSColor. You can also create a transparent
color by setting the alpha of any other color to 0.
Note: Stroke and fill colors do not affect the appearance of text. To apply color to text, you must
change the attributes associated with the text.
Applying Color to Text
Unlike many graphics operations, text is not drawn using the current stroke and fill colors. Instead, to apply
color to text, you must apply color attributes to the characters of the corresponding string object.
To apply color to a range of characters in an NSAttributedString object, you apply the
NSForegroundColorAttributeName attribute to the characters. This attribute takes a corresponding
NSColor object as its value.
To apply color to the characters of an NSString object, you apply the NSForegroundColorAttributeName
attribute just as you would for an NSAttributedString object. The difference in application isthat attributes
applied to an NSString object affect the entire string and not a specified range of characters.
The set of available attributesfor both string typesislisted in NSAttributedString Application Kit Additions Reference
in the Application Kit Framework Reference . For an example of how to change the attributes of an attributed
string, see “Changing an Attributed String” in Attributed String Programming Guide . For more information about
drawing text, see “Text” (page 127).
Getting the Components of a Color
If your program manipulates colors in any way, you may want to know the component values for the colors
you use. NSColor provides the following accessor methods for retrieving component values of a color:
● numberOfComponents
● getComponents:
● getRed:green:blue:alpha:
● getCyan:magenta:yellow:black:alpha:
● getHue:saturation:brightness:alpha:
● getWhite:alpha:
Color and Transparency
Working with Colors
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
70The NSColor class also provides methods for accessing individual component values, rather than all of the
components together. For more information, see the NSColor class reference.
Important: It is a programming error to ask an NSColor object for components that are not defined in
the color space of its current color, and making such a request raises an exception. If you need a specific
set of components, you should first convert the color to the appropriate color space using the
colorUsingColorSpaceName: method. For more information, see “Converting Between Color
Spaces” (page 71).
Choosing Colors
Applicationsthat need to present a color picker interface to the user can use either a color well or a color panel.
A color well is a control that displays a single color. You can embed this control in your windows and use it to
show a currently selected color. When clicked, a color well displays the system color panel, which provides an
interface for picking a color. You can also use the color panel on its own to prompt the user for a color.
For information about how to use color wells and the color panel in your application, see Color Programming
Topics.
Working with Color Spaces
Colorspaces help your program maintain color fidelity throughout the creation and rendering process. Although
most programs may never need to worry about color spaces, you might need to know the current color space
in some situations, such as prior to manipulating color component values.
Converting Between Color Spaces
You can convert between color spaces using the colorUsingColorSpaceName: method of NSColor. This
method creates a new color object representing the same color but using the color space you specify. To
convert a color from RGB to CMYK, you could use code similar to the following:
NSColor* rgbColor = [NSColor colorWithCalibratedRed:1.0 green: 0.5 blue: 0.5
alpha:0.75];
NSColor* cmykColor = [rgbColor colorUsingColorSpace:[NSColorSpace
genericCMYKColorSpace]];
Color and Transparency
Working with Color Spaces
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
71Mapping Physical Colors to a Color Space
The range of colors (or gamut) that can be physically displayed on an output device differs from device to
device. During rendering, Cocoa attempts to match the colors you specify in your code as closely as it can to
the colors available in the target device. Sometimes, though, it maps colorsin a different way so asto emphasize
different aspects of a color that might be more important when reproducing that color. The mapping used for
colors is referred to as the rendering intent and it is something most developers rarely need to change.
Because most developersshould not need to change the rendering intent, you cannotset the attribute directly
from Cocoa. If your application needs more control over the color management, you must use Quartz to change
the rendering intent. Table 4-2 lists the rendering intents supported by Quartz.
Table 4-2 Quartz rendering intents
Rendering intent Description
Use the default rendering intent settings. In this mode, Quartz uses the
relative colorimetric intent for all drawing except that ofsampled images;
for sampled images, Quartz uses the perceptual rendering intent.
kCGRenderingIntentDefault
This rendering intent performs no white point adjustment to the colors.
A color that appearsto be white on a screen display may be reproduced
on a printed medium as a bluish color (because a white color on a screen
actually has a bluish cast). This intent is useful for simulating one device
on another or for rendering logos where exact color reproduction is
important.
kCGRenderingIntentAbsoluteColorimetric
This rendering intent uses the white point information from the source
and destination and adjusts the color information so that the white
point of the source maps into the white point of the destination.
In-gamut colors are also adjusted accordingly. This intent is typically
used for line art graphics.
kCGRenderingIntentRelativeColorimetric
Thisrendering intent produces pleasing visual results and preservesthe
relationship between colors at the expense of the absolute color
reproduction. This intent is typically used for photographic images.
kCGRenderingIntentPerceptual
Thisrendering intent attemptsto maximize the saturation of colors. This
intent is mostly used for business charts or graphics.
kCGRenderingIntentSaturation
To change the rendering intent, you must get a Quartz graphics context for the current drawing environment
and call the CGContextSetRenderingIntent function, as shown in the following example:
- (void) drawRect:(NSRect)rect
Color and Transparency
Working with Color Spaces
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
72{
CGContextRef theCG = [[NSGraphicsContext currentContext] graphicsPort];
// Change the rendering intent.
CGContextSetRenderingIntent(theCG, kCGRenderingIntentPerceptual);
// Draw your content.
}
Color and Transparency
Working with Color Spaces
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
73Important: This chapter has not yet been updated to describe how images work in OS X v10.6. Significant
changes were made to image processing in OS X v10.6. See Application Kit Release Notes (10.7 and Earlier)
and High Resolution Guidelines for OS X for details.
Images are an important part of any Mac app. In Cocoa, images play a very important, but flexible, role in your
user interface. You can use imagesto render preexisting content or act as a buffer for your application's drawing
commands. At the heart of Cocoa'simage manipulation code isthe NSImage class. This class manages everything
related to image data and is used for the following tasks:
● Loading existing images from disk.
● Drawing image data into your views.
● Creating new images.
● Scaling and resizing images.
● Converting images to any of several different formats.
You can use images in your program for a variety of tasks. You can load images from existing image files (such
as JPEG, GIF, PDF, and EPS files) to draw elements of your user interface that might be too difficult (or too
inefficient) to draw using primitive shapes. You can also use images as offscreen or temporary buffers and
capture a sequence of drawing commands that you want to use at a later time.
Although bitmaps are one of the most common types of image, it is important not to think of the NSImage
class as simply managing photographic or bitmap data. The NSImage class in Cocoa is capable of displaying
a variety of image types and formats. It provides support for photograph and bitmap data in many standard
formats. It also provides support for vector, or command-based data, such as PDF, EPS, and PICT. You can even
use the NSImage class to represent an image created with the Core Image framework.
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
74
ImagesImage Basics
The NSImage class providesthe high-level interface for manipulating imagesin many different formats. Because
it provides the high-level interface, NSImage knows almost nothing about managing the actual image data.
Instead, the NSImage class manages one or more image representation objects—objects derived from the
NSImageRep class. Each image representation object understands the image data for a particular format and
is capable of rendering that data to the current context.
The following sections provide insight into the relationship between image objects and image representations.
Image Representations
An image representation object represents an image at a specific size, using a specific color space, and in a
specific data format. Image representations are used by an NSImage object to manage image data. An image
representation object knows how to read image data from a file, write that data back to a file, and convert the
image data to a raw bitmap that can then be rendered to the current context. Some image representations
also provide an interface for manipulating the image data directly.
For file-based images, NSImage creates an image representation object for each separate image stored in the
file. Although most image formats support only a single image, formats such as TIFF allow multiple images to
be stored. For example, a TIFF file might store both a full size version of an image and a thumbnail.
If you are creating images dynamically, you are responsible for creating the image representation objects you
need for your image. As with file-based images, most of the images you create need only a single image
representation. Because NSImage is adept at scaling and adjusting images to fit the target canvas, it is usually
not necessary to create different image representations at different resolutions. You might create multiple
representations in the following situations, however:
● For printing, you might want to create a PDF representation or high-resolution bitmap of your image.
● You want to provide different content for your image when it is scaled to different sizes.
When you draw an image, the NSImage object chooses the representation that is best suited for the target
canvas. This choice is based on several factors, which are explained in “How an Image Representation Is
Chosen” (page 77). If you want to ensure that a specific image representation is used, you can use the
drawRepresentation:inRect: method of NSImage.
Image Representation Classes
Every image representation object is based on a subclass of NSImageRep. Cocoa defines several specific
subclasses to handle commonly used formats. Table 5-1 lists the class and the image types it supports.
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
75Table 5-1 Image representation classes
Supported Description
types
Class
Handles bitmap data. Several common bitmap formats
are supported directly. For custom image formats, you
may have to decode the image data yourself before
creating your image representation. An
NSBitmapImageRep object uses any available color
profile data (ICC or ColorSync) when rendering.
TIFF, BMP,
JPEG, GIF, PNG,
DIB, ICO,
among others
NSBitmapImageRep
This classis used internally by Cocoa to cache imagesfor
drawing to the screen. You should not need to use this
class directly.
NSCachedImageRep Rendered data
Provides a representation for a CIImage object, which
itself supports most bitmap formats.
NSCIImageRep N/A
NSPDFImageRep PDF Handles the display of PDF data.
Handles the display of PostScript or encapsulated
PostScript data.
NSEPSImageRep EPS
Handles custom image data by passing it to a delegate
object you provide.
NSCustomImageRep Custom
Handles the display of PICT format version 1, version 2,
and extended version 2 pictures. The PICT format is a
legacy format described in the Carbon QuickDraw
Manager documentation.
NSPICTImageRep PICT
In most situations, you do not need to know how an image representation is created. For example, if you load
an existing image from a file, NSImage automatically determines which type of image representation to create
based on the file data. All you have to do is draw the image in your view.
If you want to support new image formats, you can create a new image representation class. The NSImage
class and its NSImageRep subclasses do not follow the class cluster model found in several other Cocoa classes.
Creating new image representations is relatively straightforward and is explained in “Creating New Image
Representation Classes” (page 109).
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
76How an Image Representation Is Chosen
When you tell an NSImage object to draw itself, it searches its list of image representations for the one that
best matches the attributes of the destination device. In determining which image representation to choose,
it follows a set of ordered rules that compare the color space, image resolution, bit depth, and image size to
the corresponding values in the destination device. The rules are applied in the following order:
1. Choose an image representation whose color space most closely matches the color space of the device.
If the device is color, choose a color image representation. If the device is monochrome, choose a gray-scale
image representation.
2. Choose an image representation that has at least as many pixels as the destination rectangle on both the
horizontal and vertical axes. If no image representation matches exactly, choose the one that has more
pixels than the destination.
By default, any image representation with a resolution that’s an integer multiple of the device resolution
is considered a match. If more than one representation matches, NSImage chooses the one that’s closest
to the device resolution. You can force resolution matches to be exact by passing NO to the
setMatchesOnMultipleResolution: method. You can force resolution matches to be exact on only
one dimension by setting the setMatchesOnlyOnBestFittingAxis: property to YES.
Thisrule prefers TIFF and bitmap representations, which have a defined resolution, over EPS representations,
which do not. You can use the setUsesEPSOnResolutionMismatch: method to cause NSImage to
choose an EPS representation in case a resolution match is not possible.
3. Choose a representation whose bit depth (bits per sample) matches the depth of the device. If no
representation matches, choose the one with the highest number of bits per sample.
You can change the order in which these rules are applied using the methods of NSImage. For example, if you
want to invert the first and second rules, pass NO to the setPrefersColorMatch: method. Doing so causes
NSImage to match the resolution before the color space.
If these rules fail to narrow the choice to a single representation—for example, if the NSImage object has two
color TIFF representations with the same resolution and depth—the chosen representation is operating-system
dependent.
Images and Caching
The NSImage class incorporates an internal caching scheme aimed at improving your application’s drawing
performance. This caching scheme is an important part of image management and is enabled by default for
all image objects; however, you can change the caching optionsfor a particular image using the setCacheMode:
method of NSImage. Table 5-2 lists the available caching modes.
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
77Table 5-2 Image caching modes
Mode Description
Use the default caching mode appropriate for the image representation.
This is the default value. For more information, see Table 5-3 (page 78).
NSImageCacheDefault
NSImageCacheAlways Always caches a version of the image.
Creates a cached version of the image if the size set for the image issmaller
than the size of the actual image data.
NSImageCacheBySize
Does not cache the image. The image data is rasterized every time it is
drawn.
NSImageCacheNever
Table 5-3 liststhe behavior of each image representation when its cache mode isset to NSImageCacheDefault.
Table 5-3 Implied cache settings
Image representation Cache behavior
Behaves as if the NSImageCacheBySize setting were in effect. Creates a
cached copy if the bitmap depth does not match the screen depth or if the
bitmap resolution is greater than 72 dpi.
NSBitmapImageRep
NSCachedImageRep Not applicable. This class is used to implement caching.
Behaves as if the NSImageCacheBySize setting were in effect. Creates a
cached copy if the bitmap depth does not match the screen depth or if the
bitmap resolution is greater than 72 dpi.
NSCIImageRep
NSPDFImageRep Behaves as if the NSImageCacheAlways setting were in effect.
NSEPSImageRep Behaves as if the NSImageCacheAlways setting were in effect.
NSCustomImageRep Behaves as if the NSImageCacheAlways setting were in effect.
Behaves as if the NSImageCacheBySize setting were in effect. Creates a
cached copy of the PICT image if it contains a bitmap whose depth does not
match the screen depth or if that bitmap resolution is greater than 72 dpi.
NSPICTImageRep
Caching is a useful step toward preparing an image for display on the screen. When first loaded, the data for
an image representation may not be in a format that can be rendered directly to the screen. For example, PDF
data, when loaded into a PDF image representation, must be rasterized before it can be sent to the graphics
card for display. With caching enabled, a NSPDFImageRep object rasterizes the PDF data before drawing it to
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
78the screen. The image representation then saves the raster data to alleviate the need to recreate it later. If you
disable caching for such images, the rasterization process occurs each time you render the image, which can
lead to a considerable performance penalty.
For bitmap image representations, the decision to cache is dependent on the bitmap image data. If the bitmap’s
colorspace, resolution, and bit depth match the corresponding attributesin the destination device, the bitmap
may be used directly without any caching. If any of these attributes varies, however, the bitmap image
representation may create a cached version instead.
Important: It is important to remember that caching is aimed at improving performance during screen
updates. During printing, Cocoa uses the native image data and resolution whenever possible and uses
cached versions of the image only as a last resort.
If you change the contents of an image representation object directly, you should invoke the recache method
of the owning NSImage object when you are done and want the changes to be reflected on the screen. Cocoa
does not automatically track the changes you make to your image representation objects. Instead, it continues
to use the cached version of your image representation until you explicitly clear that cache using the recache
method.
Caching and Image Data Retention
Because caching can lead to multiple copies of the image data in memory, NSImage usually dismisses the
original image data once a cached copy is created. Dismissing the original image data saves memory and
improves performance and is appropriate in situations where you do not plan on changing the image size or
attributes. If you do plan on changing the image size or attributes, you may want to disable this behavior.
Enabling data retention preventsimage degradation by basing changes on the original image data, as opposed
to the currently cached copy.
To retain image data for a specific image, you must send a setDataRetained: message to the NSImage
object. Preferably, you should send this message immediately after creating the image object. If you send the
message after rendering the image or locking focus on it, Cocoa may need to read the image data more than
once.
Caching Images Separately
To improve performance, most caching of an application’s images occurs in one or more offscreen windows.
These windows act as image repositories for the application and are not shared by other applications. Cocoa
manages them automatically and assigns images to them based on the current image attributes.
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
79By default, Cocoa tries to reduce the number of offscreen windows by putting multiple images into a single
window. For images whose size does not change frequently, this technique is usually faster than storing each
image in its own window. For images whose size does change frequently, it may be better to cache the image
separately by sending a setCachedSeparately: message to the image object.
Image Size and Resolution
Both NSImage and NSImageRep define methods for getting and setting the size of an image. The meaning
of sizes can differ for each type of object, however. For NSImage, the size is always specified in units of the
user coordinate space. Thus, an image that is 72 by 72 points is always rendered in a 1-inch square. For
NSImageRep, the size is generally tied to the size of the native or cached bitmap. For resolution-independent
image representations, a cached bitmap is created whose size matches that returned by NSImage. For true
bitmap images, however, the size is equal to the width and height (in pixels) of the bitmap image.
If you create your image from a data object or file, the NSImage object takes its image size information from
the provided data. For example, with EPS data, the size is taken from the bounding rectangle, whereas with
TIFF data, the size is taken from the ImageLength and ImageWidth fields. If you create a blank image, you
must set the image size yourself when you initialize the NSImage object.
You can change the size of an image at any time using the setSize: method of either NSImage or
NSImageRep. The size returned by the NSImage version of the method representsthe dimensions of the image
in the user coordinate space. Changing this value therefore changes the size of the image as it is drawn in one
of your views. This change typically affects only the cached copy of the image data, if one exists. Changing the
size of an image representation object changes the actual number of bits used to hold the image data. This
change primarily affects bitmap images, and can result in a loss of data for your in-memory copy of the image.
If the size of the data in an image representation is smaller than the rectangle into which it will be rendered,
the image must be scaled to fit the target rectangle. For resolution-independent images, such as PDF images,
scaling is less of an issue. For bitmap images, however, pixel values in the bitmap must be interpolated to fill
in the extra space. Table 5-4 lists the available interpolation settings.
Table 5-4 Image interpolation constants
Interpolation constant Description
NSImageInterpolationDefault Use the context’s default interpolation.
NSImageInterpolationNone No interpolation.
NSImageInterpolationLow Fast, low-quality interpolation.
NSImageInterpolationHigh Slower, higher-quality interpolation.
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
80The preceding interpolation settings control both the quality and the speed of the interpolation algorithm. To
change the currentinterpolation setting, use the setImageInterpolation:method of NSGraphicsContext.
Note: Scaling affectsthe in-memory copy of image data only. It does not change data stored on-disk.
With data retention disabled in an image, scaling the image multiple times can seriously degrade the resulting
image quality. Making an image smaller through scaling is a lossy operation. If you subsequently make the
image larger again by scaling, the results are based on the scaled-down version of the image.
If you need several differentsizes of an image, you might want to create multiple image representation objects,
one for each size, to avoid any lossy behavior. Alternatively, you can use the setDataRetained: method to
ensure that the caching system has access to the original image data.
Image Coordinate Systems
Like views, NSImage objects use their own coordinate system to manage their content, which in this case is
the image data itself. This internal coordinate system is independent of any containing views into which the
image is drawn. Although you might think understanding this coordinate system is important for drawing
images in your views, it actually is not. The purpose of the internal coordinate system is to orient the image
data itself. As a result, the only time you should ever need to know about this internal coordinate system is
when you create a new image by locking focus on an NSImage object and drawing into it.
Image objects have two possible orientations: standard and flipped. When you create a new, empty NSImage
object, you can set the orientation based on how you want to draw the image data. By default, images use
the standard Cartesian (unflipped) coordinate system, but you can force them to use a flipped coordinate
system by calling the setFlipped: method of NSImage prior to drawing. You must always set the image
orientation before you lock focus on the image and start drawing though. Changing the orientation of the
coordinate system after a lockFocus call has no effect. In addition, calling the setFlipped: method after
you unlock focus again may not have the desired results and should be avoided.
When drawing images in your view, you can think of the image as just a rectangle with some data in it.
Regardless of the orientation of itsinternal coordinate system, you always place an image relative to the current
view’s coordinate system. Figure 5-1 shows two images drawn in an unflipped view. The code used to draw
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
81each image uses the coordinate points shown in the figure, which are in the view’s (unflipped) coordinate
system. Because the first image uses a flipped coordinate system internally, however, it drawsits content upside
down.
Figure 5-1 Image orientation in an unflipped view
Drawing Versus Compositing
The NSImage class offers different groups of methods to facilitate drawing your images to the current context.
The two main groups of methods can be generally categorized asthe “drawing” versus“compositing” methods.
There are three “drawing” methods of NSImage:
● drawAtPoint:fromRect:operation:fraction:
● drawInRect:fromRect:operation:fraction:
● drawRepresentation:inRect:
The drawing methods are among the most commonly-used methods of NSImage because of their basic safety.
Images are typically rendered in offscreen windows and then copied to the screen as needed. In some cases,
several images may be composited into the same window for efficiency reasons. The draw methods use extra
safety checking to ensure that only the contents of the current image are ever drawn in one of your views. The
same is not true of compositing methods, of which there are the following:
● compositeToPoint:operation:
● compositeToPoint:fromRect:operation:
● compositeToPoint:fromRect:operation:fraction:
● compositeToPoint:operation:fraction:
These methods can be more efficient than the drawing methods because they perform fewer checks on the
image bounds. These methods do have other behaviors that you need to understand, however. The most
important behavior is that the compositing methods undo any scale or rotation factors (but not translation
Images
Image Basics
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
82factors) applied to the CTM prior to drawing. If you are drawing in a flipped view or manually applied scaling
or rotation valuesto the current context, these methods will ignore those transformations. Although this might
seem like a problem, it actually can be a very useful tool. For example, if your program is scaling a graphic
element, you might want to add a scale value to your transform to do the scaling (at least temporarily). If your
element usesimage-based selection handles, you could use the compositing methodsto prevent those handles
from being scaled along with the rest of your graphic element.
The other thing to remember about the compositing methods is that none of them allow you to scale your
image to a target rectangle. Cocoa composites the entire image (or designated portion thereof) bit-for-bit to
the specified location. This is in contrast to the drawInRect:fromRect:operation:fraction: method,
which lets you scale all or part of your image to the designated target rectangle in your view.
Note: The dissolveToPoint:fraction: and dissolveToPoint:fromRect:fraction:
methods behave in a similar manner asthe corresponding compositing methods. Their use is generally
more limited though and better support for dissolving images is available through Core Image.
Supported Image File Formats
Cocoa supports many common image formats internally and can import image data from many more formats
through the use of the Image I/O framework (ImageIO.framework).
Basic Formats
Table 5-5 lists the formats supported natively by Cocoa. (Uppercase versions of the filename extensions are
also recognized.)
Table 5-5 Cocoa supported file formats
Format Filename extensions UTI
Portable Document Format (PDF) .pdf com.adobe.pdf
.eps, .epi, .epsf,
.epsi, .ps
Encapsulated PostScript (EPS)
Tagged Image File Format (TIFF) .tiff, .tif public.tiff
public.jpeg,
public.jpeg-2000
Joint Photographic Experts Group .jpg, .jpeg, .jpe
(JPEG), JPEG-2000
Graphic Interchange Format (GIF) .gif com.compuserve.gif
Images
Supported Image File Formats
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
83Format Filename extensions UTI
Portable Network Graphic (PNG) .png public.png
Macintosh Picture Format (PICT) .pict, .pct, .pic com.apple.pict
Windows Bitmap Format (DIB) .bmp, .BMPf com.microsoft.bmp
Windows Icon Format .ico com.microsoft.ico
Icon File Format .icns com.apple.icns
TIFF Compression
TIFF images can be read from compressed data, aslong asthe compression algorithm is one of the fourschemes
described in Table 5-6.
Table 5-6 TIFF compression settings
Compression Description
Compresses and decompresses without information loss, achieving compression ratios
up to 5:1. It may be somewhat slower to compress and decompress than the PackBits
scheme.
LZW
Compresses and decompresses without information loss, but may not achieve the
same compression ratios as LZW.
PackBits
JPEG JPEG compression is no longer supported in TIFF files, and this factor is ignored.
Compresses and decompresses 1 bit gray-scale images using international fax
compression standards CCITT3 and CCITT4.
CCITTFAX
An NSImage object can also produce compressed TIFF data using any of these schemes. To get the TIFF data,
use the TIFFRepresentationUsingCompression:factor: method of NSImage.
Support for Other File Formats
In OS X v10.4 and later, NSImage supports many additional file formats using the Image I/O framework. To get
a complete list of supported filename extensions, use the imageFileTypes class method of NSImage. The
list of supported file formats continues to grow but Table 5-7 lists some of the more common formats that can
be imported.
Images
Supported Image File Formats
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
84Table 5-7 Additional formats supported by Cocoa
Type Filename extension
Adobe RAW .dng
Canon 2 RAW .cr2
Canon RAW .crw
FlashPix .fpx, .fpix
Fuji RAW .raf
Kodak RAW .dcr
MacPaint .ptng, .pnt, .mac
Minolta RAW .mrw
Nikon RAW .nef
Olympus RAW .orf
OpenEXR .exr
Photoshop .psd
QuickTime Import Format .qti, .qtif
Radiance .hdr
SGI .sgi
Sony RAW .srf
Targa .targa, .tga
Windows Cursor .cur
XWindow bitmap .xbm
The Image I/O framework is part of Quartz, although the actual framework is part of the Application Services
framework. Image I/O handles the importing and exporting of many file formats. To use Quartz directly, you
read image data using the CGImageSourceRef opaque type and write using the CGImageDestinationRef
type. For more information on using the Image I/O framework to read and write images, see CGImageSource
Reference and CGImageDestination Reference .
Images
Supported Image File Formats
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
85Guidelines for Using Images
Here are some guidelines to help you work with images more effectively:
● Use the NSImage interface whenever possible. The goal of NSImage is to simplify your interactions with
image data. Working directly with image representations should be done only as needed.
● Treat NSImage and its image representations as immutable objects. The goal of NSImage is to provide
an efficient way to display images on the target canvas. Avoid manipulating the data of an image
representation directly, especially if there are alternatives to manipulating the data, such as compositing
the image and some other content into a new image object.
● For screen-based drawing, it is best to use the built-in caching mechanism of NSImage. Using an
NSCachedImageRep object is more efficient than an NSBitmapImageRep object with the same data.
Cached image representations store image data using a CGImageRef object, which can be stored directly
on the video card by Quartz.
● There is little benefit to storing multiple representations of the same image (possibly at different sizes) in
a single NSImage. Modern hardware is powerful enough to resize and scale images quickly. The only
reason to considerstoring multiple representationsisif each of those representations contains a customized
version of the image or if your app supports high-resolution displays.
●
If caching is enabled and you modify an image representation object directly, be sure to invoke the
recache method of the owning NSImage object. Cocoa relies on cached content wherever possible to
improve performance and does not automatically recreate its caches when you modify image
representations. You must tell the image object to recreate its caches explicitly.
● Avoid recreating art that is already provided by the system. OS X makes several standard pieces of artwork
available for inclusion in your own interfaces. This artwork ranges from standard icons to other elements
you can integrate into your controls. You load standard images using the imageNamed: method. For a
list of standard artwork, see the constants section in NSImage Class Reference .
●
If your app supports high resolution displays, follow the guidelines in High Resolution Guidelines for OS X
for providing and naming standard- and high-resolution versions of image resources. That document also
outlines additions and changes to the NSImage class as of OS X v10.7.4.
OS X defines several technologies for working with images. Although the NSImage class is a good general
purpose class for creating, manipulating, and drawing images, there may be times when it might be easier or
more efficient to use other imaging technologies. For example, rather than manually dissolving from one image
to another by drawing partially transparent versions of each image over time, it would be more efficient to
use Core Image to perform the dissolve operation for you. For information about other image technologies,
and when you might use them, see “Choosing the Right Imaging Technology” (page 169).
Images
Guidelines for Using Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
86Creating NSImage Objects
Before you can draw an image, you have to create or load the image data. Cocoa supports several techniques
for creating new images and loading existing images.
Loading an Existing Image
For existing images, you can load the image directly from a file or URL using the methods of NSImage. When
you open an image file, NSImage automatically creates an image representation that best matches the type
of data in that file. Cocoa supports numerous file formats internally. In OS X v10.4 and later, Cocoa supports
even more file formats using the Image I/O framework. For information on supported file types,see “Supported
Image File Formats” (page 83).
The following example shows how to load an existing image from a file. It is important to remember that
images loaded from an existing file are intended primarily for rendering. If you want to manipulate the data
directly, copy it to an offscreen window or other local data structure and manipulate it there.
NSString* imageName = [[NSBundle mainBundle]
pathForResource:@"image1" ofType:@"JPG"];
NSImage* tempImage = [[NSImage alloc] initWithContentsOfFile:imageName];
Loading a Named Image
For frequently used images, you can use the Application Kit’s named image registry to load and store them.
This registry provides a fast and convenient way to retrieve images without creating a new NSImage object
each time. You can add images to this registry explicitly or you can use the registry itself to load known system
or application-specific images, such as the following:
● System images stored in the Resources directory of the Application Kit framework
● Your application’s icon or other images located in the Resources directory of your main bundle.
To retrieve images from the registry, you use the imageNamed: class method of NSImage. This method looks
in the registry for an image associated with the name you provide. If none is found, it looks for the image
among the Application Kit's shared resources. After that, it looks for a file in the Resources directory of your
application bundle, and finally it checks the Application Kit bundle. If it finds an image file, it loads the image,
adds it to the registry, and returns the corresponding NSImage object. As long as the corresponding image
object is retained somewhere by your code, subsequent attempts to retrieve the same image file return the
already-loaded NSImage object.
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
87To retrieve your application icon, ask for an image with the constant, NSImageNameApplicationIcon (on
versions of OS X before v10.6, you can use the string @"NSApplicationIcon"). Your application's custom
icon is returned, if it has one; otherwise, Cocoa returns the generic application icon provided by the system.
For a list of image names you can use to load other standard system images, see the constants section in
NSImage Class Reference .
In addition to loading existing image files, you can also add images to the registry explicitly by sending a
setName: message to an NSImage object. The setName: method adds the image to the registry under the
designated name. You might use this method in cases where the image was created dynamically or is not
located in your application bundle.
Note: When adding images to the registry explicitly, choose a name that does not match the name
of any image in your application bundle. If you choose a name that is used by a bundle resource,
the explicitly added image supersedesthat resource. You can still load the resource using the methods
of NSBundle, however.
Drawing to an Image by Locking Focus
It is possible to create images programmatically by locking focus on an NSImage object and drawing other
images or paths into the image context. This technique is most useful for creating images that you intend to
render to the screen, although you can also save the resulting image data to a file.
Listing 5-1 shows you how to create a new empty image and configure it for drawing. When creating a blank
image, you mustspecify the size of the new image in pixels. If you lock focus on an image that contains existing
content, the new content is composited with the old content. When drawing, you can use any routines that
you would normally use when drawing to a view.
Listing 5-1 Drawing to an image
NSImage* anImage = [[NSImage alloc] initWithSize:NSMakeSize(100.0, 100.0)];
[anImage lockFocus];
// Do your drawing here...
[anImage unlockFocus];
// Draw the image in the current context.
[anImage drawAtPoint:NSMakePoint(0.0, 0.0)
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
88fromRect: NSMakeRect(0.0, 0.0, 100.0, 100.0)
operation: NSCompositeSourceOver
fraction: 1.0];
Drawing to an image creates an NSCachedImageRep object or uses an existing cached image representation,
if one exists. Even when you use the lockFocusOnRepresentation: method to lock onto a specific image
representation, you do not lock onto the representation itself. Instead, you lock onto the cached offscreen
window associated with that image representation. This behavior might seem confusing but reinforces the
notion of the immutability of images and their image representations.
Images and their representations are considered immutable for efficiency and safety reasons. If you consider
the image files stored in your application bundle, would you really want to make permanent changes to the
original image? Rather than change the original image data, NSImage and its image representations modify
a copy of that data. Modifying a cached copy of the data is also more efficient forscreen-based drawing because
the data is already in a format ready for display on the screen.
Drawing Offscreen Images Using a Block-Based Drawing Method to Support High
Resolution Displays
If your app uses the lockFocus and unlockFocus methods of the NSImage class for offscreen drawing,
consider using the method imageWithSize:flipped:drawingHandler: instead (available in OS X v10.8).
If you use the lock focus methodsfor drawing, you can get unexpected results—either you’ll get a low resolution
NSImage object that looks incorrect when drawn, or you’ll get a 2x image that has more pixels in its bitmap
than you are expecting.
Using the imageWithSize:flipped:drawingHandler: method ensures you’ll get correct results under
standard and high resolution. The drawing handler is a block that can be invoked whenever the image is drawn
to, and on whatever thread the drawing occurs. You should make sure that any state you access within the
block is done in a thread-safe manner.
The code in the block should be the same code that you would use between the lockFocus and unlockFocus
methods.
Creating a Bitmap
There are a few different ways to create bitmaps in Cocoa. Some of these techniques are more convenient
than others and some may not be available in all versions of OS X, so you should consider each one carefully.
The following list summarizes the most common techniques and the situations in which you might use them:
● To create a bitmap from the contents of an existing CIImage object (in OS X v10.5 and later), use the
initWithCIImage: method of NSBitmapImageRep.
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
89● To create a bitmap from the contents of a Quartz image (in OS X v10.5 and later), use the
initWithCGImage: method of NSBitmapImageRep. When initializing bitmaps using this method, you
should treat the returned bitmap as a read-only object. In addition, you should avoid accessing the bitmap
data directly, as doing so requires the unpacking of the CGImageRef data into a separate set of buffers.
● To capture the contents of an existing view or image, use one of the following techniques:
● Lock focus on the desired object and use the initWithFocusedViewRect: method of
NSBitmapImageRep.
●
In OS X v10.4 and later, use the bitmapImageRepForCachingDisplayInRect: and
cacheDisplayInRect:toBitmapImageRep:methods of NSView. The firstmethod creates a bitmap
image representation suitable for use in capturing the view's contents while the second draws the
view contents to the bitmap. You can reuse the bitmap image representation object to update the
view contents periodically, as long as you remember to clear the old bitmap before capturing a new
one.
● To draw directly into a bitmap, create a new NSBitmapImageRep object with the parameters you want
and use the graphicsContextWithBitmapImageRep: method of NSGraphicsContext to create a
drawing context. Make the new context the current context and draw. This technique is available only in
OS X v10.4 and later.
Alternatively, you can create an NSImage object (or an offscreen window), draw into it, and then capture
the image contents. This technique is supported in all versions of OS X.
● To create the bitmap bit-by-bit, create a new NSBitmapImageRep object with the parameters you want
and manipulate the pixels directly. You can use the bitmapData method to get the raw pixel buffer.
NSBitmapImageRep also defines methods for getting and setting individual pixel values. This technique
is the most labor intensive but gives you the most control over the bitmap contents. For example, you
might use it if you want to decode the raw image data yourself and transfer it to the bitmap image
representation.
The sections that follow provide examples on how to use the first two techniques from the preceding list. For
information on how to manipulate a bitmap, see NSBitmapImageRep Class Reference .
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
90Important: In many operating systems, offscreen bitmaps are used to buffer the actual content of a view
or window. In OS X, you should generally not use offscreen bitmaps in this way. Most OS X windows are
already double-buffered to prevent rendering artifacts caused by drawing during a refresh cycle. Adding
your own offscreen bitmap would result in your window being triple-buffered, which is a waste of memory.
Capturing the Contents of a View or Image
A simple way to create a bitmap is to capture the contents of an existing view or image. When capturing a
view, the view can either belong to an onscreen window or be completely detached and not onscreen at all.
When capturing an image, Cocoa chooses the image representation that provides the best match for your
target bitmap.
Before attempting to capture the contents of a view, you should consider invoking the view’s canDraw method
to see if the view should be drawn. Cocoa views return NO from this method in situations where the view is
currently hidden or not associated with a valid window. If you are trying to capture the current state of a view,
you might use the canDraw method to prevent your code from capturing the view when it is hidden.
Once you have your view or image, lock focus on it and use the initWithFocusedViewRect: method of
NSBitmapImageRep to capture the contents. When using this method, you specify the exact rectangle you
want to capture from the view or image. Thus, you can capture all of the contents or only a portion; you cannot
scale the content you capture. The initWithFocusedViewRect: method captures the bits exactly as they
appear in the focused image or view.
Listing 5-2 shows how to create a bitmap representation from an existing image. The example gets the image
to capture from a custom routine, locks focus on it, and creates the NSBitmapImageRep object. Your own
implementation would need to replace the call to myGetCurrentImage with the code to create or get the
image used by your program.
Listing 5-2 Capturing the contents of an existing image
NSImage* image = [self myGetCurrentImage];
NSSize size = [image size];
[image lockFocus];
NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:
NSMakeRect(0,0,size.width,size.height)];
[image unlockFocus];
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
91To capture the content of an onscreen view, you would use code very much like the preceding example. After
locking focus on the view, you would create your NSBitmapImageRep object using the
initWithFocusedViewRect: method.
To capture the content of a detached (offscreen) view, you must create an offscreen window for the view
before you try to capture its contents. The window object provides a backing buffer in which to hold the view’s
rendered content. As long as you do not order the window onto the screen, the origin you specify for your
window does not really matter. The example in Listing 5-3 uses large negative values for the origin coordinates
(just to make sure the window is not visible) but could just as easily use the coordinate (0, 0).
Listing 5-3 Drawing to an offscreen window
NSRect offscreenRect = NSMakeRect(-10000.0, -10000.0,
windowSize.width, windowSize.height);
NSWindow* offscreenWindow = [[NSWindow alloc]
initWithContentRect:offscreenRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreRetained
defer:NO];
[offscreenWindow setContentView:myView];
[[offscreenWindow contentView] display]; // Draw to the backing buffer
// Create the NSBitmapImageRep
[[offscreenWindow contentView] lockFocus];
NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:
NSMakeRect(0, 0, windowSize.width, windowSize.height)];
// Clean up and delete the window, which is no longer needed.
[[offscreenWindow contentView] unlockFocus];
[offscreenWindow release];
Drawing Directly to a Bitmap
In OS X v10.4 and later, it is possible to create a bitmap image representation object and draw to it directly.
This technique is simple and does not require the creation of any extraneous objects, such as an image or
window. If your code needs to run in earlier versions of OS X, however, you cannot use this technique.
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
92Listing 5-4, creates a new NSBitmapImageRep object with the desired bit depth, resolution, and color space.
It then creates a new graphics context object using the bitmap and makes that context the current context.
Listing 5-4 Drawing directly to a bitmap
NSRect offscreenRect = NSMakeRect(0.0, 0.0, 500.0, 500.0);
NSBitmapImageRep* offscreenRep = nil;
offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
pixelsWide:offscreenRect.size.width
pixelsHigh:offscreenRect.size.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:0
bytesPerRow:(4 * offscreenRect.size.width)
bitsPerPixel:32];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext
graphicsContextWithBitmapImageRep:offscreenRep]];
// Draw your content...
[NSGraphicsContext restoreGraphicsState];
Once drawing is complete, you can add the bitmap image representation object to an NSImage object and
display it like any other image. You can use this image representation object as a texture in your OpenGL code
or examine the bits of the bitmap using the methods of NSBitmapImageRep.
Creating a PDF or EPS Image Representation
The process for creating an image representation for PDF or EPS data is the same for both. In both cases, you
use a custom NSView object together with the Cocoa printing system to generate the desired data. From the
generated data, you then create an image representation of the desired type.
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
93The NSView class defines two convenience methods for generating data based on the contents of the view:
● For PDF data, use the dataWithPDFInsideRect: method of NSView.
● For EPS data, use the dataWithEPSInsideRect: method of NSView.
When you send one of these messages to your view, Cocoa launches the printing system, which drives the
data generation process. The printing system handles most of the data generation process,sending appropriate
messages to your view object as needed. For example, Cocoa sends a drawRect: message to your view for
each page that needs to be drawn. The printing system also invokes other methods to compute page ranges
and boundaries.
Note: The NSView class provides a default pagination scheme. To provide a custom scheme, your
view must override the knowsPageRange: and rectForPage: methods at a minimum. For more
information about printing and pagination, see Printing Programming Guide for OS X .
After the printing system finishes, the code that called either dataWithPDFInsideRect: or
dataWithEPSInsideRect: receives an NSData object with the PDF or EPS data. You must then pass this
object to the imageRepWithData: method of either NSEPSImageRep or NSPDFImageRep to initialize a new
image representation object, which you can then add to your NSImage object.
Listing 5-5 shows the basic steps for creating a PDF image from some view content. The view itself must be
one that knows how to draw the desired content. This can be a detached view designed solely for drawing
the desired content with any desired pagination, or it could be an existing view in one of your windows.
Listing 5-5 Creating PDF data from a view
MyPDFView* myView = GetMyPDFRenderView();
NSRect viewBounds = [myView bounds];
NSData* theData = [myView dataWithPDFInsideRect:viewBounds];
NSPDFImageRep* pdfRep = [NSPDFImageRep imageRepWithData:theData];
// Create a new image to hold the PDF representation.
NSImage* pdfImage = [[NSImage alloc] initWithSize:viewBounds.size];
[pdfImage addRepresentation:pdfRep];
Images
Creating NSImage Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
94If you choose to use an existing onscreen view, your view’s drawing code should distinguish between content
drawn for the screen or for the printing system and adjust content accordingly. Use the
currentContextDrawingToScreen class method or the isDrawingToScreen instance method of
NSGraphicsContext to determine whether the current context is targeted for the screen or a print-based
canvas. These methods return NO for operations that generate PDF or EPS data.
Important: When drawing in a printing context, the only supported compositing operators are
NSCompositeCopy and NSCompositeSourceOver. If you need to render content using any other operators,
you must composite them to an image or offscreen window first and then render the resulting image to
the printing context using one of the supported operators.
Using a Quartz Image to Create an NSImage
The NSImage class does not provide any direct means for wrapping data from a Quartz image object. If you
have a CGImageRef object, the simplest way to create a corresponding Cocoa image is to lock focus on an
NSImage object and draw yourQuartz image using the CGContextDrawImage function. The basic techniques
for how to do this are covered in “Drawing to an Image by Locking Focus” (page 88).
Working with Images
Once you have an image, there are many ways you can use it. The simplest thing you can do is draw it into a
view as part of your program’s user interface. You can also process the image further by modifying it in any
number of ways. The following sections show you how to perform several common tasks associated with
images.
Drawing Images into a View
The NSImage class defines several methods for drawing an image into the current context. The two most
commonly used methods are:
● drawAtPoint:fromRect:operation:fraction:
● drawInRect:fromRect:operation:fraction:
These methods offer a simple interface for rendering your images, but more importantly, they ensure that only
your image content is drawn. Other methods, such as the compositeToPoint:operation: method and its
variants, are fast at drawing images but they do not check the image’s boundaries before drawing. If the
drawing rectangle strays outside of the image bounds, it is possible to draw content not belonging to your
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
95image. If the image resides on a shared offscreen window, which many do, it is even possible to draw portions
of other images. For more information about the differences between these methods, see “Drawing Versus
Compositing” (page 82).
With one exception, all of the drawing and compositing methods choose the image representation that is best
suited for the target canvas—see “How an Image Representation Is Chosen” (page 77). The one exception is
the drawRepresentation:inRect: method, which uses the image representation object you specify. For
more information about the use of these methods, see the NSImage reference.
Images support the same set of compositing options as other Cocoa content, with the same results. For a
complete list of compositing options and an illustration of their effects,see “Setting Compositing Options” (page
32).
Drawing Resizable Textures Using Images
If you are implementing a resizable custom control and want the control to have a textured background that
does not distort as the control is resized, you would typically break up the background portion into several
different images and composite them together. Although some of the images would contain fixed size content,
others would need to be designed to present a smooth texture even after being resized or tiled. When it comes
time to draw the images, however, you should avoid doing the drawing yourself. Instead, you should use the
following AppKit functions, which were introduced in OS X v10.5:
● NSDrawThreePartImage
● NSDrawNinePartImage
Drawing multipart images cleanly on high-resolution screens can be very challenging. If you are not careful
about aligning images correctly on integral boundaries, the resulting texture might contain pixel cracks or
other visual artifacts. The AppKit functionstake into account all of the factorsrequired to draw multipart images
correctly in any situation, including situations where resolution independence scale factors other than 1.0 are
in use.
Figure 5-2 shows how you assemble a three-part image for a horizontally resizable control. The two end caps
are fixed size images that provide the needed decoration for the edges of the background. The center fill
portion then resizes appropriately to fit the bounding rectangle you pass into the NSDrawThreePartImage
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
96function. (If you wanted the control to be resizable in the vertical direction, you would stack these images
vertically instead of horizontally.) After drawing the background with this function, you would then layer any
additional content on top of the background as needed.
Figure 5-2 Drawing a three-part image
Figure 5-3 shows you how to assemble a nine-part image for a control that can be resized both vertically and
horizontally. In this case, the size of the corner pieces stays fixed but the five remaining fill images vary in size
to fit the current bounding rectangle.
Figure 5-3 Drawing a nine-part image
For more information about these functions, see their descriptions in Application Kit Functions Reference .
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
97Creating an OpenGL Texture
In OpenGL, a texture is one way to paint the surface of an object. For complex or photorealistic surfaces, it may
be easier to apply a texture than render the same content using primitive shapes. Almost any view or image
in Cocoa can be used to create an OpenGL texture. From a view or image, you create a bitmap image
representation object (as described in “Capturing the Contents of a View or Image” (page 91)) and then use
that object to create your texture.
Listing 5-6 shows a self-contained method for creating a texture from an NSImage object. After creating the
NSBitmapImageRep object, this method configures some texture-related parameters, creates a new texture
object, and then associates the bitmap data with that object. This method handles 24-bit RGB and 32-bit RGBA
images, but you could readily modify it to support other image formats. You must pass in a pointer to a valid
GLuint variable for texName but the value stored in that parameter can be 0. If you specify a nonzero value,
your identifier is associated with the texture object and can be used to identify the texture later; otherwise, an
identifier is returned to you in the texName parameter.
Listing 5-6 Creating an OpenGL texture from an image
- (void)textureFromImage:(NSImage*)theImg textureName:(GLuint*)texName
{
NSBitmapImageRep* bitmap = [NSBitmapImageRep alloc];
int samplesPerPixel = 0;
NSSize imgSize = [theImg size];
[theImg lockFocus];
[bitmap initWithFocusedViewRect:
NSMakeRect(0.0, 0.0, imgSize.width, imgSize.height)];
[theImg unlockFocus];
// Set proper unpacking row length for bitmap.
glPixelStorei(GL_UNPACK_ROW_LENGTH, [bitmap pixelsWide]);
// Set byte aligned unpacking (needed for 3 byte per pixel bitmaps).
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
// Generate a new texture name if one was not provided.
if (*texName == 0)
glGenTextures (1, texName);
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
98glBindTexture (GL_TEXTURE_RECTANGLE_EXT, *texName);
// Non-mipmap filtering (redundant for texture_rectangle).
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
samplesPerPixel = [bitmap samplesPerPixel];
// Nonplanar, RGB 24 bit bitmap, or RGBA 32 bit bitmap.
if(![bitmap isPlanar] &&
(samplesPerPixel == 3 || samplesPerPixel == 4))
{
glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0,
samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8,
[bitmap pixelsWide],
[bitmap pixelsHigh],
0,
samplesPerPixel == 4 ? GL_RGBA : GL_RGB,
GL_UNSIGNED_BYTE,
[bitmap bitmapData]);
}
else
{
// Handle other bitmap formats.
}
// Clean up.
[bitmap release];
}
In the preceding code, there are some additional points worth mentioning:
● GL_TEXTURE_RECTANGLE_EXT is used for non–power-of-two texture support, which is not supported
on the Rage 128 hardware.
● The gluScaleImage() function can be used to scale non-PoT texturesinto PoT dimensionsfor hardware
that doesn't support GL_TEXTURE_RECTANGLE_EXT.
● When you call this method, the current context must be a valid OpenGL context. For more information
about OpenGL graphics contexts, see “Using OpenGL in Your Application” (page 165).
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
99● Upon completion, the texture is bound to the value in texName. If you specified 0 for the texName
parameter, a new texture ID is generated for you and returned in texName.
For more information on Apple's support for OpenGL, see OpenGL Programming Guide for Mac .
Applying Core Image Filters
In OS X v10.4 and later, Core Image filters are a fast and efficient way to modify an image without changing
the image itself. Core Image filters use graphics acceleration to apply real-time effects such as Gaussian blurs,
distortions, and color corrections to an image. Because the filters are applied when content is composited to
the screen, they do not modify the actual image data.
Core Image filters operate on CIImage objects. If you have an existing CIImage object, you can simply apply
any desired filtersto it and use it to create an NSCIImageRep object. You can then add thisimage representation
object to an NSImage object and draw the results in your view. In OS X v10.5 and later, you can also use the
initWithCIImage: method of NSBitmapImageRep to render already-processed images directly to a bitmap
representation.
If you do not already have a CIImage object, you need to create one using your program’s existing content.
The first step is to create a bitmap image representation for the content you want to modify, the process for
which is described in “Creating a Bitmap” (page 89). Once you have an NSBitmapImageRep object, use the
initWithBitmapImageRep: method of CIImage to create a Core Image image object.
For information on how to apply Core Image filters to a CIImage object, see “Using Core Image Filters” in Core
Image Programming Guide .
Getting and Setting Bitmap Properties
Every NSBitmapImageRep object contains a dictionary that defines the bitmap’s associated properties. These
properties identify important information about the bitmap, such as how it was compressed, its color profile
(if any), its current gamma level, its associated EXIF data, and so on. When you create a new NSBitmapImageRep
from an existing image file, many of these properties are set automatically. You can also access and modify
these properties using the valueForProperty: and setProperty:withValue: methods of
NSBitmapImageRep.
For a complete list of properties you can get and set for a bitmap, see NSBitmapImageRep Class Reference .
Converting a Bitmap to a Different Format
The NSBitmapImageRep class provides built-in support for converting bitmap data to severalstandard formats.
To convert bitmap images to other formats, you can use any of the following methods:
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
100● +TIFFRepresentationOfImageRepsInArray:
● +TIFFRepresentationOfImageRepsInArray:usingCompression:factor:
●
-TIFFRepresentation
●
-TIFFRepresentationUsingCompression:factor:
● +representationOfImageRepsInArray:usingType:properties:
●
-representationUsingType:properties:
The first set of methods generate TIFF data for the bitmap. For all other supported formats, you use the
representationOfImageRepsInArray:usingType:properties: and
representationUsingType:properties: methods. These methods support the conversion of bitmap
data to BMP, GIF, JPEG, PNG, and TIFF file formats.
All of the preceding methods return an NSData object with the formatted image data. You can write this data
out to a file or use it to create a newNSBitmapImageRep object.
Associating a Custom Color Profile With an Image
You can associate a custom ColorSync profile with a NSBitmapImageRep object containing pixel data produced
by decoding a TIFF, JPEG, GIF or PNG file. To associate the data with the bitmap image representation, you use
the setProperty:withValue: method of NSBitmapImageRep and the NSImageColorSyncProfileData
property. Listing 5-7 shows an example of how to load the ColorSync data and associate it with a bitmap image
representation.
Listing 5-7 Adding a ColorSync profile to an image
@implementation NSBitmapImageRep (MoreColorMethods)
- (NSBitmapImageRep *) imageRepWithProfileAtPath:(NSString *) pathToProfile
{
id result = [self copy];
// Build an NSData object using the specified ColorSync profile
id profile = [NSData dataWithContentsOfFile: pathToProfile];
// Set the ColorSync profile for the object
[result setProperty:NSImageColorSyncProfileData withValue:profile];
return [result autorelease];
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
101}
@end
In OS X v10.5, it is also possible to associate a custom ICC color profile with an NSBitmapImageRep object.
To do so, you must initialize your NSBitmapImageRep instance using the calibrated RGB colorspace
(NSCalibratedRGBColorSpace). After that, you load the profile and associate the corresponding data object
with the NSImageColorSyncProfileData key exactly as you would for a ColorSync profile.
Converting Between Color Spaces
Cocoa does not provide any direct ways to convert images from one color space to another. Although Cocoa
fully supports color spaces included with existing image files, there is no way to convert image data directly
using NSImage. Instead, you must use a combination of Quartz and Cocoa to convert the image data.
Creating the Target Image
Converting the color space of an existing image requires the use of Quartz to establish a drawing context that
uses the target color space. Once you have a CGContextRef object with the desired color space, you can use
it to configure the Cocoa drawing environment and draw your image.
Listing 5-8 shows you how to create a Quartz bitmap context using a custom colorspace. Thisfunction receives
a CMProfileRef object, which you can get from the ColorSync Manager or from the colorSyncProfile
method of NSColorSpace. It uses the color profile to determine the number of channels in the color space.
Once it knows the total number of channels (including alpha) needed for the bitmap, it creates and returns a
matching bitmap context.
Listing 5-8 Creating a bitmap with a custom color profile
CGContextRef CreateCGBitmapContextWithColorProfile(size_t width,
size_t height,
CMProfileRef profile,
CGImageAlphaInfo alphaInfo)
{
size_t bytesPerRow = 0;
size_t alphaComponent = 0;
// Get the type of the color space.
CMAppleProfileHeader header;
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
102if (noErr != CMGetProfileHeader(profile, &header))
return nil;
// Get the color space info from the profile.
CGColorSpaceRef csRef = CGColorSpaceCreateWithPlatformColorSpace(profile);
if (csRef == NULL)
return NULL;
// Add 1 channel if there is an alpha component.
if (alphaInfo != kCGImageAlphaNone)
alphaComponent = 1;
// Check the major color spaces.
OSType space = header.cm2.dataColorSpace;
switch (space)
{
case cmGrayData:
bytesPerRow = width;
// Quartz doesn’t support alpha for grayscale bitmaps.
alphaInfo = kCGImageAlphaNone;
break;
case cmRGBData:
bytesPerRow = width * (3 + alphaComponent);
break;
case cmCMYKData:
bytesPerRow = width * 4;
// Quartz doesn’t support alpha for CMYK bitmaps.
alphaInfo = kCGImageAlphaNone;
break;
default:
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
103return NULL;
}
// Allocate the memory for the bitmap.
void* bitmapData = malloc(bytesPerRow * height);
CGContextRef theRef = CGBitmapContextCreate(bitmapData, width,
height, 8, bytesPerRow,
csRef, alphaInfo);
// Cleanup if an error occurs; otherwise, the caller is responsible
// for releasing the bitmap data.
if ((!theRef) && bitmapData)
free(bitmapData);
CGColorSpaceRelease(csRef);
return theRef;
}
Once you have a Quartz bitmap context, you can create a new Cocoa graphics context object and use it for
drawing. To create the NSGraphicsContext object, you use the
graphicsContextWithGraphicsPort:flipped: method, which takes a CGContextRef object as a
parameter. You then use the setCurrentContext: method to make it current and begin drawing. When
you are done drawing, you use Quartz to create a CGImageRef object containing the results. Listing 5-9 shows
this process.
Listing 5-9 Converting a bitmap to a different color space
- (CGImageRef) convertBitmapImageRep:(NSBitmapImageRep*)theRep
toColorSpace:(NSColorSpace*)colorspace
{
if (!theRep)
return nil;
// Map the Cocoa constants returned by -bitmapFormat to their
// Quartz equivalents.
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
104CGImageAlphaInfo alphaInfo = GetAlphaInfoFromBitmapImageRep(theRep);
// Get the rest of the image info.
NSSize imageSize = [theRep size];
size_t width = imageSize.width;
size_t height = imageSize.height;
CMProfileRef profile = (CMProfileRef)[colorspace colorSyncProfile];
// Create a new 8-bit bitmap context based on the image info.
CGContextRef cgContext = CreateCGBitmapContextWithColorProfile(width,
height, profile, alphaInfo);
if (cgContext == NULL)
return NULL;
// Create an NSGraphicsContext that draws into the CGContext.
NSGraphicsContext *graphicsContext = [NSGraphicsContext
graphicsContextWithGraphicsPort:cgContext flipped:NO];
// Make the NSGraphicsContext current and draw into it.
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:graphicsContext];
// Create a new image for rendering the original bitmap.
NSImage* theImage = [[[NSImage alloc] initWithSize:imageSize] autorelease];
[theImage addRepresentation:theRep];
// Draw the original image in the Quartz bitmap context.
NSRect imageRect = NSMakeRect(0.0, 0.0, imageSize.width, imageSize.height);
[theImage drawAtPoint:NSMakePoint(0.0, 0.0)
fromRect:imageRect
operation: NSCompositeSourceOver
fraction: 1.0];
[NSGraphicsContext restoreGraphicsState];
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
105// Create a CGImage from the CGContext's contents.
CGImageRef cgImage = CGBitmapContextCreateImage(cgContext);
// Release the context. Note that this does not release the bitmap data.
CGContextRelease(cgContext);
return cgImage;
}
There are two ways to get an NSImage object from a CGImageRef type. In OS X v10.5 and later, you can create
an NSBitmapImageRep object using its initWithCGImage: method and then add that image representation
to an NSImage object. If your code needs to run in versions of OS X v10.4 or earlier, however, you can lock
focus on an NSImage object and use the CGContextDrawImage function to draw the Quartz image into the
image. This latter technique creates a copy of the image data and requires more effort than using the
initWithCGImage: method but is available on all versions of OS X. Listing 5-10 shows a sample method that
demonstrates both approaches but always uses the best approach available for the target platform.
Listing 5-10 Using a CGImageRef object to create an NSImage object
- (NSImage*)imageFromCGImageRef:(CGImageRef)image
{
NSImage* newImage = nil;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
NSBitmapImageRep* newRep = [[NSBitmapImageRep alloc] initWithCGImage:image];
NSSize imageSize;
// Get the image dimensions.
imageSize.height = CGImageGetHeight(image);
imageSize.width = CGImageGetWidth(image);
newImage = [[NSImage alloc] initWithSize:imageSize];
[newImage addRepresentation:newRep];
#else
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
106NSRect imageRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
CGContextRef imageContext = nil;
// Get the image dimensions.
imageRect.size.height = CGImageGetHeight(image);
imageRect.size.width = CGImageGetWidth(image);
// Create a new image to receive the Quartz image data.
newImage = [[NSImage alloc] initWithSize:imageRect.size];
[newImage lockFocus];
// Get the Quartz context and draw.
imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextDrawImage(imageContext, *(CGRect*)&imageRect, image);
[newImage unlockFocus];
#endif
return [newImage autorelease];
}
Using a Custom Color Profile
If you have an existing ICC profile and want to associate that profile with an image, you must do so using the
ColorSync Manager. If you are working with Quartz graphic contexts, you use the ICC profile to obtain the color
space information needed to create a CGImageRef object. You can then use that color space information to
create an appropriate context for rendering your image.
Listing 5-11 shows you how to create a CGColorSpaceRef object from an ICC profile. This code uses several
ColorSync Manager functions to create a CMProfileRef object, from which you can then extract the color
space object. OS X includes several standard ICC profiles in the /System/Library/ColorSync/Profiles/
directory.
Listing 5-11 Creating a color space from a custom color profile
CGColorSpaceRef CreateColorSpaceForProfileAtPath(NSString* path)
{
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
107CMProfileLocation profileLoc;
CMProfileRef profileRef;
CGColorSpaceRef csRef = NULL;
// Specify where the ICC profile data file is located.
profileLoc.locType = cmPathBasedProfile;
strncpy(profileLoc.u.pathLoc.path, [path fileSystemRepresentation], 255);
// Get the ColorSync profile information from the data file.
CMOpenProfile(&profileRef, &profileLoc);
// Use the profile to create the color space object.
csRef = CGColorSpaceCreateWithPlatformColorSpace(profileRef);
CMCloseProfile(profileRef);
return csRef;
}
For more information on ColorSync and its functions, see ColorSync Manager Reference .
Premultiplying Alpha Values for Bitmaps
Although premultiplying alpha values used to be a common way to improve performance when rendering
bitmaps, the technique is not recommended for programsrunning inOS X. Premultiplication involves multiplying
values in the bitmap’s alpha channel with the corresponding pixel values and storing the results back to the
bitmap’s source file. The goal of pre-multiplication is to reduce the number of calculations performed when
the bitmap is composited with other content. In OS X, premultiplication can actually result in more calculations.
In OS X, color correction is integral to the operating system. In order to process colors correctly, ColorSync
needs the original pixel color values. If a bitmap contains premultiplied color values, ColorSync must undo the
premultiplication before it can check the colors. This extra step adds a significant amount of work to the system
because it must be performed every time the colors are checked.
Images
Working with Images
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
108The only reason to consider premultiplication of alpha values for your bitmaps is if your data is already
premultiplied and leaving it that way is beneficial to your program’s data model. Even so, you should do some
performance tests to see if using premultiplied bitmaps hurts your overall application performance. Cocoa
incorporates color management into many parts of the framework. If your code paths use these parts of the
framework, you might find it beneficial to change your model.
Creating New Image Representation Classes
If you want to add support for new image formats or generate images from other types of source information,
you may want to subclass NSImageRep. Although Cocoa supports many image formats directly, and many
more indirectly through the Image IO framework,subclassing NSImageRep gives you control over the handling
of image data while at the same time maintaining a tight integration with the NSImage class. If you decide to
subclass, you should provide implementations for the following methods:
● imageUnfilteredTypes
● canInitWithData:
● initWithData:
● draw
These methods provide the basic interface that the parent NSImageRep class needs to interact with your
subclass. The methods provide information about what image data formats your class supports along with
entry points for initializing your object and drawing the image.
Before your subclass can be used, it must be registered with the Application Kit. You should do this early in
your application’s execution by invoking the registerImageRepClass: class method of NSImageRep.
Registering your class lets Cocoa know that your class exists and that it can handle a specific set of file types.
Yourimplementation ofthe imageUnfilteredTypesmethod should return an array ofUTItypes corresponding
to the image file types your class supports directly.
Another method you should always override is the canInitWithData: method. Once your image
representation class has been identified as handling a particular type of data, Cocoa may notify it when data
of the appropriate type is received. At that time, Cocoa passes a data object to your canInitWithData:
method. Your implementation of this method should examine the data quickly and verify that it can really
handle the format.
Images
Creating New Image Representation Classes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
109Note: If your subclass is capable of reading multiple images from a single file, you should also
implement the imageRepsWithData: method. This method must parse the image data and check
to see if it indeed contains multiple images. For each separate image, you should create an instance
of your subclass and initialize it with the appropriate subset of the image data.
Once your class is chosen to handle the image data, Cocoa looks for an initWithData: method and uses it
to initialize your object with the image data. Your implementation of this method should retain the data and
use it to initialize the object. At some point later, your draw method may be called to render the data in the
current context. Your draw method should render the data at the current origin point and with the current
size and settings specified by the NSImageRep parent class.
Images
Creating New Image Representation Classes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
110Creating an effective and beautiful Mac app often requires the use of many different techniques. Beyond the
basic drawing of paths and images in views, there are other ways to create more complex imagery for your
application. The following sections cover many of the most commonly used techniques supported by Cocoa.
Adding Shadows to Drawn Paths
Cocoa provides support for shadows through the NSShadow class. A shadow mimics a light source cast on the
object, making paths appear as if they’re floating above the surface of the view. Figure 6-1 shows the effect
created by a shadow for a few paths.
Figure 6-1 Shadows cast by rendered paths
A shadow effect consists of horizontal and vertical offset values, a blur value, and the shadow color. These
effects combine to give the illusion that there is a light above the canvas that is shining down on the shapes
below. The offset and blur values effectively determine the position of the light and the height of the shapes
above the canvas.
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
111
Advanced Drawing TechniquesShadow positions always use the base coordinate system of the view, ignoring any transforms you apply to
the shapes in your view. This means that no matter how you manipulate the shapes in a view, the apparent
position of the light generating the shadows never changes. If you want to change the apparent position of
the light, you must change the shadow object attributes and apply the updated shadow object to the current
graphics context before drawing your content.
To create a shadow, you create an NSShadow object and call its methods to set the desired shadow attributes.
If you anticipate one or more paths overlapping each other, you should be sure to choose a color that has an
alpha value; otherwise, shadows that intersect other objects might look flat and ruin the effect. To apply the
shadow, invoke its set method.
Listing 6-1 shows the code used to create the shadow for the paths in Figure 6-1 (page 111). A partially
transparent color is used to allow for overlapping paths and shadows.
Listing 6-1 Adding a shadow to a path
[NSGraphicsContext saveGraphicsState];
// Create the shadow below and to the right of the shape.
NSShadow* theShadow = [[NSShadow alloc] init];
[theShadow setShadowOffset:NSMakeSize(10.0, -10.0)];
[theShadow setShadowBlurRadius:3.0];
// Use a partially transparent color for shapes that overlap.
[theShadow setShadowColor:[[NSColor blackColor]
colorWithAlphaComponent:0.3]];
[theShadow set];
// Draw your custom content here. Anything you draw
// automatically has the shadow effect applied to it.
[NSGraphicsContext restoreGraphicsState];
[theShadow release];
Shadow effects are stored as part of the graphics state, so once set, they affect all subsequent rendering
commands in the current context. This is an important thing to remember because it might force you to think
about the order in which you draw your content. For example, if you set up a shadow, fill a path, and then
Advanced Drawing Techniques
Adding Shadows to Drawn Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
112stroke the same path, you do not get a single shape with an outline, fill color, and shadow. Instead, you get
two shapes—an outline and a fill shape—and two shadows, one for each shape. If you stroke the path after
filling it, the shadow for the stroked path appears on top of the filled shape. In Figure 6-1 (page 111), the desired
effect was achieved by applying the shadow to only the fill shape of each path.
Note: Another way to a single shadow for multiple paths is using a Quartz transparency layer. For
more information about using transparency layers, see Quartz 2D Programming Guide .
Creating Gradient Fills
A gradient fill (also referred to as a shading in Quartz) is a pattern that gradually changes from one color to
another. Unlike the image-based patterns supported by NSColor, a gradient fill does not tile colors to fill the
target shape. Instead, it uses a mathematical function to compute the color at individual points along the
gradient. Because they are mathematical by nature, gradients are resolution independent and scale readily to
any device.
Figure 6-2 shows some simple gradient fill patterns. Gradients a and b show linear gradients filling different
Bezier shapes and aligned along different angles while gradients c and d show radial gradients. In the case of
gradient c, the gradient was set to draw before and after the gradient’s starting and ending locations, thus
Advanced Drawing Techniques
Creating Gradient Fills
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
113creating both a white circle in the very center of the gradient and a black border surrounding the gradient.
For gradient d, the center points of the circles used to draw the gradient are offset, creating a different sort of
shading effect.
Figure 6-2 Different types of gradients
In OS X v10.5 and later, Cocoa provides support for drawing gradients using the NSGradient class. If your
software runs on earlier versions of OS X, you must use Quartz or Core Image to perform gradient fills.
Using the NSGradient Class
In OS X v10.5 and later, you can use the NSGradient class to create complex gradient fill patterns without
having to write your own color computation function. Gradient objects are immutable objects that store
information about the colors in the gradient and provide an interface for drawing those colors to the current
context. When you create an NSGradient object, you specify one or more NSColor objects and a set of
optional location parameters. During drawing, the gradient object uses this information to compute the color
transitions for the gradient.
Advanced Drawing Techniques
Creating Gradient Fills
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
114The NSGradient class supports both high-level and primitive drawing methods. The high-level methods
provide a simple interface for drawing gradients as a fill pattern for a Bezier path or rectangle. If you need
additional control over the final shape and appearance of the gradient fill, you can set up the clipping path
your self and use the primitive drawing methods of NSGradient to do your drawing.
Configuring the Colors of a Gradient Object
The NSGradient class uses color stops to determine the position of color changes in its gradient fill. A color
stop is a combination of an NSColor object and a floating-point number in the range 0.0 to 1.0. The floating
point number represents the relative position of the associated color along the drawing axis of the gradient,
which can be either radial or axial.
By definition, gradients must have at least two color stops. Typically, these color stops represent the start and
end points of the gradient. Although the start point is often located at 0.0 and the end point at 1.0, that may
not always be the case. You can position the start and end points anywhere along the gradient’s drawing axis.
As it creates the gradient, the gradient object fills the area prior to the start point with the start color and
similarly fills the area after the end point with the end color.
You can use the same gradient object to draw multiple gradient fills and you can freely mix the creation of
radial and axial gradients using the same gradient object. Although you configure the colors of a gradient
when you create the gradient object, you configure the drawing axis of the gradient only when you go to draw
it. The NSGradient class definesthe following methodsfor configuring the colors and colorstops of a gradient.
● initWithStartingColor:endingColor:
● initWithColors:
● initWithColorsAndLocations:
● initWithColors:atLocations:colorSpace:
Although you cannot change the colors of a gradient object after you initialize it, you can get information
about the colors it contains using accessor methods. The numberOfColorStops method returns the number
of colors that the gradient uses to draw itself and the getColor:location:atIndex: method retrieves the
colorstop information for each of those colors. If you want to know what color would be drawn for the gradient
in between two color stops, you can use the interpolatedColorAtLocation: method to get it.
Drawing to a High-Level Path
The NSGradient class defines several convenience methods for drawing both radial and axial gradients:
● drawInRect:angle:
● drawInRect:relativeCenterPosition:
● drawInBezierPath:angle:
Advanced Drawing Techniques
Creating Gradient Fills
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
115● drawInBezierPath:relativeCenterPosition:
These convenience methods are easily identified by the fact that they take either an NSBezierPath or a
rectangle as their first parameter. This parameter is used as a clipping region for the gradient when it is drawn.
You might use these methods to draw a gradient fill inside an existing shape in your interface.
Listing 6-2 shows some code that draws an axial gradient pattern. The NSBezierPath object containing the
rounded rectangle shape acts as the clipping region for the gradient when it is drawn. Figure 6-3 (page 117)
shows the resulting gradient.
Listing 6-2 Clipping an axial gradient to a rounded rectangle
- (void)drawRect:(NSRect)rect
{
NSRect bounds = [self bounds];
NSBezierPath* clipShape = [NSBezierPath bezierPath];
[clipShape appendBezierPathWithRoundedRect:bounds xRadius:40 yRadius:30];
NSGradient* aGradient = [[[NSGradient alloc]
initWithColorsAndLocations:[NSColor redColor], (CGFloat)0.0,
[NSColor orangeColor], (CGFloat)0.166,
[NSColor yellowColor], (CGFloat)0.33,
[NSColor greenColor], (CGFloat)0.5,
[NSColor blueColor], (CGFloat)0.75,
[NSColor purpleColor], (CGFloat)1.0,
nil] autorelease];
[aGradient drawInBezierPath:clipShape angle:0.0];
Advanced Drawing Techniques
Creating Gradient Fills
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
116}
Figure 6-3 Axial gradient drawn inside a Bezier path
Using the Primitive Drawing Routines
In addition to the high-level convenience methods, the NSGradient class defines two primitive methods for
drawing gradients:
● drawFromPoint:toPoint:options:
● drawFromCenter:radius:toCenter:radius:options:
These methods give you more flexibility over the gradient parameters, including the ability to extend the
gradient colors beyond theirstart and end points. Unlike the high-level routines, these methods do not change
the clip region prior to drawing. If you do notset up a custom clip region prior to drawing, the resulting gradient
could potentially expand to fill your entire view, depending on the gradient options.
Listing 6-3 shows the code for drawing a radial gradient in a view using the primitive drawing routine of
NSGradient. The second circle in the gradient is offset from the first one by 60 points in both the horizontal
and vertical directions, causing the overall gradient to skew towards the upper-right of the circle. Because the
code passes the value 0 for the options parameter, the gradient does not draw beyond the start and end
colors and therefore does not fill the entire view. Figure 6-4 (page 118) shows the gradient resulting from this
code.
Listing 6-3 Drawing a radial gradient using primitive routine
- (void)drawRect:(NSRect)rect
{
NSRect bounds = [self bounds];
NSGradient* aGradient = [[[NSGradient alloc]
initWithStartingColor:[NSColor orangeColor]
Advanced Drawing Techniques
Creating Gradient Fills
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
117endingColor:[NSColor cyanColor]] autorelease];
NSPoint centerPoint = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
NSPoint otherPoint = NSMakePoint(centerPoint.x + 60.0, centerPoint.y + 60.0);
CGFloat firstRadius = MIN( ((bounds.size.width/2.0) - 2.0),
((bounds.size.height/2.0) -2.0) );
[aGradient drawFromCenter:centerPoint radius:firstRadius
toCenter:otherPoint radius:5.0
options:0];
}
Figure 6-4 Gradient created using primitive drawing method
Using Quartz Shadings in Cocoa
Because the NSGradient class is available only in OS X v10.5 and later, software that runs on earlier versions
of OS X must use Quartz or Core Image to draw gradient fills. Quartz supports the creation of both radial and
axial gradients in different color spaces using a mathematical computation function you provide. The use of
a mathematical function means that the gradients you create using Quartz scale well to any resolution. Core
Image, on the other hand, provides filters for creating a fixed-resolution image consisting of a radial, axial, or
Gaussian gradient. Because the end result is an image, however, Core Image gradients may be less desirable
for PDF and other print-based drawing.
To draw a Quartz shading in your Cocoa program, you would do the following from your drawRect: method:
1. Get a CGContextRef using the graphicsPort method of NSGraphicsContext. (You will pass this
reference to other Quartz functions.)
2. Create a CGShadingRef using Quartz; see “Gradients” in Quartz 2D Programming Guide .
Advanced Drawing Techniques
Creating Gradient Fills
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
1183. Configure the current clipping path to the desired shape for your shading; see “Setting the Clipping
Region” (page 35).
4. Draw the shading using CGContextDrawShading.
For information on using Core Image to create images with gradient fills, see Core Image Programming Guide .
Drawing to the Screen
If you want to take over the entire screen for your drawing, you can do so from a Cocoa application. Entering
full-screen drawing mode is a two-step process:
1. Capture the desired screen (or screens) for drawing.
2. Configure your drawing environment.
After capturing the screen, the way you configure your drawing environment depends on whether you are
using Cocoa or OpenGL to draw. In OpenGL, you create an NSOpenGLContext object and invoke several of
its methodsto enter full-screen mode. In Cocoa, you have to create a window that fillsthe screen and configure
that window.
Capturing the Screen
Cocoa does not provide direct support for capturing and releasing screens. The NSScreen class provides
read-only access to information about the available screens. To capture or manipulate a screen, you must use
the functions found in Quartz Services.
To capture all of the available screens, you can simply call the CGCaptureAllDisplays function. To capture
an individual display, you must get the ID of the desired display and call the CGDisplayCapture function to
capture it. The following example shows how to use information provided by an NSScreen object to capture
the main screen of a system.
- (BOOL) captureMainScreen
{
// Get the ID of the main screen.
NSScreen* mainScreen = [NSScreen mainScreen];
NSDictionary* screenInfo = [mainScreen deviceDescription];
NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
// Capture the display.
Advanced Drawing Techniques
Drawing to the Screen
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
119CGDisplayErr err = CGDisplayCapture([screenID longValue]);
if (err != CGDisplayNoErr)
return NO;
return YES;
}
To release a display you previously captured, use the CGDisplayRelease function. If you captured all of the
active displays, you can release them all by calling the CGReleaseAllDisplays function.
For more information about capturing and manipulating screens, see Quartz Display Services Reference .
Full-Screen Drawing in OpenGL
Applications that do full-screen drawing tend to be graphics intensive and thus use OpenGL to improve
rendering speed. Creating a full-screen context using OpenGL is easy to do from Cocoa. After capturing the
desired displays, create and configure an NSOpenGLContext object and then invoke its setFullScreen and
makeCurrentContextmethods. Afterinvoking thesemethods, your application goesimmediately to full-screen
mode and you can start drawing content.
When requesting a full-screen context in OpenGL, the pixel format for your contextshould include the following
attributes:
● NSOpenGLPFAFullScreen
● NSOpenGLPFAScreenMask
● NSOpenGLPFAAccelerated
● NSOpenGLPFANoRecovery (only if your OpenGL graphics context is shared)
Listing 6-4 shows the basic steps for capturing all displays and setting up the OpenGL context for full-screen
drawing. For information on how to create an NSOpenGLContext object, see “Creating an OpenGL Graphics
Context” (page 166).
Listing 6-4 Creating an OpenGL full-screen context
NSOpenGLContext* CreateScreenContext()
{
CGDisplayErr err;
Advanced Drawing Techniques
Drawing to the Screen
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
120err = CGCaptureAllDisplays();
if (err != CGDisplayNoErr)
return nil;
// Create the context object.
NSOpenGLContext* glContext = CreateMyGLContext();
// If the context is bad, release the displays.
if (!glContext)
{
CGReleaseAllDisplays();
return nil;
}
// Go to full screen mode.
[glContext setFullScreen];
// Make this context current so that it receives OpenGL calls.
[glContext makeCurrentContext];
return glContext;
}
Once you go into full-screen mode with your graphics context, your application has full control of the screen.
To exit full-screen mode, invoke the clearDrawable method of your OpenGL context and call the
CGReleaseAllDisplays function to release the screens back to the system.
For detailed sample code showing you how to enter full-screen mode using OpenGL and Cocoa, see the
NSOpenGL Fullscreen sample in Sample Code > Graphics & Imaging > OpenGL.
Full-Screen Drawing in Cocoa
All Cocoa drawing occurs in a window, but for full screen drawing, the window you create is a little different.
Instead of a bordered window with a title bar, you need to create a borderless window that spans the entire
screen area.
Advanced Drawing Techniques
Drawing to the Screen
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
121Although you create a full-screen window using Cocoa classes, you still have to use Quartz Services to capture
the display and configure the window properly. The capture processis described in “Capturing the Screen” (page
119). Once you capture the screen, the window server puts up a shield window that hides most other content.
To make your full-screen window visible, you must adjust its level to sit above this shield. You can get the
shield level using the CGShieldingWindowLevel function and pass the returned value to the setLevel:
method of your window.
Listing 6-5 shows an action method defined in a subclass of NSDocument. The document object uses this
method to capture the main display and create the window to fill thatscreen space. The window itself contains
a single view (of type MyFullScreenView) for drawing content. (In your own code, you would replace this
view with your own custom drawing view.) A reference to the window is stored in the myScreenWindow class
instance variable, which is initialized to nil when the class is first instantiated.
Listing 6-5 Creating a Cocoa full-screen context
- (IBAction)goFullScreen:(id)sender
{
// Get the screen information.
NSScreen* mainScreen = [NSScreen mainScreen];
NSDictionary* screenInfo = [mainScreen deviceDescription];
NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
// Capture the screen.
CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue];
CGDisplayErr err = CGDisplayCapture(displayID);
if (err == CGDisplayNoErr)
{
// Create the full-screen window if it doesn’t already exist.
if (!myScreenWindow)
{
// Create the full-screen window.
NSRect winRect = [mainScreen frame];
myScreenWindow = [[NSWindow alloc] initWithContentRect:winRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO
screen:[NSScreen mainScreen]];
Advanced Drawing Techniques
Drawing to the Screen
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
122// Establish the window attributes.
[myScreenWindow setReleasedWhenClosed:NO];
[myScreenWindow setDisplaysWhenScreenProfileChanges:YES];
[myScreenWindow setDelegate:self];
// Create the custom view for the window.
MyFullScreenView* theView = [[MyFullScreenView alloc]
initWithFrame:winRect];
[myScreenWindow setContentView:theView];
[theView setNeedsDisplay:YES];
[theView release];
}
// Make the screen window the current document window.
// Be sure to retain the previous window if you want to use it again.
NSWindowController* winController = [[self windowControllers]
objectAtIndex:0];
[winController setWindow:myScreenWindow];
// The window has to be above the level of the shield window.
int32_t shieldLevel = CGShieldingWindowLevel();
[myScreenWindow setLevel:shieldLevel];
// Show the window.
[myScreenWindow makeKeyAndOrderFront:self];
}
}
To exit full screen mode using Cocoa, simply release the captured display, resize your window so that it does
not occupy the entire screen, and set its level back to NSNormalWindowLevel. For more information about
the shield window, see Quartz Display Services Reference .
Advanced Drawing Techniques
Drawing to the Screen
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
123Disabling Screen Updates
You can disable and reenable all screen flushes using the NSDisableScreenUpdates and
NSEnableScreenUpdates functions. (In OS X v10.4 and later, you can also use the
disableScreenUpdatesUntilFlush method of NSWindow.) You can use this technique to synchronize
flushes to both a parent and child window. As soon as you reenable screen updates, all windows are flushed
simultaneously (or at least close to it).
To prevent the system from appearing frozen, the system may automatically reenable screen updates if your
application leaves them disabled for a prolonged period of time. If you leave screen updates disabled for more
than 1 second, the system automatically reenables them.
Using NSTimer for Animated Content
By default, Cocoa sends a drawRect: message to your views only when a user action causes something to
change. If your view contains animated content, you probably want to update that content at more regular
intervals. For both indeterminate-length and finite-length animations, you can do this using timers.
Note: For finite-length animations, you can also use an NSAnimation object to control the animation
timing. For more information, see “Using Cocoa Animation Objects” (page 125).
The NSTimer class provides a mechanism for generating periodic events in your application. When a preset
time is reached, the timer object sends a message to your application, giving you the chance to perform any
desired actions. For animations, you would use a timer to tell your application that it is time to draw the next
frame.
There are two steps involved with getting a timer to run. The first step is to create the NSTimer object itself
and specify the object to notify, the message to send, the time interval for the notification, and whether the
timer repeats. The second step is to install that timer object on the run loop of your thread. The methods
scheduledTimerWithTimeInterval:invocation:repeats: and
scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: perform both of these
steps for you. Other methods of NSTimer create the timer but do not install it on the run loop.
For information and examples on how to create and use timers, see Timer Programming Topics.
Advanced Drawing Techniques
Using NSTimer for Animated Content
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
124Using Cocoa Animation Objects
The NSAnimation and NSViewAnimation classes provide sophisticated behavior for animations that occur
over a finite length of time. OS X uses animation objects to implement transition animations for user interface
elements. You can define custom animation objects to implement animations for your own code. Unlike
NSTimer, animation notifications can occur at irregular intervals, allowing you to create animationsthat appear
to speed up or slow down.
For information about how to use Cocoa animation objects, see Animation Programming Guide for Cocoa .
Optimizing Your Drawing Code
The following sections provide some basic guidance for improving the overall performance of your drawing
code. These are the things that you should definitely be doing in your code. For a more comprehensive list of
drawing optimization techniques, see Drawing Performance Guidelines.
Draw Minimally
Even with modern graphics hardware, drawing is still an expensive operation. The best way to reduce the
amount of time spent in your drawing code is to draw only what is needed in the first place.
During a view update, the drawRect: method receives a rectangle that specifies the portion of the view that
needs to be updated. This rectangle is always limited to the portion of the view that is currently visible and in
some cases may be even smaller. Your drawing code should pay attention to this rectangle and avoid drawing
content outside of it. Because the rectangle passed to drawRect: might be a union ofseveralsmaller rectangles,
an even better approach is to call the view’s getRectsBeingDrawn:count: method and constrain your
drawing to the exact list of rectangles returned by that method.
Avoid Forcing Synchronous Updates
When invalidating portions of your views, you should avoid using the display family of methods to force an
immediate update. These methods cause the system to send a drawRect: message to the affected view (and
potentially other views in the hierarchy) immediately rather than wait until the next regular update cycle. If
there are several areas to update, this may result in a lot of extra work for your drawing code.
Instead, you should use the setNeedsDisplay: and setNeedsDisplayInRect: methods to mark areas
as needing an update. When you call these methods, the system collects the rectangles you specify and
coalesces them into a combined update region, which it then draws during the next update cycle.
Advanced Drawing Techniques
Using Cocoa Animation Objects
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
125If you are creating animated content, you should also be careful not to trigger visual updates more frequently
than the screen refresh rate allows. Updating faster than the refresh rate results in your code drawing frames
that are never seen by the user. In addition, updating faster than the refresh rate is not allowed in OS X v10.4
and later. If you try to update the screen faster than the refresh rate, the window server may block the offending
thread until the next update cycle.
Reuse Your Objects
If you have objects that you plan to use more than once, consider caching them for later use. Caching saves
time by eliminating the need to recreate objects each time you want to draw them. Of course, caching requires
more memory, so be judicious about what you cache. It is faster to recreate an object in memory than page it
in from disk.
Many objects are cached automatically by Cocoa and do not need to be cached in your own code. For example,
Cocoa caches NSColor objects representing commonly used colors as those colors are requested.
Minimize State Changes
Every time you save the graphics state, you incur a small performance penalty. Whenever you have objects
with the same rendering attributes, try to draw them all at the same time. If you save and restore the graphics
state for each object, you may waste some CPU cycles.
With Cocoa, methods and functions that draw right away usually involve a change in graphics state. For
example, when you call the stroke method of NSBezierPath, the object automatically saves the graphics
state and appliesthe options associated with that path. While you are building the path, however, the graphics
state does not change. Thus, if you want to draw several shapes using the same graphics attributes, it is
advantageous to fill a single NSBezierPath with all of the shapes and then draw them all as a group.
Note: There is a tradeoff between creating larger, more complex Bezier paths and using individual
objects for each shape you want to draw. As path complexity increases, so do the number of
calculations required to determine fill characteristics and to perform hit detection—see “Reduce
Path Complexity” (page 155). When creating Bezier paths, you need to find an appropriate balance
between path complexity and graphics state changes.
Advanced Drawing Techniques
Optimizing Your Drawing Code
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
126Text rendering is a special type of drawing that is an important part of most applications. Cocoa provides a
range of options for rendering text that should satisfy the needs of most developers. The following sections
cover these options briefly. For more detailed information, you should see the documents in Reference Library
> Cocoa > Text & Fonts.
Text Attributes
Cocoa provides support for programmatically getting font information using the NSFont class. You can apply
fonts as attributes to strings or use them to set the default font in the current context. The Cocoa text system
also uses font objects for formatting text. You request NSFont objects from Cocoa using the name and size
of the font you want, as shown in the following example.
NSFont* font1= [NSFont fontWithName:@"Helvetica" size:9.0];
NSFont* font2 = [NSFont fontWithName:@"Helvetica Bold" size:10.0];
The NSFont class does not provide a programmatic way to modify other text attributes, such as the character
spacing and text drawing mode. Cocoa does, however, provide a system Font panel that you can display to
the user. From this panel, the user can make changes to the current font attributes. You can also set most text
options using the Cocoa text system, which is described in “Advanced Text Drawing” (page 128).
Although you usually specify font attributes directly when drawing NSString and NSAttributedString
objects, you can also change the font and font size information in the current graphics state. To change these
values, you create an NSFont object and invoke its set method.
For information about working with fonts and font objects, see Font Handling . For information about how to
display the Font panel, see Font Panel Programming Topics.
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
127
TextSimple Text Drawing
If you need to draw a small amount of text quickly, the simplest way to do it is using the methods of NSString
and NSAttributedString. The Application Kit defines methods on these classes that support drawing the
string in the current context. For an NSString object, you can apply basic attributes (such as font, color, and
style settings) to the entire string during drawing. For an NSAttributedString object, you can apply multiple
sets of attributes to different parts of the string.
Prior to OS X v10.4, the NSString and NSAttributedString classes were intended for rendering text
occasionally in your program. The performance of these drawing methods was not as good asthe performance
you could get by rendering text using the Cocoa text system. Also, the layout for strings is limited to a simple
rectangular area in the current view. In OS X v10.4, performance of the string drawing methods improved
significantly and is useful in many situations; of course, you should always measure the performance yourself
and see if it is adequate for your program. If you need to do more complex text layout, you should still consider
using the Cocoa text system.
For information on string drawing methods, see NSString Application Kit Additions Reference or NSAttributedString
Application Kit Additions Reference in Application Kit Framework Reference .
Advanced Text Drawing
If your program displays a lot of text or needs to arrange text in complex ways, you should use the Cocoa text
system. This system provides advanced text-handling capabilities on top of basic features such as text input,
layout, display, editing, copying, and pasting. The system supports multiple fonts and paragraph styles,
embedded images, spell checking, nonrectangular text containers, and sophisticated typesetting features,
among many other features.
Text layout is one of the most expensive drawing-related operations you can do and the Cocoa text system is
optimized for the best possible performance. The text system manages a sophisticated set of caches and
optimizes the times at which it performs layout to reduce the impact on your program’s drawing cycle. Of
course, these optimizations work only if your program reuses its text objects, but doing so is relatively simple.
The simplest way to use the Cocoa text system is to place an NSTextView object in one of your windows. A
text view object creates and maintainsthe text layout objectsit needsto draw text and respondsto user events
to modify the text.
If you want to have more control over the text layout and editing behavior, you can tie into the Cocoa text
system at several places. The text engine at the heart of the Cocoa text system is highly customizable. You can
subclass several text system classes to provide custom layout and typesetting behavior. You can also create
your own text-based views to provide features beyond what the default NSTextView offers.
Text
Simple Text Drawing
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
128For information about the Cocoa text system, you should start by reading Cocoa Text Architecture Guide . That
document describes the basic concepts of the text system and introduces you to many of the classes involved
in text layout and management. It also provides simple tutorials to get you started and pointers to other
text-related documents.
Text
Advanced Text Drawing
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
129Cocoa provides support for drawing simple or complex geometric shapes using paths. A path is a collection
of points used to create primitive shapes such as lines, arcs, and curves. From these primitives, you can create
more complex shapes, such as circles, rectangles, polygons, and complex curved shapes, and paint them.
Because they are composed of points(as opposed to a rasterized bitmap), paths are lightweight, fast, and scale
to different resolutions without losing precision or quality.
The following sectionsfocus primarily on the use of the NSBezierPath class, which providesthe main interface
for creating and manipulating paths. Cocoa also provides a handful of functions that offer similar behavior for
creating and drawing paths but do not require the overhead of creating an object. Those functions are
mentioned where appropriate, but for more information,see Foundation Framework Reference and Application
Kit Framework Reference .
Path Building Blocks
Cocoa defines several fundamental data types for manipulating geometric information in the drawing
environment. These data types include NSPoint, NSRect, and NSSize. You use these data types to specify
lines, rectangles, and width and height information for the shapes you want to draw. Everything from lines
and rectangles to circles, arcs, and Bezier curves can be specified using one or more of these data structures.
The coordinate values for point, rectangle, and size data types are all specified using floating-point values.
Floating-point values allow for much finer precision asthe resolution of the underlying destination device goes
up.
The NSPoint, NSRect, and NSSize data types have equivalentsin the Quartz environment: CGPoint, CGRect,
and CGSize. Because the layout of the Cocoa and Quartz types are identical, you can convert between two
types by casting from one type to its counterpart.
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
130
PathsThe NSBezierPath Class
The NSBezierPath class provides the behavior for drawing most primitive shapes, and for many complex
shapes, it isthe only tool available in Cocoa. An NSBezierPath object encapsulatesthe information associated
with a path, including the pointsthat define the path and the attributesthat affect the appearance of the path.
The following sections explain how NSBezierPath represents path information and also describe the attributes
that affect a path’s appearance.
Path Elements
An NSBezierPath object uses path elementsto build a path. A path element consists of a primitive command
and one or more points. The command tells the path object how to interpret the associated points. When
assembled, a set of path elements creates a series of line segments that form the desired shape.
The NSBezierPath class handles much of the work of creating and organizing path elementsinitially. Knowing
how to manipulate path elements becomes important, however, if you want to make changes to an existing
path. If you create a complex path based on user input, you might want to give the user the option of changing
that path later. Although you could create a new path object with the changes, it is far simpler to modify the
existing path elements. (For information on how to modify path elements, see “Manipulating Individual Path
Elements” (page 156).)
The NSBezierPath class defines only four basic path element commands, which are listed in Table 8-1. These
commands are enough to define all of the possible path shapes. Each command has one or more points that
contain information needed to position the path element. Most path elements use the current drawing point
as the starting point for drawing.
Table 8-1 Path element commands
Number Description
of
points
Command
Movesthe path object’s current drawing point to the specified
point. This path element does not result in any drawing. Using
this command in the middle of a path resultsin a disconnected
line segment.
NSMoveToBezier- 1
PathElement
Creates a straight line from the current drawing point to the
specified point. Lines and rectangles are specified using this
path element.
NSLineToBezier- 1
PathElement
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
131Number Description
of
points
Command
Creates a curved line segment from the current point to the
specified endpoint using two control pointsto define the curve.
The points are stored in the following order: controlPoint1,
controlPoint2, endPoint. Ovals, arcs, and Bezier curves all
use curve elements to specify their geometry.
NSCurveToBezier- 3
PathElement
Marks the end of the current subpath at the specified point.
(Note that the point specified for the Close Path element is
essentially the same as the current point.
NSClosePathBezier- 1
PathElement
When you add a new shape to a path, NSBezierPath breaks that shape down into one or more component
path elements for storage purposes. For example, calling moveToPoint: or lineToPoint: creates a Move
To element or Line To element respectively. In the case of more complex shapes, like rectangles and ovals,
several line or curve elements may be created. Figure 8-1 shows two shapes and the resulting path elements.
For the curved segment, the figure also shows the control points that define the curve.
Figure 8-1 Path elements for a complex path
Listing 8-1 shows the code that creates the path shown in Figure 8-1.
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
132Listing 8-1 Creating a complex path
NSBezierPath* aPath = [NSBezierPath bezierPath];
[aPath moveToPoint:NSMakePoint(0.0, 0.0)];
[aPath lineToPoint:NSMakePoint(10.0, 10.0)];
[aPath curveToPoint:NSMakePoint(18.0, 21.0)
controlPoint1:NSMakePoint(6.0, 2.0)
controlPoint2:NSMakePoint(28.0, 10.0)];
[aPath appendBezierPathWithRect:NSMakeRect(2.0, 16.0, 8.0, 5.0)];
Subpaths
A subpath is a series of connected line and curve segments within an NSBezierPath object. A single path
object may contain multiple subpaths, with each subpath delineated by a Move To or Close Path element.
When you set the initial drawing point (typically using the moveToPoint: method), you set the starting point
of the first subpath. As you draw, you build the contents of the subpath until you either close the path (using
the closePath method) or add another Move To element. At that point, the subpath is considered closed
and any new elements are added to a new subpath.
Some methods of NSBezierPath automatically create a new subpath for you. For example, creating a rectangle
or oval results in the addition of a Move To element, several drawing elements, and a Close Path and Move To
element (see Figure 8-1 (page 132) for an example). The Move To element at the end of the list of elements
ensures that the current drawing point is left in a known location, which in this case is at the rectangle’s origin
point.
Subpaths exist to help you distinguish different parts of a path object. For example, subpaths affect the way
a path is filled; see “Winding Rules” (page 141). The division of a path into subpaths also affects methods such
as bezierPathByReversingPath, which reversesthe subpaths one at a time. In other cases, though,subpaths
in an NSBezierPath object share the same drawing attributes.
Path Attributes
An NSBezierPath object maintains all of the attributes needed to determine the shape of its path. These
attributes include the line width, curve flatness, line cap style, line join style, and miter limit of the path. You
set these values using the methods of NSBezierPath.
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
133Path attributes do not take effect until you fill or stroke the path, so if you change an attribute more than once
before drawing the path, only the last value is used. The NSBezierPath class maintains both a custom and
default version of each attribute. Path objects use custom attribute values if they are set. If no custom attribute
value is set for a given path object, the default value is used. The NSBezierPath class does not use path
attribute values set using Quartz functions.
Note: Path attributes apply to the entire path. If you want to use different attributes for different
parts of a path, you must create two separate path objects and apply the appropriate attributes to
each.
The following sections describe the attributes you can set for a path object and how those attributes affect
your rendered paths.
Line Width
The line width attribute controls the width of the entire path. Line width is measured in points and specified
as a floating-point value. The default width for all lines is 1. To change the default line width for all
NSBezierPath objects, you use the setDefaultLineWidth: method. To set the line width for the current
path object, you use the setLineWidth: method of that path object. To set the default line width for shapes
rendered without an NSBezierPath object, you must use the CGContextSetLineWidth function in Quartz.
Fractional line widths are rendered as close as possible to the specified width, subject to the limitations of the
destination device, the position of the line, and the current anti-aliasing setting. For example, suppose you
want to draw a line whose width is 0.2 points. Multiplying this width by 1/72 points per inch yields a line that
is 0.0027778 inches wide. On a 90 dpi screen, the smallest possible line would be 1 pixel wide or 0.0111 inches.
To ensure your line is not hidden on the screen, Cocoa nominally drawsit at the screen’slarger minimum width
(0.0111 inches). In reality, if the line straddles a pixel boundary or anti-aliasing is enabled, the line might affect
additional pixels on either side of the path. If the output device were a 600 dpi printer instead, Quartz would
be able to render the line closer to its true width of 0.0027778 inches.
Listing 8-2 draws a few paths using different techniques. The NSFrameRect function uses the default line
width to draw a rectangle, so that value must be set prior to calling the function. Path objects use the default
value only if a custom value has not been set. You can even change the line width of a path object and draw
again to achieve a different path width, although you would also need to move the path to see the difference.
Listing 8-2 Setting the line width of a path
// Draw a rectangle using the default line width: 2.0.
[NSBezierPath setDefaultLineWidth:2.0];
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
134NSFrameRect(NSMakeRect(20.0, 20.0, 10.0, 10.0));
// Set the line width for a single NSBezierPath object.
NSBezierPath* thePath = [NSBezierPath bezierPath];
[thePath setLineWidth:1.0]; // Has no effect.
[thePath moveToPoint:NSMakePoint(0.0, 0.0)];
[thePath lineToPoint:NSMakePoint(10.0, 0.0)];
[thePath setLineWidth:3.0];
[thePath lineToPoint:NSMakePoint(10.0, 10.0)];
// Because the last value set is 3.0, all lines are drawn with
// a width of 3.0, not just the second line.
[thePath stroke];
// Changing the width and stroking again draws the same path
// using the new line width.
[thePath setLineWidth:4.0];
[thePath stroke];
// Changing the default line width has no effect because a custom
// value already exists. The path is rendered with a width of 4.0.
[thePath setDefaultLineWidth:5.0];
[thePath stroke];
Line Cap Styles
The current line cap style determinesthe appearance of the open end points of a path segment. Cocoa supports
the line cap styles shown in Figure 8-2.
Figure 8-2 Line cap styles
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
135To set the line cap style for a NSBezierPath object, use the setLineCapStyle: method. The default line
cap style is set to NSButtLineCapStyle. To change the default line cap style, use the
setDefaultLineCapStyle: method. Listing 8-3 demonstrates both of these methods:
Listing 8-3 Setting the line cap style of a path
[// Set the default line cap style
[NSBezierPath setDefaultLineCapStyle:NSButtLineCapStyle];
// Customize the line cap style for the new object.
NSBezierPath* aPath = [NSBezierPath bezierPath];
[aPath moveToPoint:NSMakePoint(0.0, 0.0)];
[aPath lineToPoint:NSMakePoint(10.0, 10.0)];
[aPath setLineCapStyle:NSSquareLineCapStyle];
[aPath stroke];
Line Join Styles
The current line join style determines how connected lines in a path are joined at the vertices. Cocoa supports
the line join styles shown in Figure 8-3.
Figure 8-3 Line join styles
To set the line join style for an NSBezierPath object, use the setLineJoinStyle: method. The default line
join style is set to NSMiterLineJoinStyle. To change the default line join style, use the
setDefaultLineJoinStyle: method. Listing 8-4 demonstrates both of these methods:
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
136Listing 8-4 Setting the line join style of a path
[// Set the default line join style
[NSBezierPath setDefaultLineJoinStyle:NSMiterLineJoinStyle];
// Customize the line join style for a new path.
NSBezierPath* aPath = [NSBezierPath bezierPath];
[aPath moveToPoint:NSMakePoint(0.0, 0.0)];
[aPath lineToPoint:NSMakePoint(10.0, 10.0)];
[aPath lineToPoint:NSMakePoint(10.0, 0.0)];
[aPath setLineJoinStyle:NSRoundLineJoinStyle];
[aPath stroke];
Line Dash Style
The line dash style determines the pattern used to stroke a path. By default, stroked paths appear solid. Using
a line-dash pattern, you can specify an alternating group of solid and transparent swatches. When setting a
line dash pattern, you specify the width (in points) of each successive solid or transparent swatch. The widths
you specify are then repeated over the entire length of the path.
Figure 8-4 shows some sample line dash patterns, along with the values used to create each pattern.
Figure 8-4 Line dash patterns
The NSBezierPath class does not support the concept of a default line dash style. If you want a line dash
style, you must apply it to a path explicitly using the setLineDash:count:phase: method as shown in
Listing 8-5, which renders the last pattern from the preceding figure.
Listing 8-5 Adding a dash style to a path
void AddDashStyleToPath(NSBezierPath* thePath)
{
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
137// Set the line dash pattern.
float lineDash[6];
lineDash[0] = 40.0;
lineDash[1] = 12.0;
lineDash[2] = 8.0;
lineDash[3] = 12.0;
lineDash[4] = 8.0;
lineDash[5] = 12.0;
[thePath setLineDash:lineDash count:6 phase:0.0];
}
Line Flatness
The line flatness attribute determinesthe rendering accuracy for curved segments. The flatness value measures
the maximum error tolerance (in pixels) to use during rendering. Smaller values result in smoother curves but
require more computation time. Larger values result in more jagged curves but are rendered much faster.
Line flatness is one parameter you can tweak when you want to render a large number of curves quickly and
do not care about accuracy. For example, you might increase this value during a live resize orscrolling operation
when accuracy is not as crucial. Regardless, you should always measure performance to make sure such a
modification actually saves time.
Figure 8-5 shows how changing the default flatness affects curved surfaces. The figure on the left shows a
group of curved surfaces rendered with the flatness value set to 0.6 (its default value). The figure on the right
shows the same curved surfaces rendered with the flatness value set to 20. The curvature of each surface is
lost and now appears to be a set of connected line segments.
Figure 8-5 Flatness effects on curves
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
138To set the flatness for a specific NSBezierPath object, use the setFlatness: method. To set the default
flatness value, use setDefaultFlatness:, as shown in Listing 8-6:
Listing 8-6 Setting the flatness of a path
[- (void) drawRect:(NSRect)rect
{
if ([self inLiveResize])
{
// Adjust the default flatness upward to reduce
// the number of required computations.
[NSBezierPath setDefaultFlatness:10.0];
// Draw live resize content.
}
// ...
}
Miter Limits
Miter limits help you avoid spikes that occur when you join two line segments at a sharp angle. If the ratio of
the miter length—the diagonal length of the miter—to the line thickness exceeds the miter limit, the corner
is drawn using a bevel join instead of a miter join.
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
139Note: Miter limits apply only to paths rendered using the miter join style.
Figure 8-6 shows an example of how different miter limits affect the same path. This path consists of several
10-point wide lines connected by miter joins. In the figure on the left, the miter limit is set to 5. Because the
miter lengths exceed the miter limit, the line joins are changed to bevel joins. By increasing the miter limit to
16, as shown in the figure on the right, the miter joins are restored but extend far beyond the point where the
two lines meet.
Figure 8-6 Miter limit effects
To set the miter limits for a specific NSBezierPath object, use the setMiterLimit: method. To set the
default miter limit for newly created NSBezierPath objects, use setDefaultMiterLimit:. Listing 8-7
demonstrates both of these methods:
Listing 8-7 Setting the miter limit for a path
// Increase the default limit
[NSBezierPath setDefaultMiterLimit:20.0];
// Customize the limit for a specific path with sharp angles.
NSBezierPath* aPath = [NSBezierPath bezierPath];
[aPath moveToPoint:NSMakePoint(0.0, 0.0)];
[aPath lineToPoint:NSMakePoint(8.0, 100.0)];
[aPath lineToPoint:NSMakePoint(16.0, 0.0)];
[aPath setLineWidth:5.0];
[aPath setMiterLimit:5.0];
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
140[aPath stroke];
Winding Rules
When you fill the area encompassed by a path, NSBezierPath applies the current winding rule to determine
which areas of the screen to fill. A winding rule is simply an algorithm that tracks information about each
contiguous region that makes up the path's overall fill area. A ray is drawn from a point inside a given region
to any point outside the path bounds. The total number of crossed path lines (including implicit lines) and the
direction of each path line are then interpreted using the rules in Table 8-2, which determine if the region
should be filled.
Table 8-2 Winding rules
Winding rule Description
Count each left-to-right path as +1 and each right-to-left path as -1. If
the sum of all crossings is 0, the point is outside the path. If the sum is
nonzero, the point isinside the path and the region containing it isfilled.
This is the default winding rule.
NSNonZeroWindingRule
Count the total number of path crossings. If the number of crossings is
even, the point is outside the path. If the number of crossings is odd,
the point is inside the path and the region containing it should be filled.
NSEvenOddWindingRule
Fill operations are suitable for use with both open and closed subpaths. A closed subpath is a sequence of
drawing calls that ends with a Close Path path element. An open subpath ends with a Move To path element.
When you fill a partial subpath, NSBezierPath closes it for you automatically by creating an implicit
(non-rendered) line from the first to the last point of the subpath.
Paths
The NSBezierPath Class
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
141Figure 8-7 shows how the winding rules are applied to a particular path. Subfigure a shows the path rendered
using the nonzero rule and subfigure b shows it rendered using the even-odd rule. Subfigures c and d add
direction marks and the hidden path line that closes the figure to help you see how the rules are applied to
two of the path’s regions.
Figure 8-7 Applying winding rules to a path
To set the winding rule for an NSBezierPath object, use the setWindingRule: method. The default winding
rule is NSNonZeroWindingRule. To change the default winding rule for all NSBezierPath objects, use the
setDefaultWindingRule: method.
Manipulating Geometric Types
The Foundation framework includes numerousfunctionsfor manipulating geometric values and for performing
various calculations using those values. In addition to basic equality checks, you can perform more complex
operations,such asthe union and intersection of rectangles or the inclusion of a point in a rectangle’s boundaries.
Table 8-3 listssome of the more commonly used functions and their behaviors. The function syntax is provided
in a shorthand notation, with parameter types omitted to demonstrate the calling convention. For a complete
list of available functions, and their full syntax, see the Functions section in Foundation Framework Reference .
Paths
Manipulating Geometric Types
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
142Table 8-3 Commonly used geometry functions
Operation Function Description
Returns a properly formatted NSPoint data
structure with the specified x and y values.
NSPoint NSMakePoint(x,
y)
Creation
Returns a properly formatted NSSize data
structure with the specified width and height.
NSSize NSMakeSize(w,
h)
Returns a properly formatted NSRect data
structure with the specified origin (x, y) and size
(width, height).
NSRect NSMakeRect(x,
y, w, h)
BOOL NSEqualPoints(p1, Returns YES if the two points are the same.
p2)
Equality
Returns YES if the two size types have identical
widths and heights.
BOOL NSEqualSizes(s1,
s2)
Returns YES, if the two rectangles have the same
origins and the same widths and heights.
BOOL NSEqualRects(r1,
r2)
Returns YES if rectangle 1 completely encloses
rectangle 2.
BOOL NSContainsRect(r1,
r2)
Rectangle
manipulations
Returns a copy of the specified rectangle with its
sides moved inward by the specified delta values.
Negative delta values move the sides outward.
Does not modify the original rectangle.
NSRect NSInsetRect(r,
dX, dY)
NSRect Returns the intersection of the two rectangles.
NSIntersectionRect(r1,
r2)
NSRect NSUnionRect(r1, Returns the union of the two rectangles.
r2)
Tests whether the point lies within the specified
view rectangle. Adjusts the hit-detection
algorithm to provide consistent behavior from
the user’s perspective.
BOOL NSMouseInRect(p,
r, flipped)
Tests whether the point lies within the specified
rectangle. This is a basic mathematical
comparison.
BOOL NSPointInRect(p,
r)
Paths
Manipulating Geometric Types
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
143Drawing Fundamental Shapes
For many types of content, path-based drawing has several advantages over image-based drawing:
● Because paths are specified mathematically, they scale easily to different resolutions. Thus, the same path
objects can be used for screen and print-based drawing.
● The geometry information associated with a path requires much less storage space than most image data
formats.
● Rendering paths is often faster than compositing a comparable image. It takes less time to transfer path
data to the graphics hardware than it takes to transfer the texture data associated with an image.
The following sections provide information about the primitive shapes you can draw using paths. You can
combine one or more of these shapesto create a more complex path and then stroke or fill the path as described
in “Drawing the Shapes in a Path” (page 152). For some shapes, there may be more than one way to add the
shape to a path, or there may be alternate waysto draw the shape immediately. Wherever possible, the benefits
and disadvantages of each technique are listed to help you decide which technique is most appropriate in
specific situations.
Adding Points
An NSPoint structure by itself represents a location on the screen; it has no weight and cannot be drawn as
such. To draw the equivalent of a point on the screen, you would need to create a small rectangle at the desired
location, as shown in Listing 8-8.
Listing 8-8 Drawing a point
void DrawPoint(NSPoint aPoint)
{
NSRect aRect = NSMakeRect(aPoint.x, aPoint.y, 1.0, 1.0);
NSRectFill(aRect);
}
Of course, a more common use for points is to specify the position of other shapes. Many shapes require you
to specify the current point before actually creating the shape. You set the current point using the
moveToPoint: or relativeMoveToPoint: methods. Some shapes, like rectangles and ovals, already contain
location information and do not require a separate call to moveToPoint:.
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
144Important: You must specify a starting point before drawing individual line, arc, curve, and glyph paths.
If you do not, NSBezierPath raises an exception.
Adding Lines and Polygons
Cocoa provides a couple of options for adding lines to a path, with each technique offering different tradeoffs
between efficiency and correctness. You can draw lines in the following ways:
● Create single horizontal and vertical lines by filling a rectangle using NSRectFill. This technique is less
precise but is often a little faster than creating an NSBezierPath object. To create diagonal lines using
this technique, you must apply a rotation transform before drawing. This technique is not appropriate for
creating connected line segments.
● Use the lineToPoint:, relativeLineToPoint:, or strokeLineFromPoint:toPoint: methods
of NSBezierPath to create individual or connected line segments. This technique is fast and is the most
precise option for creating lines and complex polygons.
● Use the appendBezierPathWithPoints:count: method to create a series of connected lines quickly.
This technique is faster than adding individual lines.
Polygons are composed of multiple connected lines and should be created using an NSBezierPath object.
The simplest way to create a four-sided nonrectangular shape, like a parallelogram, rhombus, or trapezoid, is
using line segments. You could also create these shapes using transforms, but calculating the correct skew
factors would require a lot more work.
Listing 8-9 shows code to draw a parallelogram using NSBezierPath. The method in this example inscribes
the parallelogram inside the specified rectangle. The withShift parameter specifies the horizontal shift
applied to the top left and bottom right corners of the rectangular area.
Listing 8-9 Using lines to draw a polygon
void DrawParallelogramInRect(NSRect rect, float withShift)
{
NSBezierPath* thePath = [NSBezierPath bezierPath];
[thePath moveToPoint:rect.origin];
[thePath lineToPoint:NSMakePoint(rect.origin.x + withShift, NSMaxY(rect))];
[thePath lineToPoint:NSMakePoint(NSMaxX(rect), NSMaxY(rect))];
[thePath lineToPoint:NSMakePoint(NSMaxX(rect) - withShift, rect.origin.y)];
[thePath closePath];
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
145[thePath stroke];
}
Adding Rectangles
Because rectangles are used frequently, there are several options for drawing them.
● Use the methods of NSBezierPath to create your rectangle. The following methods are reasonably fast
and offer the best precision:
● strokeRect:
● fillRect:
● bezierPathWithRect:
● appendBezierPathWithRect:
● Create rectangles using the Cocoa functions described in “Drawing Rectangles” (page 152). These functions
draw rectangles faster than, but with less precision than, the methods of NSBezierPath.
● Create a rectangle using individual lines as described in “Adding Lines and Polygons” (page 145). You could
use thistechnique to create diagonally oriented rectangles—that is, rectangles whose sides are not parallel
to the x and y axes—without using a rotation transform.
Listing 8-10 shows a simple function that fills and strokes the same rectangle using two different techniques.
The current fill and stroke colors are used when drawing the rectangle, along with the default compositing
operation. In both cases, the rectangles are drawn immediately; there is no need to send a separate fill or
stroke message.
Listing 8-10 Drawing a rectangle
void DrawRectangle(NSRect aRect)
{
NSRectFill(aRect);
[NSBezierPath strokeRect:aRect];
}
Adding Rounded Rectangles
InOS X v10.5 and later, the NSBezierPath classincludesthe following methodsfor creating rounded-rectangles:
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
146● bezierPathWithRoundedRect:xRadius:yRadius:
● appendBezierPathWithRoundedRect:xRadius:yRadius:
These methods create rectangles whose corners are curved according to the specified radius values. The radii
describe the width and height of the oval to use at each corner of the rectangle. Figure 8-8 shows how this
inscribed oval is used to define the path of the rectangle’s corner segments.
Figure 8-8 Inscribing the corner of a rounded rectangle
Listing 8-11 shows a code snippet that creates and draws a path with a rounded rectangle.
Listing 8-11 Drawing a rounded rectangle
void DrawRoundedRect(NSRect rect, CGFloat x, CGFloat y)
{
NSBezierPath* thePath = [NSBezierPath bezierPath];
[thePath appendBezierPathWithRoundedRect:rect xRadius:x yRadius:y];
[thePath stroke];
}
Adding Ovals and Circles
To draw ovals and circles, use the following methods of NSBezierPath:
● bezierPathWithOvalInRect:
● appendBezierPathWithOvalInRect:
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
147Both methods inscribe an oval inside the rectangle you specify. You must then fill or stroke the path object to
draw the oval in the current context. The following example creates an oval from the specified rectangle and
strokes its path.
void DrawOvalInRect(NSRect ovalRect)
{
NSBezierPath* thePath = [NSBezierPath bezierPath];
[thePath appendBezierPathWithOvalInRect:ovalRect];
[thePath stroke];
}
You could also create an oval using arcs, but doing so would duplicate what the preceding methods do internally
and would be a little slower. The only reason to add individual arcs is to create a partial (non-closed) oval path.
For more information, see “Adding Arcs” (page 148).
Adding Arcs
To draw arcs, use the following methods of NSBezierPath:
● appendBezierPathWithArcFromPoint:toPoint:radius:
● appendBezierPathWithArcWithCenter:radius:startAngle:endAngle:
● appendBezierPathWithArcWithCenter:radius:startAngle:endAngle:clockwise:
The appendBezierPathWithArcFromPoint:toPoint:radius: method creates arcs by inscribing them
in an angle formed by the current point and the two points passed to the method. Inscribing a circle in this
manner can result in an arc that does not intersect any of the points used to specify it. It can also result in the
creation of an unwanted line from the current point to the starting point of the arc.
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
148Figure 8-9 shows three different arcs and the control points used to create them. For the two arcs created
using appendBezierPathWithArcFromPoint:toPoint:radius:, the current point must be set before
calling the method. In both examples, the point isset to (30, 30). Because the radius of the second arc isshorter,
and the starting point of the arc is not the same as the current point, a line is drawn from the current point to
the starting point.
Figure 8-9 Creating arcs
Listing 8-12 shows the code snippets you would use to create each of the arcs from Figure 8-9. (Although the
figure shows the arcs individually, executing the following code would render the arcs on top of each other.
)
Listing 8-12 Creating three arcs
NSBezierPath* arcPath1 = [NSBezierPath bezierPath];
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
149NSBezierPath* arcPath2 = [NSBezierPath bezierPath];
[[NSColor blackColor] setStroke];
// Create the first arc
[arcPath1 moveToPoint:NSMakePoint(30,30)];
[arcPath1 appendBezierPathWithArcFromPoint:NSMakePoint(0,30)
toPoint:NSMakePoint(0,60) radius:30];
[arcPath1 stroke];
// Create the second arc.
[arcPath2 moveToPoint:NSMakePoint(30,30)];
[arcPath2 appendBezierPathWithArcFromPoint:NSMakePoint(30,40)
toPoint:NSMakePoint(70,30) radius:20];
[arcPath2 stroke];
// Clear the old arc and do not set an initial point, which prevents a
// line being drawn from the current point to the start of the arc.
[arcPath2 removeAllPoints];
[arcPath2 appendBezierPathWithArcWithCenter:NSMakePoint(30,30) radius:30
startAngle:45 endAngle:135];
[arcPath2 stroke];
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
150Adding Bezier Curves
To draw Bezier curves, you must use the curveToPoint:controlPoint1:controlPoint2: method of
NSBezierPath. This method supports the creation of a cubic curve from the current point to the destination
point you specify when calling the method. The controlPoint1 parameter determinesthe curvature starting
from the current point, and controlPoint2 determines the curvature of the destination point, as shown in
Figure 8-1 (page 132).
Figure 8-10 Cubic Bezier curve
Adding Text
Because NSBezierPath only supports path-based content, you cannot add text characters directly to a path;
instead, you must add glyphs. A glyph is the visual representation of a character (or partial character) in a
particular font. For glyphs in an outline font, this visual representation is stored as a set of mathematical paths
that can be added to an NSBezierPath object.
Note: Using NSBezierPath is not the most efficient way to render text, but can be used in situations
where you need the path information associated with the text.
To obtain a set of glyphs, you can use the Cocoa text system or the NSFont class. Getting glyphs from the
Cocoa text system is usually easier because you can get glyphs for an arbitrary string of characters, whereas
using NSFont requires you to know the names of individual glyphs. To get glyphs from the Cocoa text system,
you must do the following:
1. Create the text system objects needed to manage text layout.
2. Use the glyphAtIndex: or getGlyphs:range: method of NSLayoutManager to retrieve the desired
glyphs.
3. Add the glyphs to your NSBezierPath object using one of the following methods:
● appendBezierPathWithGlyph:inFont:
● appendBezierPathWithGlyphs:count:inFont:
Paths
Drawing Fundamental Shapes
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
151When added to your NSBezierPath object, glyphs are converted to a series of path elements. These path
elements simply specify lines and curves and do not retain any information about the characters themselves.
You can manipulate paths containing glyphs just like you would any other path by changing the points of a
path element or by modifying the path attributes.
Drawing the Shapes in a Path
There are two options for drawing the contents of a path: you can stroke the path or fill it. Stroking a path
renders an outline of the path’sshape using the currentstroke color and path attributes. Filling the path renders
the area encompassed by the path using the current fill color and winding rule.
Figure 8-11 shows the same path from Figure 8-1 (page 132) but with the contents filled and a different stroke
width applied.
Figure 8-11 Stroking and filling a path.
Drawing Rectangles
Cocoa provides several functions for drawing rectangles to the current context immediately using the default
attributes. These functions use Quartz primitives to draw one or more rectangles quickly, but in a way that
may be less precise than if you were to use NSBezierPath. For example, these routines do not apply the
current join style to the corners of a framed rectangle.
Table 8-4 lists some of the more commonly used functions for drawing rectangles along with their behaviors.
You can use these functions in places where speed is more important than precision. The syntax for each
function is provided in a shorthand notation, with parameter types omitted to demonstrate the calling
conventions. For a complete list of available functions, and their full syntax, see Application Kit Functions
Reference .
Paths
Drawing Rectangles
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
152Table 8-4 Rectangle frame and fill functions
Function Description
void NSEraseRect(aRect) Fills the specified rectangle with white.
Drawsthe frame of the rectangle using the current fill color,
the default line width, and the NSCompositeCopy
compositing operation.
void NSFrameRect(aRect)
Drawsthe frame of the rectangle using the current fill color,
the specified width, and the NSCompositeCopy
compositing operation.
void
NSFrameRectWithWidth(aRect,
width)
Drawsthe frame of the rectangle using the current fill color,
the specified width, and the specified operation.
void NSFrameRectWithWidthUsingOperation(aRect, width,
op)
Fills the rectangle using the current fill color and the
NSCompositeCopy compositing operation.
void NSRectFill(aRect)
Fills the rectangle using the current fill color and specified
compositing operation.
void NSRectFillUsingOperation(aRect, op)
Fillsthe C-style array of rectangles using the current fill color
and the NSCompositeCopy compositing operation.
void NSRectFillList(rectList,
count)
Fills the C-style array of rectangles using the corresponding
list of colors. Each list must have the same number of entries.
void NSRectFillListWithColors(rects, colors,
count)
Fillsthe C-style array of rectangles using the current fill color
and the specified compositing operation.
void NSRectFillListUsingOperation(rects, count, op)
Fills the C-style array of rectangles using the corresponding
list of colors and the specified compositing operation. The
list of rectangles and list of colors must contain the same
number of items.
void NSRectFillListWithColorsUsingOperation(rects,
colors, count, op)
Paths
Drawing Rectangles
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
153Important: You may have noticed that the NSFrameRect, NSFrameRectWithWidth, and
NSFrameRectWithWidthUsingOperation functions draw the rectangle using the fill color instead of
the stroke color. These methods draw the rectangle’s frame by filling four sub-rectangles, one for each side
of the rectangle. This differs from the way NSBezierPath draws rectangles and can sometimes lead to
confusion. If your rectangle does not show up the way you expected, check your code to make sure you
are setting the drawing color using either the set or setFill method of NSColor.
Working with Paths
Building a sleek and attractive user interface is hard work and most programs use a combination of images
and paths to do it. Paths have the advantage of being lightweight, scalable, and fast. Even so, paths are not
appropriate in all situations. The following sections provide some basic tips and guidance on how to use paths
effectively in your program.
Building Paths
Building a path involves creating an NSBezierPath object and adding path elements to it. All paths must
start with a Move To element to mark the first point of the path. In some cases, this element is added for you
but in others you must add it yourself. For example, methods that create a closed path (such as an oval or
rectangle) insert a MoveTo element for you.
A single NSBezierPath object may have multiple subpaths. Each subpath is itself a complete path, meaning
the subpath may not appear connected to any other subpaths when drawn. Filled subpaths can still interact
with each other, however. Overlapping subpaths may cancel each other’s fill effect, resulting in holes in the
fill area.
All subpaths in an NSBezierPath object share the same drawing attributes. The only way to assign different
attributes to different paths is to create different NSBezierPath objects for each.
Improving Rendering Performance
As you work on your drawing code, you should keep performance in mind. Drawing is a processor intensive
activity but there are many waysto reduce the amount of drawing performed by your application. The following
sections offersome basic tipsrelated to improving drawing performance with Cocoa applications. For additional
drawing-related performance tips, see Drawing Performance Guidelines.
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
154Note: As with any determination of performance, you should measure the speed of your drawing
operations before making any changes. If the amount of time spent inside the methods of
NSBezierPath becomessignificant,simplifying your paths might offer better performance. Limiting
the total amount of drawing you do during an update cycle might also improve performance.
Reuse Your Path Objects
If you draw the same content repeatedly, consider caching the objects used to draw that content. It is usually
more efficient to retain an existing NSBezierPath object than to recreate it during each drawing cycle. For
content that might change dynamically, you might also consider maintaining a pool of reusable objects.
Correctness Versus Efficiency
When writing your drawing code, you should always try to make that code as efficient as possible without
sacrificing the quality of the rendered content. If your drawing code seems slow, there are some tradeoffs you
can make to improve efficiency that reduce quality only temporarily:
● Use the available update rectanglesto draw only what has changed. Use different NSBezierPath objects
for each part of the screen rather than one large object that covers everything. For more information, see
“Reduce Path Complexity” (page 155).
● During scrolling, live resizing, or other time-critical operations, consider the following options:
●
If your screen contains animated content, pause the animation until the operation is complete.
● Try temporarily increasing the flatness value for curved paths. The default flatness value is set to 0.6,
which results in nice smooth curves. Increasing this value above 1.0 may make your curves look more
jagged but should improve performance. You may want to try a few different values to determine a
good tradeoff between appearance and speed.
● Disable anti-aliasing. For more information, see “Setting the Anti-aliasing Options” (page 37).
● When drawing rectangles, use NSFrameRect and NSRectFill for operations where the highest quality
is not required. These functions offer close approximations to what you would get with NSBezierPath
but are often a little faster.
Reduce Path Complexity
If you are drawing a large amount of content, you should do your best to reduce the complexity of the path
data you store in a single NSBezierPath object. Path objects with hundreds of path elements require more
calculations than those with 10 or 20 elements. Every line or curve segment you add increases the number of
calculations required to flatten the path or determine whether a point is inside it. Numerous path crossings
also increases the number of required calculations when filling the path.
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
155If the accuracy of rendered paths is not crucial, try using multiple NSBezierPath objects to draw the same
content. There is very little visual difference between using one path object or multiple path objects. If your
path is already grouped into multiple subpaths, then it becomes easy to put some of those subpaths in other
NSBezierPath objects. Using multiple path objects reduces the number of calculations for each subpath and
also allows you to limit rendering to only those paths that are in the current update rectangle.
Manipulating Individual Path Elements
Given an NSBezierPath object with some existing path data, you can retrieve the points associated with that
path and modify them individually. An illustration program might do this in response to a mouse event over
one of the points in a path. If the mouse event results in that point being dragged to a new location, you can
quickly update the path element with the new location and redraw the path.
The elementCount method of NSBezierPath returns the total number of path elements for all subpaths of
the object. To find out the type of a given path element, use the elementAtIndex: or
elementAtIndex:associatedPoints: method. These methods return one of the values listed in Table
8-1 (page 131). Use the elementAtIndex:associatedPoints: method if you also want to retrieve the
points associated with an element. If you do not already know the type of the path element, you should pass
this method an array capable of holding at least three NSPoint data types.
To change the points associated with a path element, use the setAssociatedPoints:atIndex: method.
You cannot change the type of a path element, only the points associated with it. When changing the points,
NSBezierPath takes only as many points from your point array as are needed. For example, if you specify
three points for a Line To path element, only the first point is used.
Listing 8-13 shows a method that updates the control point associated with a curve path element on the end
of the current path. The pointsthat define the curve are stored in the order controlPoint1, controlPoint2,
endPoint. This method replaces the point controlPoint2, which affects the end portion of the curve.
Listing 8-13 Changing the control point of a curve path element
- (void)replaceLastControlPointWithPoint:(NSPoint)newControl
inPath:(NSBezierPath*)thePath
{
int elemCount = [thePath elementCount];
NSBezierPathElement elemType =
[thePath elementAtIndex:(elemCount - 1)];
if (elemType != NSCurveToBezierPathElement)
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
156return;
// Get the current points for the curve.
NSPoint points[3];
[thePath elementAtIndex:(elemCount - 1) associatedPoints:points];
// Replace the old control point.
points[1] = newControl;
// Update the points.
[thePath setAssociatedPoints:points atIndex:(elemCount - 1)];
}
Transforming a Path
The coordinate system of an NSBezierPath object always matches the coordinate system of the view in
which it is drawn. Thus, given a path whose first point is at (0, 0) in your NSBezierPath object, drawing the
path in your view places that point at (0, 0) in the view’s current coordinate system. To draw that path in a
different location, you must apply a transform in one of two ways:
● Apply the transform to the view coordinate system and then draw the path. For information on how to
apply transforms to a view, see “Creating and Applying a Transform” (page 51).
● Apply the transform to the NSBezierPath object itself using the transformUsingAffineTransform:
method and then draw it in an unmodified view.
Both techniques cause the path to be drawn at the same location in the view; however, the second technique
also has the side effect of permanently modifying the NSBezierPath object. Depending on your content,
this may or may not be appropriate. For example, in an illustration program, you might want the user to be
able to drag shapes around the view; therefore, you would want to modify the NSBezierPath object to retain
the new position of the path.
Creating a CGPathRef From an NSBezierPath Object
There may be times when it is necessary to convert an NSBezierPath object to a CGPathRef data type so
that you can perform path-based operations using Quartz. For example, you might want to draw your path to
a Quartz transparency layer or use it to do advanced hit detection. Although you cannot use a NSBezierPath
object directly from Quartz, you can use its path elements to build a CGPathRef object.
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
157Listing 8-14 shows you how to create a CGPathRef data type from an NSBezierPath object. The example
extends the behavior of the NSBezierPath class using a category. The quartzPath method uses the path
elements of the NSBezierPath object to call the appropriate Quartz path creation functions. Although the
method creates a mutable CGPathRef object, it returns an immutable copy for drawing. To ensure that the
returned path returns correct results during hit detection, this method implicitly closes the last subpath if your
code does not do so explicitly. Quartz requires paths to be closed in order to do hit detection on the path’s fill
area.
Listing 8-14 Creating a CGPathRef from an NSBezierPath
@implementation NSBezierPath (BezierPathQuartzUtilities)
// This method works only in OS X v10.2 and later.
- (CGPathRef)quartzPath
{
int i, numElements;
// Need to begin a path here.
CGPathRef immutablePath = NULL;
// Then draw the path elements.
numElements = [self elementCount];
if (numElements > 0)
{
CGMutablePathRef path = CGPathCreateMutable();
NSPoint points[3];
BOOL didClosePath = YES;
for (i = 0; i < numElements; i++)
{
switch ([self elementAtIndex:i associatedPoints:points])
{
case NSMoveToBezierPathElement:
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
break;
case NSLineToBezierPathElement:
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
158CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
didClosePath = NO;
break;
case NSCurveToBezierPathElement:
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
didClosePath = NO;
break;
case NSClosePathBezierPathElement:
CGPathCloseSubpath(path);
didClosePath = YES;
break;
}
}
// Be sure the path is closed or Quartz may not do valid hit detection.
if (!didClosePath)
CGPathCloseSubpath(path);
immutablePath = CGPathCreateCopy(path);
CGPathRelease(path);
}
return immutablePath;
}
@end
The code from the preceding example closes only the last open path by default. Depending on your path
objects, you might also want to close intermediate subpaths whenever a new Move To element is encountered.
If your path objects typically contain only one path, you do not need to do so, however.
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
159Detecting Mouse Hits on a Path
If you need to determine whether a mouse event occurred on a path or its fill area, you can use the
containsPoint: method of NSBezierPath. This method teststhe point against all closed and open subpaths
in the path object. If the point lies on or inside any of the subpaths, the method returns YES. When determining
whether a point is inside a subpath, the method uses the nonzero winding rule.
If your software runs in OS X v10.4 and later, you can perform more advanced hit detection using the
CGContextPathContainsPoint and CGPathContainsPoint functions in Quartz. Using these functions
you can determine if a point is on the path itself or if the point is inside the path using either the nonzero or
even-odd winding rule. Although you cannot use these functions on an NSBezierPath object directly, you
can convert your path object to a CGPathRef data type and then use them. For information on how to convert
a path object to a CGPathRef data type, see “Creating a CGPathRef From an NSBezierPath Object” (page 157).
Important: Quartz considers a point to be inside a path only if the path is explicitly closed. If you are
converting your NSBezierPath objects to Quartz paths for use in hit detection, be sure to close any open
subpaths either prior to or during the conversion. If you do not, points lying inside your path may not be
correctly identified as such.
Listing 8-15 shows an example of how you might perform advanced hit detection on an NSBezierPath object.
This example adds a method to the NSBezierPath class using a category. The implementation of the method
adds a CGPathRef version of the current path to the current context and calls the
CGContextPathContainsPoint function. This function uses the specified mode to analyze the location of
the specified point relative to the current path and returns an appropriate value. Modes can include
kCGPathFill, kCGPathEOFill, kCGPathStroke, kCGPathFillStroke, or kCGPathEOFillStroke.
Listing 8-15 Detecting hits on a path
@implementation NSBezierPath (BezierPathQuartzUtilities)
// Note, this method works only in OS X v10.4 and later.
- (BOOL)pathContainsPoint:(NSPoint)point forMode:(CGPathDrawingMode)mode
{
CGPathRef path = [self quartzPath]; // Custom method to create a CGPath
CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext]
graphicsPort];
CGPoint cgPoint;
BOOL containsPoint = NO;
cgPoint.x = point.x;
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
160cgPoint.y = point.y;
// Save the graphics state before doing the hit detection.
CGContextSaveGState(cgContext);
CGContextAddPath(cgContext, path);
containsPoint = CGContextPathContainsPoint(cgContext, cgPoint, mode);
CGContextRestoreGState(cgContext);
return containsPoint;
}
@end
Paths
Working with Paths
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
161Cocoa was designed to integrate well with other technologies in OS X. Many technologies are packaged as
Objective-C frameworks, which makesincluding them in Cocoa easy. You are not limited to the use of Objective-C
frameworks, though. Cocoa itself uses Quartz internally to implement most drawing routines. You can use
Quartz and other C-based technologies,such as OpenGL and QuickTime, from your code with little extra effort.
The sections that follow provide information about how to incorporate some of the more important drawing
technologies available in OS X.
Using Quartz in Your Application
Everything you can draw using Cocoa can also be drawn using Quartz. The Cocoa drawing code itself uses
Quartz primitives to render content. Cocoa simply adds an object-oriented interface and in some cases does
more of the work for you. Cocoa does not provide classes for all Quartz behavior, however. In situations where
a feature is not available in Cocoa, you may want to use Quartz directly.
For general information about Quartz features and how to use them, see Quartz 2D Programming Guide .
Using Quartz Features
Because Quartz implements some features that Cocoa does not, there may be times when you need to use
Quartz function calls from your Cocoa code. Because Cocoa uses Quartz for most drawing operations, mixing
the two technologies is not an issue.
Some of the Quartz features that are not supported directly by Cocoa include the following:
● Layers
● Gradients (also called shadings)
●
Image data sources
● Blend modes (Cocoa uses compositing modes instead)
● Masking images
● Transparency layers (for grouping content)
● Arbitrary patterns (other than images)
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
162
Incorporating Other Drawing TechnologiesIn each case, you are free to use Quartz functions to take advantage of these features. Some features can
produce data types that you can then incorporate back into a Cocoa object. (For example, you can use an
image data source to obtain a Quartz image (CGImageRef), which you can then use to create an NSImage
object.) In some cases, however, you may need to perform the entire operation using Quartz functions.
For information on how to use Quartz features, see Quartz 2D Programming Guide .
Graphics Type Conversions
When going back and forth between Cocoa and Quartz code,some conversion of data types may be necessary.
Table 9-1 shows the Cocoa equivalents of some basic Quartz types.
Table 9-1 Simple data-type conversions
Cocoa type Quartz type
NSRect CGRect
NSPoint CGPoint
NSSize CGSize
Although in each case the structure layout is the same, you cannot pass the Quartz data type directly to a
method expecting the Cocoa type. To convert, you must cast from one type to another, as shown in the
following example:
NSRect cocoaRect = *(NSRect*)&myCGRect;
Table 9-2 lists the Cocoa classes that approximate the behavior of specific Quartz data types. In some cases,
the Cocoa class wraps an instance of its Quartz counterpart, but that is not always true. In the case of shadows,
Quartz provides no direct data type for managing the shadow parameters; you must set shadows attributes
in Quartz using several different functions. In the case of layers, there are no Cocoa equivalents.
Table 9-2 Equivalent Cocoa and Quartz data types
Cocoa type Quartz type
NSGraphicsContext CGContextRef
NSAffineTransform CGAffineTransform
NSColor CGColorRef, CGPatternRef
NSFont CGFontRef
Incorporating Other Drawing Technologies
Using Quartz in Your Application
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
163Cocoa type Quartz type
NSGlyph CGGlyph
NSImage CGImageRef
NSBezierPath CGPathRef
NSShadow CGSize, CGColorRef
NSGradient (OS X v10.5 and later) CGShadingRef
No equivalent CGLayerRef
Because Cocoa types often wrap equivalent Quartz types, you should look at the Cocoa reference documentation
for information about how to get equivalent Quartz objects, if any. In many cases, Cocoa classes do not offer
direct access to their Quartz equivalent and you may need to create the Quartz type based on information in
the Cocoa object, such as in the following cases:
● To create a CGPathRef object from an NSBezierPath object, you must redraw the path using Quartz
function calls. Use the elementAtIndex:associatedPoints: method of NSBezierPath to retrieve
the path’s point information.
● To convert back and forth between CGColorRef and NSColor objects, get the color component values
from one object and use those values to create the other object. When creating colors, you may also need
to specify the color space for that color. For the most part, Quartz and Cocoa support the same color
spaces. If a color uses a custom color space, you can use the available ICC profile data to create the
appropriate color space object.
● To create an NSImage object from a Quartz image, you need to create the image object indirectly. For
information on how to do this, see “Using a Quartz Image to Create an NSImage” (page 95).
● To create Quartz shadows, you can use the methods of NSShadow to retrieve the color, offset, and blur
radius values prior to calling CGContextSetShadow or CGContextSetShadowWithColor.
Getting a Quartz Graphics Context
Before using any Quartz features, you need to obtain a Quartz graphics context (CGContextRef) for drawing.
For view-based drawing, you can get the context by sending a graphicsPort message to the current Cocoa
graphics context (NSGraphicsContext). This method returns a pointer that you can cast to a CGContextRef
data type and use in subsequent Quartz function calls.
Incorporating Other Drawing Technologies
Using Quartz in Your Application
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
164Creating a Cocoa Graphics Context Using Quartz
In OS X v10.4 and later, if you have an existing Quartz graphics context, you can create a Cocoa graphics context
object using the graphicsContextWithGraphicsPort:flipped: class method of NSGraphicsContext.
You then use the setCurrentContext: class method to make that context the current context.
Modifying the Graphics State
When mixing calls to Quartz and Cocoa, remember that many Cocoa classes maintain a local copy of some
graphics attributes normally associated with the Quartz graphics context. When such a class is ready to draw
its content, it modifiesthe graphicsstate to match itslocalsettings, drawsits content, and restoresthe graphics
state to its originalsettings. If you use Quartz to change an attribute that is maintained locally by a Cocoa class,
your changes may not be used.
If you make changesto the graphicsstate using the NSGraphicsContext class, your changes are immediately
conveyed to the Quartz graphics context, and vice versa. If you are not using NSGraphicsContext to set an
attribute, you should assume that the attribute is local to the object. For example, the NSBezierPath class
prefers local copies of graphics attributes over the default (or global) attributes stored in the current context.
Using OpenGL in Your Application
OpenGL is an open, cross-platform, three-dimensional (3D) graphics standard with broad industry support.
OpenGL eases the task of writing real-time 2D or 3D graphics applications by providing a mature,
well-documented graphics processing pipeline that supports the abstraction of current and future hardware
accelerators.
The sections that follow provide a glimpse into the techniques used to incorporate OpenGL drawing calls into
your Cocoa application. For more on OpenGL support in OS X, and for detailed examples of how to integrate
OpenGL into your Cocoa application, see OpenGL Programming Guide for Mac . For general information about
OpenGL, see Reference Library > Graphics & Imaging > OpenGL.
Using NSOpenGLView
One way to do OpenGL drawing is to add an OpenGL view (an instance of NSOpenGLView) to your window.
An OpenGL view behaves like any other view but also stores a pointer to an OpenGL graphics context object
(an instance of NSOpenGLContext). Storing the graphics context in the view eliminates the need for your
code to recreate the context during each drawing cycle, which can be expensive.
Incorporating Other Drawing Technologies
Using OpenGL in Your Application
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
165To use an OpenGL view in your program, you create a subclass of NSOpenGLView and add that view to your
window, either programmatically or using Interface Builder. When creating an OpenGL view programmatically,
you specify the pixel format object you want to associate with the view. A pixel format object (an instance of
NSOpenGLPixelFormat)specifiesthe buffers and other rendering attributes of the OpenGL graphics context.
For information on the meaning of different pixel format attributes, see OpenGL Programming Guide for Mac .
If you use Interface Builder to add your view to a window, you specify the pixel format information using the
inspector for your view. Interface Builder lets you specify some pixel attributes, but not all. To support other
attributes, you must replace the view’s pixel format object at runtime using the setPixelFormat: method.
Important: If you set the pixel format attributes programmatically, you must do so before getting the
OpenGL graphics context using the openGLContext method. The graphics context is created with the
current pixel format information and is not recreated if that information changes. Alternatively, you can
change the OpenGL graphics context at any time using the setOpenGLContext: method.
As with other views, you use your OpenGL view’s drawRect: method to draw the content of your view. When
your drawRect: method is invoked, the environment is automatically configured for drawing using the
OpenGL graphics context associated with your view.
Unlike with other graphics contexts, you do not need to restore the previous OpenGL graphics context when
you are done drawing. OpenGL does not maintain a stack of graphics contexts that need to be popped as they
are no longer needed. Instead, it simply uses the most recent context that was made current.
Creating an OpenGL Graphics Context
Before creating an OpenGL graphics context object, you first create a pixel format object
(NSOpenGLPixelFormat). The attributes you specify when creating your pixel format object determine the
rendering behavior of the graphics context. Once you have a valid pixel format object, you can create and
initialize your OpenGL graphics context object.
Listing 9-1 attempts to create an OpenGL graphics context that supports full-screen, double-buffered, 32-bit
drawing. If the desired renderer is available, it returns the context; otherwise, it returns nil.
Listing 9-1 Creating an OpenGL graphics context
- (NSOpenGLContext*)getMyContext
{
// Specify the pixel-format attributes.
NSOpenGLPixelFormatAttribute attrs[] =
{
Incorporating Other Drawing Technologies
Using OpenGL in Your Application
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
166NSOpenGLPFAFullScreen,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
0
};
// Create the pixel-format object.
NSOpenGLContext* myContext = nil;
NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc]
initWithAttributes:attrs];
// If the pixel format is valid, create the OpenGL context.
if (pixFmt != nil)
{
myContext = [[NSOpenGLContext alloc] initWithFormat:pixFmt
shareContext:NO];
}
[pixFmt release];
return myContext;
}
Because the creation of OpenGL graphics contexts depends on the currently available renderers, your code
should always verify that the desired objects were created before trying to use them. If creating an object fails,
you can always try to create it again using a different set of attributes.
Using QuickTime in Your Application
QuickTime is Apple's cross-platform multimedia technology designed to help you create and deliver video,
sound, animation, graphics, text, interactivity, and music. QuickTime supports dozens of file and compression
formats for images, video, and audio, including ISO-compliant MPEG-4 video and AAC audio.
You can incorporate QuickTime features into your Cocoa applications in one of two ways. The easiest way is
through the QuickTime Kit, which is a full-featured Objective-C based framework for the QuickTime interfaces.
If you are already familiar with the C-based QuickTime interfaces, you can use those instead.
Incorporating Other Drawing Technologies
Using QuickTime in Your Application
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
167Using the QuickTime Kit
The QuickTime Kit framework (QTKit.framework) works with QuickTime movies in Cocoa applications in OS
X. The QuickTime Kit framework was introduced in OS X v10.4 and was designed as an alternative to and
eventual replacement for the existing NSMovie and NSMovieView classes in Cocoa. This new framework
provides more extensive coverage of QuickTime functions and data types than had been offered by the
Application Kit classes. More importantly, the framework does not require Cocoa programmersto be conversant
with Carbon data types such as handles, aliases, file-system specifications, and so on.
The QuickTime Kit framework is available primarily in OS X v10.4 and later, but it is also supported in OS X
v10.3 with QuickTime 7 or later installed. For information on how to use the QuickTime Kit, see QuickTime Kit
Programming Guide . For a reference of the classes in the QuickTime Kit, see QTKit Framework Reference .
Using QuickTime C-Based Functions
Long before the introduction of the QuickTime Kit framework, QuickTime programs were written using a
C-based API. The QuickTime API encompasses thousands of functions and gives you the maximum flexibility
in managing QuickTime content. You can use this API in your Cocoa applications like you would any other
framework.
For an introduction toQuickTime,seeQuickTimeOverview. Forthe completeQuickTime reference,seeQuickTime
Framework Reference .
Using Quartz Composer Compositions
If yoursoftware runsin OS X v10.4 and later, you can use Quartz Composer to render complex graphical content.
Quartz Composer usesthe latestOS X graphicstechnologiesto create advanced graphical images and animations
quickly and easily. You use the Quartz Composer application to create composition files graphically and then
load those compositions into your Cocoa application and run them. Changing the behavior of your Cocoa
application is then as simple as updating the composition file.
Quartz Composer is especially suited for applications that want to perform complex image manipulations.
Through it, you gain easy access to features of Quartz 2D, Core Image, Core Video, OpenGL, QuickTime, MIDI
System Services, and Real Simple Syndication (RSS). Your application can render compositions for display or
provide the user with controls for manipulating the composition parameters.
For a detailed example showing you how to run a composition from your Cocoa application, see the chapter
“Using QCRenderer to Play a Composition” in Quartz Composer Programming Guide .
Incorporating Other Drawing Technologies
Using Quartz Composer Compositions
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
168Choosing the Right Imaging Technology
OS X includes several different technologies for manipulating images. Although the NSImage class provide a
robust feature set that is sufficient for many developer’s uses, there may be specific times when you need to
use other imaging technologies. Table 9-3 lists some of the other imaging technologies available and when
you might use each one of them.
Table 9-3 Imaging technologies
Image Description
technology
Quartz images are immutable data types that you use to manipulate bitmap data in
Quartz. Although NSImage is easier to use and provides automatic support for
resolution independence, you might need to create Quartz images if another API
you are using expects them. You can create a Quartz image by drawing into a
NSBitmapImageRep object or Quartz bitmap context and then extracting a
CGImageRef from there. Quartz images are part of the Application Services
framework.
Quartz Images
(CGImageRef)
Quartz layers are a mutable alternative to Quartz images. You can draw to layers
much like you would draw to an NSImage object. You do so by creating a context,
locking focus on that context, drawing, and retrieving an image object from the
results. Because they are implemented in video memory, layers can be very efficient
to use, especially if you need to draw the same image repeatedly. Quartz layers are
available in OS X v10.4 and later as part of the Application Services framework.
Quartz Layers
(CGLayerRef)
The Core Image framework is geared toward processing image data. You would use
this technology to apply visual effects or filters to existing bitmap images. Because
it is explicitly designed for manipulating bitmap images, you must convert your
images to a CIImage object before you do any processing. Core Image is available
in OS X v10.4 and later as part of the Quartz Core framework.
Core Image
(CIImage)
The Image I/O framework is geared towards developers who need more direct control
over reading and writing image data. You might use this framework to convert
imagesfrom one format to another or you might use it to add metadata to an image
created by your program. The features of Image I/O are available in OS X v10.4 and
later as part of the Application Services framework.
Image I/O
While not explicitly an imaging technology, the Core Animation framework is a smart
and efficient way to render images and other data inside a view. The framework
provides a cached backing store that makes it possible to do animations with a
minimal amount of redrawing. You might use this technology in place of NSImage
or other imaging technologies to create animation effects or other rapidly changing
graphics. It offers respectable animation performance without requiring you to use
low-level APIs such as OpenGL. The Core Animation framework is available in OS X
v10.5 and later as part of the Quartz Core framework.
Core
Animation
Incorporating Other Drawing Technologies
Choosing the Right Imaging Technology
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
169This table describes the changes to Cocoa Drawing Guide .
Date Notes
Added information on supporting offscreen drawing for high resolution
displays.
2012-09-19
Added “Drawing Offscreen Images Using a Block-Based Drawing Method
to Support High Resolution Displays” (page 89).
Updated “Guidelines for Using Images” (page 86).
2012-07-23 Updated links to guidelines on high resolution.
2011-01-18 Corrected reference to application icon image name constant.
2009-10-19 Corrected typos.
2009-01-06 Updated the guidelines associated with resolution independent drawing.
Updated advice for creating an NSImage from a CGImageRef. Updated
the discussion of screen coordinates.
2008-10-15
2007-10-31 Updated the content for OS X v10.5.
Added information about NSGradient and rounded rectangle support.
Updated the information about flipped coordinate systems.
Fixed bugs in several code examples.
Added guidance about which imaging technologies work best for different
types of operations.
Added the mathematical equations corresponding to the available
compositing operations.
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
170
Document Revision HistoryDate Notes
Fixed several code examples and added information about how to add a
ColorSync profile to a bitmap.
2006-10-03
Changed matrix values to match the values in NSAffineTransformStruct.
Fixed example for casting a CGRect to an NSRect.
2006-06-28
2006-04-04 Moved animation object details to "Animation Programming Guide."
New document that describes how to draw content from a Cocoa
application.
2006-03-08
This document replaces information about Cocoa drawing that was
previously published in BasicDrawing , Drawing and Images, TheDrawing
Environment, and OpenGL .
Document Revision History
2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved.
171Apple Inc.
© 2005, 2012 Apple Inc.
All rights reserved.
No part of this publication may be reproduced,
stored in a retrievalsystem, or transmitted, in any
form or by any means, mechanical, electronic,
photocopying, recording, or otherwise, without
prior written permission of Apple Inc., with the
following exceptions: Any person is hereby
authorized to store documentation on a single
computer for personal use only and to print
copies of documentation for personal use
provided that the documentation contains
Apple’s copyright notice.
No licenses, express or implied, are granted with
respect to any of the technology described in this
document. Apple retains all intellectual property
rights associated with the technology described
in this document. This document is intended to
assist application developers to develop
applications only for Apple-labeled computers.
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, Carbon, Cocoa, ColorSync,
Mac, Mac OS, Macintosh, Objective-C, OS X,
Quartz,QuickDraw,QuickTime, Spaces, and Xcode
are trademarks of Apple Inc., registered in the
U.S. and other countries.
Retina is a trademark of Apple Inc.
Adobe, Acrobat, and PostScript are trademarks
or registered trademarks of Adobe Systems
Incorporated in the U.S. and/or other countries.
Helvetica is a registered trademark of
Heidelberger Druckmaschinen AG, available from
Linotype Library GmbH.
OpenGL is a registered trademark of Silicon
Graphics, Inc.
Even though Apple has reviewed this document,
APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS
DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
PURPOSE.ASARESULT, THISDOCUMENT IS PROVIDED
“AS IS,” AND YOU, THE READER, ARE ASSUMING THE
ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL,OR CONSEQUENTIAL
DAMAGES RESULTING FROM ANY DEFECT OR
INACCURACY IN THIS DOCUMENT, even if advised of
the possibility of such damages.
THE WARRANTY AND REMEDIES SET FORTH ABOVE
ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL
OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,
agent, or employee is authorized to make any
modification, extension, or addition to this warranty.
Some states do not allow the exclusion or limitation
of implied warranties or liability for incidental or
consequential damages, so the above limitation or
exclusion may not apply to you. This warranty gives
you specific legal rights, and you may also have other
rights which vary from state to state.
Cryptographic Services
GuideContents
About Cryptographic Services 5
At a Glance 5
How to Use This Document 5
Prerequisites 5
See Also 6
Cryptography Concepts In Depth 7
What Is Encryption? 7
Types of Encryption 8
Symmetric Keys 8
Asymmetric Keys 9
Diffie-Hellman Key Exchange 11
Cryptographic Hash Functions 12
Digital Signatures 12
Digital Certificates 14
Encrypting and Hashing Data 19
Encryption Technologies Common to iOS and OS X 19
Keychain Services 19
Cryptographic Message Syntax Services 20
Certificate, Key, and Trust Services 20
Common Crypto 20
Encryption Technologies Specific to OS X 20
Security Transforms 20
CDSA/CSSM 21
OpenSSL 22
Encryption in iOS 22
Managing Keys, Certificates, and Passwords 23
Certificate, Key, and Trust Services 23
Keychain Services 24
To Learn More 24
Generating Random Numbers 25
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
2Generating Random Numbers in OS X 25
Generating Random Numbers in iOS 26
Transmitting Data Securely 27
Using the URL Loading System 28
CFNetwork 28
Secure Transport 29
OpenSSL 29
To Learn More 30
CDSA Overview 31
Apple CDSA Plug-ins 33
AppleCSP Module 33
AppleFileDL Module 33
AppleCSP/DL Module 34
AppleX509CL Module 34
AppleX509TP Module 34
CSSM Services 35
Cryptographic Services 35
Data Store Services 36
Certificate Services 36
Trust Policy Services 36
Authorization Computation Services 36
Document Revision History 37
Glossary 38
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
3
ContentsFigures
Cryptography Concepts In Depth 7
Figure 1-1 Asymmetric key encryption 10
Figure 1-2 Creating a digital signature 13
Figure 1-3 Verifying a digital signature 14
Figure 1-4 Anatomy of a digital certificate 15
Figure 1-5 Creating the certificates for the root CA and a secondary CA 16
Figure 1-6 Creating the certificate for an end user and signing a document with it 17
CDSA Overview 31
Figure A-1 OS X implementation of CDSA 32
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
4OS X and iOS provide a number of technologiesthat provide cryptographic services—encryption and decryption,
hashing, random number generation, secure network communication, and so on. These technologies can be
used to secure data at rest (when stored on your hard drive or other media), secure data in transit, determine
the identity of a third party, and build additional security technologies.
At a Glance
OS X and iOS provide a wide range of cryptographic services, including:
● Encryption and decryption (both general-purpose and special-purpose)
● Key management using keychains
● Cryptographically strong random number generation
● Secure communication (SSL and TLS)
● Secure storage using FileVault and iOS File Protection
How to Use This Document
“Cryptography Concepts In Depth” (page 7) provides a basic grounding in cryptographic concepts and
terminology. These concepts are not specific to OS X or iOS, but are necessary for understanding the rest of
the book.
“Encrypting Data” (page 19) describes the APIs available in OS X and iOS for general-purpose encryption.
Prerequisites
Before reading this document, you should be familiar with the conceptsin SecurityOverview and Secure Coding
Guide .
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
5
About Cryptographic ServicesSee Also
For more information about OS X authentication and authorization (built on top of encryption technologies),
read Authentication, Authorization, and Permissions Guide .
About Cryptographic Services
See Also
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
6The word cryptography (from Greek kryptos, meaning hidden) at its core refers to techniques for making data
unreadable to prying eyes. This is not a complete definition, however.
In practice, cryptography can includes a range of techniques that can be used for verifying the authenticity of
data (detecting modifications), determining the identity of a person or other entity, determining who sent a
particular message or created a particular piece of data, sending data securely across a network, locking files
securely behind a password or passphrase, and so on.
This chapter describes a number of these techniques, beginning with basic encryption, then moving on to
other cryptographic constructs built on top of it.
Note: This chapter repeats many of the concepts in Security Overview, but with additional detail
and depth. It may help to read that document before reading this chapter.
What Is Encryption?
Encryption is the transformation of data into a form in which it cannot be made sense of without the use of
some key. Such transformed data is referred to as ciphertext. Use of a key to reverse this process and return
the data to its original (cleartext or plaintext) form is called decryption. Most of the security APIs in OS X and
iOS rely to some degree on encryption of text or data. For example, encryption is used in the creation of
certificates and digital signatures, in secure storage of secrets in the keychain, and in secure transport of
information.
Encryption can be anything from a simple process of substituting one character for another—in which case
the key is the substitution rule—to a complex mathematical algorithm. For purposes of security, the more
difficult it is to decrypt the ciphertext, the better. On the other hand, if the algorithm is too complex, takes too
long to do, or requires keys that are too large to store easily, it becomes impractical for use in a personal
computer. Therefore,some balance must be reached between strength of the encryption (that is, how difficult
it is for someone to discover the algorithm and the key) and ease of use.
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
7
Cryptography Concepts In DepthFor practical purposes, the encryption need only be strong enough to protect the data for the amount of time
the data might be useful to a person with malicious intent. For example, if you need to keep your bid on a
contract secret only until after the contract has been awarded, an encryption method that can be broken in a
few weeks willsuffice. If you are protecting your credit card number, you probably want an encryption method
that cannot be broken for many years.
Types of Encryption
There are two main types of encryption in use in computer security, referred to as symmetric key encryption
and asymmetric key encryption . A closely related process to encryption, in which the data is transformed using
a key and a mathematical algorithm that cannot be reversed, is called cryptographic hashing. The remainder
of thissection discusses encryption keys, key exchange mechanisms(including the Diffie-Hellman key exchange
used in some OS X secure transport protocols), and cryptographic hash functions.
Symmetric Keys
Symmetric key cryptography (also called private key cryptography or secret key cryptography) is the classic
use of keysthat most people are familiar with: the same key is used to encrypt and decrypt the data. The classic,
and most easily breakable, version of this is the Caesar cipher (named for Julius Caesar), in which each letter
in a message is replaced by a letter that is a fixed number of positions away in the alphabet (for example, “a”
is replaced by “c”, “b” is replaced by “d”, and so forth). In this case, the key used to encrypt and decrypt the
message issimply the number of positionsin the alphabet to shift the letters. Modern symmetric key algorithms
are much more sophisticated and much harder to break. However, they share the property of using the same
key for encryption and decryption.
There are many different algorithms used for symmetric key cryptography, offering anything from minimal to
nearly unbreakable security. Some of these algorithms offer strong security, easy implementation in code, and
rapid encryption and decryption. Such algorithms are very useful for such purposes as encrypting files stored
on a computer to protect them in case an unauthorized individual uses the computer. They are somewhat less
useful forsending messagesfrom one computer to another, because both ends of the communication channel
must possess the key and must keep it secure. Distribution and secure storage of such keys can be difficult
and can open security vulnerabilities.
In 1968, the USS Pueblo , a U.S. Navy intelligence ship, was captured by the North Koreans. At the time, every
Navy ship carried symmetric keys for a variety of code machines at a variety of security levels. Each key was
changed daily. Because there was no way to know how many of these keys had not been destroyed by the
Pueblo’s crew and therefore were in the possession of North Korea, the Navy had to assume that all keys being
Cryptography Concepts In Depth
Types of Encryption
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
8carried by the Pueblo had been compromised. Every ship and shore station in the Pacific theater (that is,several
thousand installations, including ships at sea) had to replace all of their keys by physically carrying code books
and punched cards to each installation.
The Pueblo incident was an extreme case. However, it hassomething in common with the problem of providing
secure communication for commerce over the Internet. In both cases, codes are used for sending secure
messages, not between two locations, but between a server (the Internetserver or the Navy’s communications
center) and a large number of communicants (individual web users or ships and shore stations). The more end
users that are involved in the secure communications, the greater the problems of distribution and protection
of the secret symmetric keys.
Although secure techniques for exchanging or creating symmetric keys can overcome this problem to some
extent (for example, Diffie-Hellman key exchange, described later in this chapter), a more practical solution
for use in computer communications came about with the invention of practical algorithms for asymmetric
key cryptography.
Asymmetric Keys
In asymmetric key cryptography, different keys are used for encrypting and decrypting a message. The
asymmetric key algorithms that are most useful are those in which neither key can be deduced from the other.
In that case, one key can be made public while the other is kept secure. There are some distinct advantages
to this public-key–private-key arrangement, often referred to as public key cryptography: the necessity of
distributing secret keysto large numbers of usersis eliminated, and the algorithm can be used for authentication
as well as for cryptography.
The first public key algorithm to become widely available was described by Ron Rivest, Adi Shamir, and Len
Adleman in 1977, and is known as RSA encryption from their initials. Although other public key algorithms
have been created since, RSA is still the most commonly used. The mathematics of the method are beyond
the scope of this document, and are available on the Internet and in many books on cryptography. The algorithm
is based on mathematical manipulation of two large prime numbers and their product. Its strength is believed
to be related to the difficulty of factoring a very large number. With the current and foreseeable speed of
modern digital computers, the selection of long-enough prime numbers in the generation of the RSA keys
should make this algorithm secure indefinitely. However, this belief has not been proved mathematically, and
either a fast factorization algorithm or an entirely different way of breaking RSA encryption might be possible.
Also, if practical quantum computers are developed, factoring large numbers will no longer be an intractable
problem.
Other public key algorithms, based on different mathematics of equivalent complexity to RSA, include ElGamal
encryption and elliptic curve encryption. Their use issimilar to RSA encryption (though the mathematics behind
them differs), and they will not be discussed further in this document.
Cryptography Concepts In Depth
Types of Encryption
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
9To see how public key algorithms address the problem of key distribution, assume that Alice wants to receive
a secure communication from Bob. The procedure is illustrated in Figure 1-1.
Figure 1-1 Asymmetric key encryption
The secure message exchange illustrated in Figure 1-1 has the following steps:
1. Alice uses one of the public key algorithms to generate a pair of encryption keys: a private key, which she
keeps secret, and a public key. She also prepares a message to send to Bob.
2. Alice sends the public key to Bob, unencrypted. Because her private key cannot be deduced from the
public key, doing so does not compromise her private key in any way.
3. Alice can now easily prove her identity to Bob (a process known as authentication ). To do so, she encrypts
her message (or any portion of the message) using her private key and sends it to Bob.
4. Bob decrypts the message with Alice’s public key. This proves the message must have come from Alice,
as only she has the private key used to encrypt it.
Cryptography Concepts In Depth
Types of Encryption
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
105. Bob encrypts his message using Alice’s public key and sends it to Alice. The message is secure, because
even if it is intercepted, no one but Alice has the private key needed to decrypt it.
6. Alice decrypts the message with her private key.
Since encryption and authentication are subjects of great interest in nationalsecurity and protecting corporate
secrets, some extremely smart people are engaged both in creating secure systems and in trying to break
them. Therefore, itshould come as no surprise that actualsecure communication and authentication procedures
are considerably more complex than the one just described. For example, the authentication method of
encrypting the message with your private key can be got around by a man-in-the-middle attack, where
someone with malicious intent (usually referred to as Eve in books on cryptography) intercepts Alice’s original
message and replacesit with their own,so that Bob is using not Alice’s public key, but Eve’s. Eve then intercepts
each of Alice’s messages, decrypts it with Alice’s public key, alters it (if she wishes), and reencrypts it with her
own private key. When Bob receives the message, he decrypts it with Eve’s public key, thinking that the key
came from Alice.
Although this is a subject much too broad and technical to be covered in detail in this document, digital
certificates and digital signatures can help address these security problems. These techniques are described
later in this chapter.
Diffie-Hellman Key Exchange
The Diffie-Hellman key exchange protocol is a way for two ends of a communication session to generate
symmetric private keys through the exchange of public keys. The two sides agree beforehand on the exact
algorithm to use and certain parameters, such as the size of the keys. Then each side selects a random number
as a private key and uses that number to generate a public key, according to the algorithm. The security of
this algorithm dependsin part on it being extremely difficult to derive or guessthe private key from this public
key.
The two sides exchange public keys and then each generates a session key using their own private key and
the other side’s public key. The mathematics of the algorithm is such that, even though neither side knows
the other side’s private key, both sides’ session keys are identical. A third party intercepting the public keys
but lacking knowledge of either private key cannot generate a session key. Therefore, data encrypted with the
session key is secure while in transit.
Although Diffie-Hellman key exchange provides strong protection against compromise of intercepted data, it
provides no mechanism for ensuring that the entity on the other end of the connection is who you think it is.
That is, this protocol is vulnerable to a man-in-the-middle attack. Therefore, it is sometimes used together with
some other authentication method to ensure the integrity of the data.
Cryptography Concepts In Depth
Diffie-Hellman Key Exchange
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
11Diffie-Hellman key exchange is supported by Apple Filing Protocol (AFP) version 3.1 and later and by Apple’s
Secure Transport API. Because RSA encryption tends to be slower than symmetric key methods, Diffie-Hellman
(and other systems where public keys are used to generate symmetric private keys) can be useful when a lot
of encrypted data must be exchanged.
Cryptographic Hash Functions
A cryptographic hash function takes any amount of data and applies an algorithm that transforms it into a
fixed-size output value. For a cryptographic hash function to be useful, it has to be extremely difficult or
impossible to reconstruct the original data from the hash value, and it must be extremely unlikely that the
same output value could result from any other input data.
Sometimes it is more important to verify the integrity of data than to keep it secret. For example, if Alice sent
a message to Bob instructing him to shred some records (legally, of course), it would be important to Bob to
verify that the list of documents was accurate before proceeding with the shredding. Since the shredding is
legal, however, there is no need to encrypt the message, a computationally expensive and time-consuming
process. Instead, Alice could compute a hash of the message (called a message digest) and encrypt the digest
with her private key. When Bob receives the message, he decrypts the message digest with Alice’s public key
(thus verifying that the message is from Alice) and computes his own message digest from the message text.
If the two digests match, Bob knows the message has not been corrupted or tampered with.
The most common hash function you will use is SHA-1, an algorithm developed and published by the U.S.
Government that produces a 160-bit hash value from any data up to 2**64 bits in length. There are also a
number of more exotic algorithms such as SHA-2, elliptic-curve-based algorithms, and so on.
For compatibility with existing systems and infrastructure, you may occasionally need to use older algorithms
such as MD5, but they are not recommended for use in new designs because of known weaknesses.
Digital Signatures
Digital signatures are a way to ensure the integrity of a message or other data using public key cryptography.
Like traditionalsignatures written with ink on paper, they can be used to authenticate the identity of the signer
of the data. However, digital signatures go beyond traditional signatures in that they can also ensure that the
data itself has not been altered. This is like signing a check in such a way that if someone changes the amount
of the sum written on the check, an “Invalid” stamp becomes visible on the face of the check.
To create a digital signature, the signer generates a message digest of the data and then uses a private key to
encrypt the digest. The signature includes the encrypted digest and information about the signer’s digital
certificate. The certificate is used to verify the signature; it includesthe public key needed to decrypt the digest
Cryptography Concepts In Depth
Cryptographic Hash Functions
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
12and the algorithm used to create the digest. To verify that the signed document has not been altered, the
recipient uses the algorithm to create their own message digest and uses the public key to decrypt the digest
in the signature. If the two digests are identical, then the message cannot have been altered and must have
been sent by the owner of the public key.
To ensure that the person who provided the signature is not only the same person who provided the data but
is also who they say they are, the certificate is also signed—in this case by the certification authority who issued
the certificate.
Digital signatures play a key role in code signing. Developers are encouraged to sign their applications. On
execution, each application’ssignature is checked for validity. Digitalsignatures are required on all applications
for iOS. Read Code Signing Guide for details about how code signing is used by OS X and iOS.
Figure 1-2 illustrates the creation of a digital signature.
Figure 1-2 Creating a digital signature
CA signature CA signature
Cryptography Concepts In Depth
Digital Signatures
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
13Figure 1-3 illustrates the verification of a digital signature. The recipient gets the signer’s public key from the
signer’s certificate and uses that to decrypt the digest. Then, using the algorithm indicated in the certificate,
the recipient creates a new digest of the data and compares the new digest to the decrypted copy of the one
delivered in the signature. If they match, then the received data must be identical to the original data created
by the signer.
Figure 1-3 Verifying a digital signature
Hash
CA signature
Digital Certificates
A digital certificate is a collection of data used to verify the identity of the holder or sender of the certificate.
For example, an X.509 certificate contains such information as:
● Structural information—version,serial number, the message digest algorithm used to create the signature,
and so on
● A digital signature from the certificate authority to ensure that the certificate has not been altered and to
indicate the identity of the issuer
●
Information about the certificate holder—name, email address, company name, the owner’s public key,
and so on
● Validity period (the certificate is not valid before or after this period)
Cryptography Concepts In Depth
Digital Certificates
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
14● Attributes, known as certificate extensions, that contain additional information such as allowable uses
for this certificate
The careful reader will have noticed that a digital signature includes the certificate of the signer, and that the
signer’s certificate, in turn, contains a digital signature that includes another certificate. In general, each
certificate is verified through the use of another certificate, creating a chain of trust—a certificate chain that
ends with a root certificate. The issuer of a certificate is called a certification authority (CA). The owner of the
root certificate is the root certification authority. Figure 1-4 illustrates the anatomy of a digital certificate.
Figure 1-4 Anatomy of a digital certificate
Cryptography Concepts In Depth
Digital Certificates
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
15The root certificate is self-signed, meaning the signature of the root certificate was created by the root
certification authority themselves. Figure 1-5 and Figure 1-6 illustrate how a chain of certificates is created and
used. Figure 1-5 shows how the root certification authority creates its own certificate and then creates a
certificate for a secondary certification authority.
Figure 1-5 Creating the certificates for the root CA and a secondary CA
Cryptography Concepts In Depth
Digital Certificates
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
16Figure 1-6 shows how the secondary certification authority creates a certificate for an end user and how the
end user uses it to sign a document.
Figure 1-6 Creating the certificate for an end user and signing a document with it
In Figure 1-6, the creator of the document has signed the document. The signature indicates the certificate of
the document’s creator (labeled User in the figure). The document’s creator signs the document with a private
key, and the signing certificate contains the corresponding public key, which can be used to decrypt the
message digest to verify the signature (described earlier in “Digital Signatures”). This certificate—together with
the private and public keys—was provided by a certification authority (CA).
In order to verify the validity of the user’s certificate, the certificate is signed using the certificate of the CA.
The certificate of the CA includes the public key needed to decrypt the message digest of the user’s certificate.
Continuing the certificate chain, the certificate of the CA is signed using the certificate of the authority who
issued that certificate. The chain can go on through any number of intermediate certificates, but in Figure 1-5
Cryptography Concepts In Depth
Digital Certificates
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
17the issuer of the CA’s certificate is the root certification authority. Note that the certificate of the root CA, unlike
the others, is self-signed—that is, it does not refer to a further certification authority but is signed using the
root CA’s own private key.
When a CA creates a certificate, it uses its private key to encrypt the certificate’s message digest. The signature
of every certificate the CA issues refers to its own signing certificate. The CA’s public key is in this certificate,
and the application verifying the signature must extract this key to verify the certificate of the CA. So it continues,
on down the certificate chain, to the certificate of the root CA. When a root CA issues a certificate, it, too, signs
the certificate. However, this signing certificate was not issued by another CA; the chain stops here. Rather,
the root CA issues its own signing certificate, as shown in Figure 1-5.
The certificate of the root CA can be verified by creating a digest and comparing it with one widely available.
Typically, the root certificate and root CA’s public key are already stored in the application or on the computer
that needs to verify the signature.
It’s possible to end a certificate chain with a trusted certificate that is not a root certificate. For example, a
certificate can be certified as trusted by the user, or can be cross certified—that is, signed with more than one
certificate chain. The general term for a certificate trusted to certify other certificates—including root certificates
and others—is anchor certificate. Because most anchor certificates are root certificates, the two terms are
often used interchangeably.
The confidence you can have in a given certificate depends on the confidence you have in the anchor certificate;
for example, the trust you have in the certificate authorities and in their proceduresfor ensuring thatsubsequent
certificate recipients in the certificate chain are fully authenticated. For this reason, it is always a good idea to
examine the certificate that comes with a digital signature, even when the signature appears to be valid. In
OS X and iOS, all certificates you receive are stored in your keychain. In OS X, you can use the Keychain Access
utility to view them.
Certain attributes of a digital certificate (known as certificate extensions) are said to establish a level of trust
for a digital certificate. A trust policy is a set of rules that specify the appropriate uses for a certificate that has
a specific level of trust. In other words, the level of trust for a certificate is used to answer the question “Should
I trust this certificate for this action?”
For example, in order to be trusted to verify a digitally signed email message, a certificate must contain an
email address that matches the address of the sender of the email.
Cryptography Concepts In Depth
Digital Certificates
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
18Both symmetric and asymmetric key encryption schemes can be used to encrypt data. Asymmetric encryption
is most commonly used for sending data across trust boundaries, such as one person sending another person
an encrypted email. It is also often used forsending a symmetric session key across an insecure communication
channel so that symmetric encryption can then be used for future communication. Symmetric encryption is
most commonly used for data at rest (on your hard drive for example) and as a session key in a number of
encrypted networking schemes.
OS X and iOS provide a number of different APIs for encryption and decryption. This chapter describes the
recommended APIs.
Encryption Technologies Common to iOS and OS X
OS X and iOS provide a number of encryption technologies. Of these, three APIs are available on both iOS and
OS X:
● Keychain Services API—provides secure storage for passwords, keys, and so on
● Cryptographic Message Syntax—provides (non-streaming) symmetric and asymmetric encryption and
decryption
● Certificate, Key, and Trust Services—provides cryptographic support services and trust validation
The sections that follow describe these technologies.
Keychain Services
The Keychain Services API is commonly used to store passwords, keys, certificates, and othersecretsin a special
encrypted file called a keychain. You should always use the keychain to store passwords and othershort pieces
of data (such as cookies) that are used to grant access to secure web sites, as otherwise this data might be
compromised if an unauthorized person gains access to a user’s computer, mobile device, or a backup thereof.
Although this is mostly used for storing passwords and keys, the keychain can also store small amounts of
arbitrary data. The keychain is described further in the next chapter.
OS X also includes a utility that allows users to store and read the data in the keychain, called Keychain Access.
For more information, see “Keychain Access” in Security Overview.
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
19
Encrypting and Hashing DataCryptographic Message Syntax Services
The Cryptographic Message Syntax Services programming interface allows you to encrypt or add a digital
signature to S/MIME messages. It is a good API to use when signing or encrypting data for store-and-forward
applications, such as email. See Cryptographic Message Syntax Services Reference for details.
Certificate, Key, and Trust Services
The Certificate, Key, and Trust Services API provides trust validation and support functions for cryptography.
These features are described further in “Managing Keys, Certificates, and Passwords” (page 23).
In iOS, this API also provides basic encryption capabilities, as described in “Encryption in iOS” (page 22).
Common Crypto
In OS X v10.5 and later and iOS 5.0 and later, Common Crypto provides low-level C support for encryption and
decryption. Common Crypto is not as straightforward as Security Transforms, but provides a wider range of
features, including additional hashing schemes, cipher modes, and so on.
For more information, see the manual page for CommonCrypto.
Encryption Technologies Specific to OS X
In addition to Keychain Services and Cryptographic Message Syntax Services, OS X provides four additional
APIs for performing encryption:
● Security Transforms API—a Core-Foundation-level API that provides support for signing and verifying,
symmetric cryptography, and Base64 encoding and decoding
● Common Crypto—a C-level API that can perform most symmetric encryption and decryption tasks
● CDSA/CSSM—a legacy API thatshould be used only to perform tasks notsupported by the other two APIs,
such as asymmetric encryption
These APIs are described in the sections that follow.
Security Transforms
In OS X v10.7 and later, the Security Transforms API provides efficient and easy-to-use support for performing
cryptographic tasks. Security transforms are the recommended way to perform symmetric encryption and
decryption, asymmetric signing and verifying, and Base64 encoding and decoding in OS X.
Encrypting and Hashing Data
Encryption Technologies Specific to OS X
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
20Based on the concept of data flow programming, the Security Transforms API lets you construct graphs of
transformationsthat feed into one another, transparently using Grand Central Dispatch to schedule the resulting
work efficiently across multiple CPUs. As the CFDataRef (or NSData) objects pass through the object graph,
callbacks within each individual transform operate on that data, then pass it on to the transform’s output,
which may be connected to the input of another transform object, and so on.
The transform API also provides a file reader transform (based on CFReadStreamRef or NSInputStream
objects) that can be chained to the input of other transforms.
Out of the box, the Security Transforms API allows you to read files, perform symmetric encryption and
decryption, perform asymmetric signing and verifying, and perform Base64 encoding. The Security Transforms
API also provides support for creating custom transforms that perform other operations on data. For example,
you might create a transform that byte swaps data prior to encrypting it or a transform that encodes the
resulting encrypted data for transport.
For more information, read Security Transforms Programming Guide and Security Transforms Reference .
CDSA/CSSM
Important: CDSA (including CSSM) is deprecated and should not be used for new development. It is not
available in iOS.
CDSA is an Open Source security architecture adopted as a technical standard by the Open Group. Apple has
developed its own Open Source implementation of CDSA, available as part of Darwin at Apple’s Open Source
site. This API provides a wide array ofsecurity services, including fine-grained access permissions, authentication
of users’ identities, encryption, and secure data storage.
Although CDSA has its own standard application programming interface (API), it is complex and does not
follow standard Apple programming conventions. For thisreason, the CDSA API is deprecated as of OS X version
10.7 (Lion) and is not available in iOS. Fortunately, OS X and iOS include their own higher-level security APIs
that abstract away much of that complexity.
Where possible, you should use one of the following instead of using CDSA directly:
● The Security Objective-C API for authentication (in OS X). See “Security Objective-C API” in Security Overview
for details.
● The Security Transforms API for symmetric encryption and decryption, asymmetric signing and verifying,
and other supported tasks in OS X v10.7 and later. See “Security Transforms” (page 20) for details.
● The Certificate, Key, and Trust Services API for general encryption, key management, and other tasks. See
“Encryption in iOS” (page 22) for details.
Encrypting and Hashing Data
Encryption Technologies Specific to OS X
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
21If these APIs do not meet your needs, you can still use CDSA in OS X, but please file bugs at http://bugreport.apple.com/ to request the additional functionality that you need. For more information, read “CDSA
Overview” (page 31).
OpenSSL
Although OpenSSL is commonly used in the open source community, OpenSSL does not provide a stable API
from version to version. For this reason, although OS X provides OpenSSL libraries, the OpenSSL libraries in OS
X are deprecated, and OpenSSL has never been provided as part of iOS. Use of the OS X OpenSSL libraries by
applications is strongly discouraged.
If your application depends on OpenSSL, you should compile OpenSSL yourself and statically link a known
version of OpenSSL into your application. This use of OpenSSL is possible on both OS X and iOS. However,
unless you are trying to maintain source compatibility with an existing open source project, you should generally
use a different API.
Common Crypto and Security Transforms are the recommended alternativesfor general encryption. CFNetwork
and Secure Transport are the recommended alternatives for secure communications.
Encryption in iOS
In iOS, in addition to providing support functions for encoding and decoding keys, the Certificate, Key, and
Trust Services API also provides basic encryption, decryption, signing, and verifying of blocks of data using the
following SecKey functions:
SecKeyEncrypt—encrypts a block of data using the specified key.
SecKeyDecrypt—decrypts a block of data using the specified key.
SecKeyRawSign—signs a block of data using the specified key.
SecKeyRawVerify—verifies a signature against a block of data and a specified key.
You can find examples of how to use these functions in “Certificate, Key, and Trust Services Tasks for iOS” in
Certificate, Key, and Trust Services Programming Guide .
For detailed reference content, read Certificate, Key, and Trust Services Reference .
Encrypting and Hashing Data
Encryption in iOS
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
22The keychain provides storage for passwords, encryption keys, certificates, and other small pieces of data.
After an application requests access to a keychain, it can store and retrieve sensitive data, confident that
untrusted applications cannot access that data without explicit action by the user.
In OS X, the user is prompted for permission when an application needs to access the keychain; if the keychain
is locked, the user is asked for a password to unlock it.
In iOS, an application can access only its own items in the keychain—the user is never asked for permission or
for a password.
There are two recommended APIs for accessing the keychain:
● Certificate, Key, and Trust Services
● Keychain Services
Certificate, Key, and Trust Services
Certificate, Key, and Trust Services is a C API for managing certificates, public and private keys, and trust
policies in iOS and OS X. You can use these services in your application to:
● Create certificates and asymmetric keys
● Add certificates and keys to keychains, remove them from keychains, and use keys to encrypt and decrypt
data
● Retrieve information about a certificate, such as the private key associated with it, the owner, and so on
● Convert certificates to and from portable representations
● Create and manipulate trust policies and evaluate a specific certificate using a specified set of trust policies
● Add anchor certificates
In OS X, functions are also available to retrieve anchor certificates and set user-specified settings for trust
policies for a given certificate.
In iOS, additional functions are provided to:
● Use a private key to generate a digital signature for a block of data
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
23
Managing Keys, Certificates, and Passwords● Use a public key to verify a signature
● Use a public key to encrypt a block of data
● Use a private key to decrypt a block of data
Certificate, Key, and Trust Services operates on certificates that conform to the X.509 ITU standard, uses the
keychain for storage and retrieval of certificates and keys, and uses the trust policies provided by Apple.
Because certificates are used by SSL and TLS for authentication, the OS X Secure Transport API includes a variety
of functions to manage the use of certificates and root certificates in a secure connection.
To display the contents of a certificate in an OS X user interface, you can use the SFCertificatePanel and
SFCertificateView classes in the Security Objective-C API. In addition, the SFCertificateTrustPanel
class displays trust decisions and lets the user edit trust decisions.
Keychain Services
In OS X and iOS, Keychain Services allows you to create keychains, add, delete, and edit keychain items, and—in
OS X only—manage collections of keychains. In most cases, a keychain-aware application does not have to do
any keychain management and only has to call a few functions to store or retrieve passwords.
By default, backups of iOS data are stored in cleartext, with the exception of passwords and other secrets on
the keychain, which remain encrypted in the backup. It is therefore important to use the keychain to store
passwords and other data (such as cookies) that are used to accesssecure web sites. Otherwise, this data might
be compromised if an unauthorized person gains access to the backup data.
To get started using Keychain Services, see Keychain Services Programming Guide and Keychain Services
Reference .
In OS X, the Keychain Access application provides a user interface to the keychain. See “Keychain Access” in
Security Overview for more information about this application.
To Learn More
For more information about using Keychain Servicesto store and retrieve secrets and certificates, read Keychain
Services Programming Guide and Keychain Services Reference .
Tor more information about Secure Transport, read “Secure Transport” (page 29).
For more information about the certificate user interface API, read “SecurityObjective-C API” in SecurityOverview.
Managing Keys, Certificates, and Passwords
Keychain Services
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
24Cryptographically secure pseudorandomnumbers are required for a number of encryption algorithms. Because
these pseudorandom numbers are generated by a computer algorithm, they are not truly random. However,
the algorithm is not discernible from the sequence.
The way you generate random numbers depends on whether you are writing code for OS X or iOS.
Generating Random Numbers in OS X
In OS X, you can get cryptographically secure pseudorandom numbers by reading from /dev/random.
Important: Numbers generated by the rand and random APIs are not cryptographically secure. In OS X,
given the same initial seed value, both functions reproducibly generate a consistent sequence of values
each time you run them, and neither generates an equally distributed set of possible values.
For example, if you need a random 64-bit integer value, you could write code like this:
FILE *fp = fopen("/dev/random", "r");
if (!fp) {
perror("randgetter");
exit(-1);
}
uint64_t value = 0;
int i;
for (i=0; i Add Keychain menu item to add them to your list of keychains) to see
what they contain and how the certificate chains are constructed.
A trust policy (TP) plug-in performs two main functions: it assembles the chain of certificates needed to verify
a given certificate, and it determines the level of trust that can be accorded the certificate.
The AppleX509TP module performs these functions on X.509 certificates, using trust policies established by
Apple.
CSSM Services
Although the OS X security APIs provide all the capabilities you are ever likely to need for developing secure
applications, nearly all the standard CSSM APIs are also available for your use. This section briefly describes
the functions provided by each CSSM service. For details, see Common Security: CDSA and CSSM, version 2
(with corrigenda), from the Open Group.
Cryptographic Services
Cryptographic Services in CSSM provides functions to perform the following tasks:
● Encrypting and decrypting text and data
● Creating and verifying digital signatures
● Creating a cryptographic hash (used for message digests and other purposes)
● Generating symmetric and asymmetric pairs of cryptographic keys
● Generating pseudorandom numbers
● Controlling access to the CSP for creation of keys
To see exactly which security protocols and algorithms are supported by Apple’s CSP implementation, see the
documentation provided with the Open Source security code, which you can download at Apple’s Open Source
site, and the Security Release Notes in the latest Xcode Tools from Apple.
CDSA Overview
CSSM Services
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
35Data Store Services
CSSM Data Store Services provides an API for storing and retrieving data that is independent of the type of
storage used. If there is more than one DL module installed, the caller can query Data Store Services to learn
the capabilities of each and select which one to use in a particular call. The Apple implementation of Data
Store Services supports any standard CDSA DL plug-in module. The AppleFileDL Data Storage Library and
AppleCSP/DL Encrypted Data Storage module both implement functions called by Data Store Services.
Certificate Services
Certificate Services as specified by CDSA performs the following functions:
● Verifies the signatures on certificates and certificate revocation lists
● Creates certificates and certificate revocation lists
● Signs certificates and certificate revocation lists
● Extracts values of fields from certificates and certificate revocation lists
● Searches certificate revocation lists for specified certificates
Apple’s implementation of Certificate Services supports all of the CL API functions in the CDSA/CSSM
specification.
Trust Policy Services
The OS X implementation of CSSM Trust Policy Services provides functions to verify certificates, to determine
what attributes they contain and therefore the level of trust they can be given, and to construct a chain of
related certificates. It does not implement other trust policy functions in the CSSM standard. Documentation
for the CSSM trust policy functions supported by Apple’s TP implementation can be found with the Open
Source security code, which you can download at Apple’s Open Source site.
Authorization Computation Services
Apple’s implementation of CSSM does not include the Authorization Computation Services defined in the
CDSA standard. Instead, the Authorization Services API calls the Security Server daemon directly (see Figure
A-1 (page 32)).
CDSA Overview
CSSM Services
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
36This table describes the changes to Cryptographic Services Guide .
Date Notes
2012-09-19 Updated artwork and made minor editorial fixes.
New document that describesthe encryption, decryption,signing, hashing,
and other cryptographic technologies in OS X and iOS.
2012-01-09
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
37
Document Revision Historyalgorithm A sequence of actions to accomplish
some task. In cryptography, refers to a sequence of
actions, usually mathematical calculations,
performed on data to encrypt or decrypt it.
anchor certificate A digital certificate trusted to be
valid, which can then be used to verify other
certificates. An anchor certificate can be a root
certificate, a cross-certified certificate (that is, a
certificate signed with more than one certificate
chain), or a locally defined source of trust.
asymmetric keys A pair of related but dissimilar
keys, one used for encrypting and the other used
for decrypting a message or other data. See also
public key cryptography. Compare symmetric keys.
authentication The process by which a person or
other entity (such as a server) proves that it is who
(or what) it says it is. Compare authorization;
identification.
authorization The process by which an entity such
as a user or a server gets the right to perform a
operation that only specific entities are allowed to
perform. (Authorization can also refer to the right
itself, as in “Bob has the authorization to run that
program.”) Authorization usually involves first
authenticating the entity and then determining
whether it hasthe appropriate permissions. Compare
authentication.
BSD Berkeley Software Distribution. BSD is a form
of the UNIX operating system and providesthe basis
for the OS X file system, including file access
permissions.
CA See certification authority (CA).
CDSA Abbreviation for Common Data Security
Architecture. An open software standard for a
security infrastructure that provides a wide array of
security services, including fine-grained access
permissions, authentication of users, encryption, and
secure data storage. CDSA has a standard application
programming interface, called CSSM. In addition, OS
X includes its own security APIs that call the CDSA
API for you. See also CDSA plug-in.
CDSA plug-in A software module that connects to
CDSA through a standard interface and that
implements or extends CDSA security services for a
particular operating system and hardware
environment.
certificate See digital certificate.
certificate authority See certification authority (CA).
certificate chain A sequence of related digital
certificates that are used to verify the validity of a
digital certificate. Each certificate is digitally signed
using the certificate of its certification authority (CA).
This creates a chain of certificates ending in an
anchor certificate.
certificate extension A data field in a digital
certificate containing information such as allowable
uses for the certificate.
Certificate, Key, and Trust Services An API you can
use to create, manage, and read certificates; add
certificates to a keychain; create encryption keys;
and manage trust policies. In iOS, you can also use
this API to encrypt, decrypt, and sign data.
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
38
Glossarycertification authority (CA) The issuer of a digital
certificate. In order for the digital certificate to be
trusted, the certification authority must be a trusted
organization that authenticates an applicant before
issuing a certificate.
CFHTTP An API that you can use to create,serialize,
deserialize, and manage HTTP protocol messages,
including secure HTTPS messages. This component
lets you add authentication information to a
message. CFHTTP is a component of CFNetwork and
is built on top of CFStream.
CFNetwork A high-level API used for creating,
sending, and receiving serialized messages over a
network. CFNetwork is built on top of Secure
Transport, and so can use the Secure Sockets Layer
(SSL) and Transport Layer Security (TLS) secure
networking protocols.
CFStream An API that creates and manages the
read and write streams that CFHTTP depends on.
CFStream is a component of CFNetwork and is built
on top of Secure Transport. You can specify a Secure
Sockets Layer (SSL) or Transport Layer Security (TLS)
protocol version to encrypt and decrypt the data
stream.
chain of trust See certificate chain.
cipher A scheme for encrypting data.
ciphertext Text or other data that has been
encrypted. Compare cleartext.
cleartext Ordinary, unencrypted data. Compare
ciphertext.
code signing The addition of a digital signature to
an application or block of code.
credentials Data that can be used to identify,
authenticate, or authorize an entity. For example, a
user name and password constitute authentication
credentials. A Kerberos ticket, consisting of an
encrypted session key and other information, is an
example of an identification credential.
cryptographic hash function An algorithm that
takes any amount of data and transforms it into a
fixed-size output value. For a cryptographic hash
function to be useful for security, it has to be
extremely difficult or impossible to reconstruct the
original data from the hash value, and it must be
extremely unlikely that the same output value could
result from any other input data. See also message
digest.
cryptographic hashing The process whereby data
is transformed using a cryptographic hash function.
CSSM Abbreviation for Common Security Services
Manager. A public application programming
interface for CDSA. CSSM also defines an interface
for plug-ins that implement security services for a
particular operating system and hardware
environment.
decryption The transformation of ciphertext back
into the original cleartext. Compare encryption. See
also asymmetric keys; symmetric keys.
Diffie-Hellman key exchange A protocol that
provides a way for two ends of a communication
session to generate symmetric private keys through
the exchange of public keys.
digest See message digest.
digital certificate A collection of data used to verify
the identity of the holder orsender of the certificate.
OS X and iOS support the X.509 standard for digital
certificates. See also certificate chain.
digital ID See digital certificate.
Glossary
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
39digital signature A way to ensure the integrity of
a message or other data using public key
cryptography. To create a digitalsignature, the signer
generates a message digest of the data and then
uses a private key to encrypt the digest. The
signature includes the encrypted digest and
identifies the signer. Anyone wanting to verify the
signature uses the signer’s digital certificate, which
containsthe public key needed to decrypt the digest
and specifiesthe algorithm used to create the digest.
encryption The transformation of data into a form
in which it cannot be made sense of without the use
of some key. Such transformed data is referred to as
ciphertext. Use of a key to reverse this process and
return the data to its original (or cleartext) form is
called decryption.
hash algorithm See cryptographic hash function.
identification The process by which a process
verifies that a person or entity is the same one it
communicated with previously. Identification is in
general faster than authentication and does not
require interaction with the user.
identity A digital certificate together with an
associated private key.
key A piece of secret information required to
decode an encrypted message. In modern
cryptographic methods, it is usually a lengthy
integer.
keychain A database in OS X and iOS used to store
encrypted passwords, private keys, and othersecrets.
It is also used to store certificates and other
non-secret information that is used in cryptography
and authentication. Applications can use the
keychain services API (or the legacy keychain
manager API) to manipulate data in the keychain.
Users can also access keychain data using the
Keychain Access utility.
Keychain Access An OS X utility that enables users
to view and modify the data stored in the keychain.
Keychain Services An API forsecurely storing small
amounts of data on the keychain.
level of trust The confidence you can have in the
validity of a certificate, based on the certificates in
its certificate chain and on the certificate extensions
the certificate contains. The level of trust for a
certificate is used together with the trust policy to
answer the question “Should I trust this certificate
for this action?”
man-in-the-middle attack An attack on a
communication channel in which the attacker can
intercept messages going between two parties
without the communicating parties’ knowledge.
Typically, the man in the middle substitutes
messages and even cryptographic keys to
impersonate one party to the other.
message digest The result of applying a
cryptographic hash function to a message or other
data. A cryptographically secure message digest
cannot be transformed back into the original
message and cannot (or is very unlikely to) be
created from a different input. Message digests are
used to ensure that a message has not been
corrupted or altered. For example, they are used for
this purpose in digital signatures. The digital
signature includes a digest of the original message,
and the recipient prepares their own digest of the
received message. If the two digests are identical,
then the recipient can be confident that the message
has not been altered or corrupted.
MIME Acronym for Multipurpose Internet Mail
Extensions. A standard for transmitting formatted
text, hypertext, graphics, and audio in electronic mail
messages over the Internet.
PKI See public key infrastructure (PKI).
Glossary
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
40plaintext See cleartext.
plug-in A code module that uses a standard
interface to implement certain features of a program
or extend the program. See also CDSA plug-in.
private key A cryptographic key that must be kept
secret. Whereas a pair of identical private keys can
be used as symmetric keys, asymmetric keys consist
of one private key and one public key.
pseudorandom number A number generated by
an algorithm that produces a series of numbers with
no discernible pattern. It should be impossible or
nearly impossible to deduce the algorithm from such
a series. However, unlike a truly random number
generator, a pseudorandom number generator
always produces the same series if the algorithm is
given the same starting value or values.
public key A cryptographic key that can be shared
or made public without compromising the
cryptographic method. See also public key
cryptography.
public key certificate See digital certificate.
public key cryptography A cryptographic method
using asymmetric keys in which one key is made
public while the other (the private key ) is kept
secure. Data encrypted with one key must be
decrypted with the other. If the public key is used
to encrypt the data, only the holder of the private
key can decrypt it; therefore the data is secure from
unauthorized use. If the private key is used to
encrypt the data, anyone with the public key can
decrypt it. Because only the holder of the private
key could have encrypted it, however,such data can
be used for authentication. See also digital certificate;
digital signature.
public key infrastructure (PKI) As defined by the
X.509 standard, a PKI isthe set of hardware,software,
people, policies, and procedures needed to create,
manage, store, distribute, and revoke digital
certificates that are based on public key
cryptography.
quantum computer A computer in which the logic
gates are based on quantum phenomena such as
electron spin rather than mechanical or conventional
electronic components. Because of the superposition
of quantum states(a consequence of the Heisenberg
Uncertainty Principle), a properly designed quantum
computer can in principle perform simultaneously
certain types of calculations that require a huge
number of sequential operations in a classic
computer. Consequently, factoring large numbers
should be several orders of magnitude faster on a
quantum computer than on present-day
supercomputers. Because the strength of most
modern cryptographic methods depends on the
difficulty of making such calculations, a practical
quantumcomputer would breakmost cryptographic
schemes in common use. Although small
proof-of-concept quantum computers have been
constructed, no such machine capable of solving
practical problems has yet been demonstrated.
Randomization Services An iOS API that produces
cryptographically secure pseudorandom numbers.
root certificate A certificate that can be verified
without recourse to another certificate. Rather than
being signed by a further certification authority (CA),
a root certificate is verified using the widely available
public key of the CA that issued the root certificate.
Compare anchor certificate.
root certification authority The certification
authority that owns the root certificate.
Glossary
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
41RSA encryption A system of public key
cryptography, named for its inventors: Ron Rivest,
Adi Shamir, and Leonard Adleman. The RSA
algorithm takestwo large prime numbers, findstheir
product, and then derives asymmetric keysfrom the
prime numbers and their product. Because the public
key includes the product, the private key could be
derived from the public key if the product could be
factored. No easy method for factoring products of
large prime numbers is currently known, but it has
not been mathematically proven that no such
method is possible. Therefore, the discovery of a fast
way to factor such numbers, or the development of
quantum computers, would break RSA.
secret key A cryptographic key that cannot be made
public without compromising the security of the
cryptographic method. In symmetric key
cryptography , the secret key is used both to encrypt
and decrypt the data. In asymmetric key
cryptography , a (secret) private key is paired with a
public key. Whichever one is used to encrypt the
data, the other is used to decrypt it. See also public
key; public key cryptography.
Secure Sockets Layer(SSL) A protocol that provides
secure communication over a TCP/IP connection
such as the Internet. It uses digital certificates for
authentication and digital signatures to ensure
message integrity, and can use public key
cryptography to ensure data privacy. An SSL service
negotiates a secure session between two
communicating endpoints. SSL is built into all major
browsers and web servers. SSL has been superseded
by Transport Layer Security (TLS).
secure storage Storage of encrypted data on disk
or another medium that persists when the power is
turned off.
Secure Transport The OS X and iPhone
implementation of Secure Sockets Layer (SSL) and
Transport Layer Security (TLS), used to create secure
connections over TCP/IP connections such as the
Internet. On OS X, Secure Transport includes an API
that is independent of the underlying transport
protocol. The CFNetwork and URL Loading System
APIs use the services of Secure Transport.
session key A cryptographic key calculated or
issued for use only for the duration of a specific
communication session. Session keys are used, for
example, by the Diffie-Hellman key exchange and
Kerberos protocols.
S/MIME Acronym for Secure Multipurpose Internet
Mail Extensions. A specification that adds digital
signature authentication and encryption to electronic
mail messages in MIME format.
SSL See Secure Sockets Layer (SSL).
strength A measure of the amount of effort
required to break a security system. For example,
the strength of RSA encryption is believed to be
related to the difficulty of factoring the product of
two large prime numbers.
symmetric keys A pair of identical keys used to
encrypt and decrypt data. See also private key.
Compare asymmetric keys.
TLS See Transport Layer Security (TLS).
Transport Layer Security (TLS) A protocol that
provides secure communication over a TCP/IP
connection such as the Internet. It uses digital
certificates for authentication and digital signatures
to ensure message integrity, and can use public key
cryptography to ensure data privacy. A TLS service
negotiates a secure session between two
communicating endpoints. TLS is built into recent
versions of all major browsers and web servers. TLS
Glossary
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
42is the successor to SSL. Although the TLS and SSL
protocols are not interoperable, Secure Transport
can back down to SSL 3.0 if a TLS session cannot be
negotiated.
trust See level of trust.
trust policy A set of rules that specify the
appropriate uses for a certificate that has a specific
level of trust. For example, the trust policy for a
browser might state that if a certificate has an SSL
certificate extension, but the certificate has expired,
the user should be prompted for permission before
a secure session is opened with a web server.
URL Loading System An API that you can use to
access the contents of http://, https://, and ftp://
URLs. Because https:// websites use Secure Sockets
Layer (SSL) or Transport Layer Security (TLS) to
protect data transfers, you can use the URL Loading
System as a secure transport API. The URL Loading
System is layered on top of CFNetwork.
X.509 A standard for digital certificates promulgated
by the International Telecommunication Union (ITU).
The X.509 ITU standard is widely used on the Internet
and throughout the information technology industry
for designing secure applications based on a public
key infrastructure (PKI).
Glossary
2012-09-19 | © 2012 Apple Inc. All Rights Reserved.
43Apple Inc.
© 2012 Apple Inc.
All rights reserved.
No part of this publication may be reproduced,
stored in a retrievalsystem, or transmitted, in any
form or by any means, mechanical, electronic,
photocopying, recording, or otherwise, without
prior written permission of Apple Inc., with the
following exceptions: Any person is hereby
authorized to store documentation on a single
computer for personal use only and to print
copies of documentation for personal use
provided that the documentation contains
Apple’s copyright notice.
No licenses, express or implied, are granted with
respect to any of the technology described in this
document. Apple retains all intellectual property
rights associated with the technology described
in this document. This document is intended to
assist application developers to develop
applications only for Apple-labeled computers.
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, Cocoa, FileVault, iPhone,
Keychain, Numbers, Objective-C, OS X, and Xcode
are trademarks of Apple Inc., registered in the
U.S. and other countries.
UNIX is a registered trademark of The Open
Group.
iOS is a trademark or registered trademark of
Cisco in the U.S. and other countries and is used
under license.
Even though Apple has reviewed this document,
APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS
DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
PURPOSE.ASARESULT, THISDOCUMENT IS PROVIDED
“AS IS,” AND YOU, THE READER, ARE ASSUMING THE
ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL,OR CONSEQUENTIAL
DAMAGES RESULTING FROM ANY DEFECT OR
INACCURACY IN THIS DOCUMENT, even if advised of
the possibility of such damages.
THE WARRANTY AND REMEDIES SET FORTH ABOVE
ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL
OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,
agent, or employee is authorized to make any
modification, extension, or addition to this warranty.
Some states do not allow the exclusion or limitation
of implied warranties or liability for incidental or
consequential damages, so the above limitation or
exclusion may not apply to you. This warranty gives
you specific legal rights, and you may also have other
rights which vary from state to state.
Resource Programming
GuideContents
About Resources 5
At a Glance 5
Nib Files Store the Objects of Your Application’s User Interface 6
String Resources Containing Localizable Text 6
Images, Sounds, and Movies Represent Pre-rendered Content 6
Property Lists and Data Files Separate Data from Code 7
iOS Supports Device-Specific Resources 7
See Also 8
Nib Files 9
Anatomy of a Nib File 9
About Your Interface Objects 10
About the File’s Owner 10
About the First Responder 10
About the Top-Level Objects 11
About Image and Sound Resources 11
Nib File Design Guidelines 11
The Nib Object Life Cycle 12
The Object Loading Process 12
Managing the Lifetimes of Objects from Nib Files 15
Top-level Objects in OS X May Need Special Handling 17
Legacy Patterns 17
Action Methods 20
Built-In Support For Nib Files 21
The Application Loads the Main Nib File 22
Each View Controller Manages its Own Nib File 22
Document and Window Controllers Load Their Associated Nib File 22
Loading Nib Files Programmatically 23
Loading Nib Files Using NSBundle 23
Getting a Nib File’s Top-Level Objects 25
Loading Nib Files Using UINib and NSNib 27
Replacing Proxy Objects at Load Time 28
Accessing the Contents of a Nib File 30
Connecting Menu Items Across Nib Files 30
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
2String Resources 32
Creating Strings Resource Files 33
Choosing Which Strings to Localize 33
About the String-Loading Macros 34
Using the genstrings Tool to Create Strings Files 35
Creating Strings Files Manually 36
Detecting Non-localizable Strings 37
Loading String Resources Into Your Code 37
Using the Core Foundation Framework 38
Using the Foundation Framework 39
Examples of Getting Strings 39
Advanced Strings File Tips 40
Searching for Custom Functions With genstrings 40
Formatting String Resources 41
Using Special Characters in String Resources 41
Debugging Strings Files 42
Image, Sound, and Video Resources 43
Images and Sounds in Nib Files 43
Loading Image Resources 43
Loading Images in Objective-C 44
Loading Images Using Quartz 45
Specifying High-Resolution Images in iOS 46
Data Resource Files 48
Property List Files 48
OS X Data Resource Files 48
Document Revision History 50
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
3
ContentsTables and Listings
Nib Files 9
Listing 1-1 Loading a nib file from the current bundle 24
Listing 1-2 Loading a nib in an iPhone application 25
Listing 1-3 Using outlets to get the top-level objects 25
Listing 1-4 Getting the top-level objects from a nib file at runtime 26
Listing 1-5 Loading a nib file using NSNib 28
Listing 1-6 Replacing placeholder objects in a nib file 29
String Resources 32
Table 2-1 Common parameters found in string-loading routines 37
Listing 2-1 A simple strings file 32
Listing 2-2 Strings localized for English 36
Listing 2-3 Strings localized for German 36
Listing 2-4 Strings with formatting characters 41
Image, Sound, and Video Resources 43
Listing 3-1 Loading an image resource 44
Listing 3-2 Using data providers to load image resources 45
Data Resource Files 48
Table 4-1 Other resource types 49
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
4Applied to computer programs, resources are data filesthat accompany a program’s executable code. Resources
simplify the code you have to write by moving the creation of complex sets of data or graphical content outside
of your code and into more appropriate tools. For example, rather than creating images pixel by pixel using
code, it is much more efficient (and practical) to create them in an image editor. To take advantage of a resource,
all your code has to do is load it at runtime and use it.
In addition to simplifying your code, resources are also an intimate part of the internationalization process for
all applications. Rather than hard-coding strings and other user-visible content in your application, you can
place that content in external resource files. Localizing your application then becomes a simple process of
creating new versions of each resource file for each supported language. The bundle mechanism used in both
OS X and iOS provides a way to organize localized resources and to facilitate the loading of resource files that
match the user’s preferred language.
This document provides information about the types of resources supported in OS X and iOS and how you
use those resources in your code. This document does not focus on the resource-creation process. Most
resources are created using either third-party applications or the developer tools provided in the
/Developer/Applications directory. In addition, although this document refers to the use of resources in
applications, the information also applies to other types of bundled executables, including frameworks and
plug-ins.
Before reading this document, you should be familiar with the organizationalstructure imposed by application
bundles. Understanding this structure makes it easier to organize and find the resource files your application
uses. For information on the structure of bundles, see Bundle Programming Guide .
At a Glance
Applications can contain many types of resources but there are several that are supported directly by iOS and
OS X.
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
5
About ResourcesNib Files Store the Objects of Your Application’s User Interface
Nib files are the quintessential resource type used to create iOS and Mac apps. A nib file is a data archive that
essentially contains a set of freeze-dried objects that you want to recreate at runtime. Nib files are used most
commonly to store preconfigured windows, views, and other visually oriented objects but they can also store
nonvisual objects such as controllers.
You create nib files using the Interface Builder application, which provides a graphical assembly area for
assembling your objects. When you subsequently load a nib file into your application, the nib-loading code
instantiates each object in the file and restores it to the state you specified in Interface Builder. Thus, what you
see in Interface Builder is really what you get in your application at runtime.
Relevant Chapters: “Nib Files” (page 9)
String Resources Containing Localizable Text
Text is a prominent part of most user interfaces but also a resource that is most affected by localization changes.
Rather than hard-coding text into your code, iOS and OS X support the storage of user-visible text in strings
files, which are human-readable text files (in the UTF-16 encoding) containing a set of string resources for an
application. (The use of the plural “strings” in is deliberate and due to the .strings filename extension used
by files of that type.) Strings files greatly simplify the internationalization and localization process by allowing
you to write your code once and then load the appropriately localized text from resource files that can be
changed easily.
The Core Foundation and Foundation frameworks provide the facilities for loading text from strings files.
Applications that use these facilities can also take advantage of tools that come with Xcode to generate and
maintain these resource files throughout the development process.
Relevant Chapters: “String Resources” (page 32)
Images, Sounds, and Movies Represent Pre-rendered Content
Images, sound, and movie resources play an important role in iOS and Mac apps. Images are responsible for
creating the unique visual style used by each operating system; they also help simplify your drawing code for
complex visual elements. Sound and movie files similarly help enhance the overall user experience of your
application while simplifying the code needed to create that experience. Both operating systems provide
extensive support for loading and presenting these types of resources in your applications.
About Resources
At a Glance
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
6Relevant Chapters: “Image, Sound, and Video Resources” (page 43)
Property Lists and Data Files Separate Data from Code
A property list file is a structured file used to store string, number, Boolean, date, and raw data values. Data
items in the file are organized using array and dictionary structures with most items associated with a unique
key. The system uses property lists to store simple data sets. For example, the Info.plist file found in nearly
every application is an example of a property list file. You can also use property list files for simple data storage
needs.
In addition to property lists, OS X supports some specially structured files for specific uses. For example,
AppleScript data and user help are stored using specially formatted data files. You can also create custom data
files of your own.
Relevant Chapters: “Data Resource Files” (page 48)
iOS Supports Device-Specific Resources
In iOS 4.0 and later, it is possible to mark individual resource files as usable only on a specific type of device.
This capability simplifies the code you have to write for Universal applications. Rather than creating separate
code paths to load one version of a resource file for iPhone and a different version of the file for iPad, you can
let the bundle-loading routines choose the correct file. All you have to do is name your resource files
appropriately.
To associate a resource file with a particular device, you add a custom modifier string to its filename. The
inclusion of this modifier string yields filenames with the following format:
.
The string represents the original name of the resource file. It also represents the name you use
when accessing the file from your code. Similarly, the string is the standard filename
extension used to identify the type of the file. The string is a case-sensitive string that can be one of
the following values:
● ~ipad - The resource should be loaded on iPad devices only.
● ~iphone - The resource should be loaded on iPhone or iPod touch devices only.
About Resources
At a Glance
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
7You can apply device modifiers to any type of resource file. For example, suppose you have an image named
MyImage.png. To specify different versions of the image for iPad and iPhone, you would create resource files
with the names MyImage~ipad.png and MyImage~iphone.png and include them both in your bundle. To
load the image, you would continue to refer to the resource as MyImage.png in your code and let the system
choose the appropriate version, as shown here:
UIImage* anImage = [UIImage imageNamed:@"MyImage.png"];
On an iPhone or iPod touch device, the system loads the MyImage~iphone.png resource file, while on iPad,
it loadsthe MyImage~ipad.png resource file. If a device-specific version of a resource is not found, the system
falls back to looking for a resource with the original filename, which in the preceding example would be an
image named MyImage.png.
See Also
The following Apple Developer documents are conceptually related to Resource Programming Guide :
● Bundle Programming Guide describes the bundle structure used by applications to store executable code
and resources.
●
Internationalization Programming Topics describes the process of preparing an application (and its
resources) for translation into other languages.
●
Interface Builder User Guide describes the application used to create nib file resources.
● Property List Programming Guide describes the facilities in place for loading property-list resource files
into a Cocoa application.
● Property List Programming TopicsforCore Foundation describesthe facilitiesinplace forloadingproperty-list
resource files into a C-based application.
About Resources
See Also
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
8Nib files play an important role in the creation of applications in OS X and iOS. With nib files, you create and
manipulate your user interfaces graphically, using Xcode, instead of programmatically. Because you can see
the results of your changesinstantly, you can experiment with different layouts and configurations very quickly.
You can also change many aspects of your user interface later without rewriting any code.
For applications built using the AppKit or UIKit frameworks, nib files take on an extra significance. Both of these
frameworks support the use of nib files both for laying out windows, views, and controls and for integrating
those items with the application’s event handling code. Xcode works in conjunction with these frameworks
to help you connect the controls of your user interface to the objects in your project that respond to those
controls. This integration significantly reduces the amount of setup that is required after a nib file is loaded
and also makes it easy to change the relationships between your code and user interface later.
Note: Although you can create an Objective-C application without using nib files, doing so is very
rare and not recommended. Depending on your application, avoiding nib files might require you to
replace large amounts of framework behavior to achieve the same results you would get using a
nib file.
Anatomy of a Nib File
A nib file describes the visual elements of your application’s user interface, including windows, views, controls,
and many others. It can also describe non-visual elements,such asthe objectsin your application that manage
your windows and views. Most importantly, a nib file describes these objects exactly as they were configured
in Xcode. At runtime, these descriptions are used to recreate the objects and their configuration inside your
application. When you load a nib file at runtime, you get an exact replica of the objectsthat were in your Xcode
document. The nib-loading code instantiates the objects, configures them, and reestablishes any inter-object
connections that you created in your nib file.
The following sections describe how nib files used with the AppKit and UIKit frameworks are organized, the
types of objects found in them, and how you use those objects effectively.
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
9
Nib FilesAbout Your Interface Objects
Interface objects are what you add to an nib file to implement your user interface. When a nib is loaded at
runtime, the interface objects are the objects actually instantiated by the nib-loading code. Most new nib files
have at least one interface object by default, typically a window or menu resource, and you add more interface
objects to a nib file as part of your interface design. This is the most common type of object in a nib file and
is typically why you create nib files in the first place.
Besides representing visual objects, such as windows, views, controls, and menus, interface objects can also
represent non-visual objects. In nearly all cases, the non-visual objects you add to a nib file are extra controller
objects that your application uses to manage the visual objects. Although you could create these objects in
your application, it is often more convenient to add them to a nib file and configure them there. Xcode provides
a generic object that you use specifically when adding controllers and other non-visual objects to a nib file. It
also provides the controller objects that are typically used to manage Cocoa bindings.
About the File’s Owner
One of the most important objects in a nib file is the File’s Owner object. Unlike interface objects, the File’s
Owner object is a placeholder object that is not created when the nib file is loaded. Instead, you create this
object in your code and pass it to the nib-loading code. The reason this object is so important is that it is the
main link between your application code and the contents of the nib file. More specifically, it is the controller
object that is responsible for the contents of the nib file.
In Xcode, you can create connections between the File’s Owner and the other interface objects in your nib file.
When you load the nib file, the nib-loading code recreates these connections using the replacement object
you specify. This allows your object to reference objects in the nib file and receive messages from the interface
objects automatically.
About the First Responder
In a nib file, the First Responder is a placeholder object that represents the first object in your application’s
dynamically determined responder chain. Because the responder chain of an application cannot be determined
at design time, the First Responder placeholder acts as a stand-in target for any action messages that need to
be directed at the application’sresponder chain. Menu items commonly target the First Responder placeholder.
For example, the Minimize menu item in the Window menu hides the frontmost window in an application,
not just a specific window, and the Copy menu item should copy the current selection, not just the selection
of a single control or view. Other objects in your application can target the First Responder as well.
When you load a nib file into memory, there is nothing you have to do to manage or replace the First Responder
placeholder object. The AppKit and UIKit frameworks automatically set and maintain the first responder based
on the application’s current configuration.
Nib Files
Anatomy of a Nib File
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
10For more information about the responder chain and how it is used to dispatch events in AppKit–based
applications,see “Event Architecture” inCocoa Event Handling Guide . For information about the responder chains
and handling actions in iPhone applications, see Event Handling Guide for iOS .
About the Top-Level Objects
When your program loads a nib file, Cocoa recreates the entire graph of objects you created in Xcode. This
object graph includes all of the windows, views, controls, cells, menus, and custom objects found in the nib file.
The top-level objects are the subset of these objects that do not have a parent object. The top-level objects
typically include only the windows, menubars, and custom controller objects that you add to the nib file.
(Objects such as File’s Owner, First Responder, and Application are placeholder objects and not considered
top-level objects.)
Typically, you use outlets in the File’s Owner object to store references to the top-level objects of a nib file. If
you do not use outlets, however, you can retrieve the top-level objects from the nib-loading routines directly.
You should always keep a pointer to these objects somewhere because your application is responsible for
releasing them when it is done using them. For more information about the nib object behavior at load time,
see “Managing the Lifetimes of Objects from Nib Files” (page 15).
About Image and Sound Resources
In Xcode, you can refer to external image and sound resources from within the contents of your nib files. Some
controls and views are able to display images or play sounds as part of their default configuration. The Xcode
library provides access to the image and sound resources of your Xcode projects so that you can link your nib
files to these resources. The nib file does not store these resources directly. Instead, it stores the name of the
resource file so that the nib-loading code can find it later.
When you load a nib file that contains references to image or sound resources, the nib-loading code reads the
actual image or sound file into memory and and caches it. In OS X, image and sound resources are stored in
named caches so that you can access them later if needed. In iOS, only image resources are stored in named
caches. To access images, you use the imageNamed: method of NSImage or UIImage, depending on your
platform. To access cached sounds in OS X, use the soundNamed: method of NSSound.
Nib File Design Guidelines
When creating your nib files, it is important to think carefully about how you intend to use the objects in that
file. A very simple application might be able to store all of its user interface components in a single nib file,
but for most applications, it is better to distribute components across multiple nib files. Creating smaller nib
files lets you load only those portions of your interface that you need immediately. They also make it easier to
debug any problems you might encounter, since there are fewer places to look for problems.
Nib Files
Nib File Design Guidelines
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
11When creating your nib files, try to keep the following guidelines in mind:
● Design your nib files with lazy loading in mind. Plan on loading nib files that contain only those objects
you need right away.
●
In the main nib file for an OS X application, considerstoring only the application menu bar and an optional
application delegate object in the nib file. Avoid including any windows or user-interface elements that will
not be used until after the application has launched. Instead, place those resources in separate nib files
and load them as needed after launch.
● Store repeated user-interface components (such as document windows) in separate nib files.
● For a window or menu that is used only occasionally,store it in a separate nib file. By storing it in a separate
nib file, you load the resource into memory only if it is actually used.
● Make the File’s Owner the single point-of-contact for anything outside of the nib file; see “Accessing the
Contents of a Nib File” (page 30).
The Nib Object Life Cycle
When a nib file is loaded into memory, the nib-loading code takes several steps to ensure the objects in the
nib file are created and initialized properly. Understanding these steps can help you write better controller
code to manage your user interfaces.
The Object Loading Process
When you use the methods of NSNib or NSBundle to load and instantiate the objectsin a nib file, the underlying
nib-loading code does the following:
1. It loads the contents of the nib file and any referenced resource files into memory:
● The raw data for the entire nib object graph is loaded into memory but is not unarchived.
● Any custom image resources associated with the nib file are loaded and added to the Cocoa image
cache; see “About Image and Sound Resources” (page 11).
● Any custom sound resources associated with the nib file are loaded and added to the Cocoa sound
cache; see “About Image and Sound Resources” (page 11).
2. It unarchives the nib object graph data and instantiates the objects. How it initializes each new object
depends on the type of the object and how it was encoded in the archive. The nib-loading code uses the
following rules (in order) to determine which initialization method to use.
a. By default, objects receive an initWithCoder: message.
Nib Files
The Nib Object Life Cycle
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
12In OS X, the list of standard objects includes the views, cells, menus, and view controllers that are
provided by the system and available in the default Xcode library. It also includes any third-party
objects that were added to the library using a custom plug-in. Even if you change the class of such
an object, Xcode encodes the standard object into the nib file and then tells the archiver to swap in
your custom class when the object is unarchived.
In iOS, any object that conforms to the NSCoding protocol is initialized using the initWithCoder:
method. This includes all subclasses of UIView and UIViewController whether they are part of
the default Xcode library or custom classes you define.
b. Custom views in OS X receive an initWithFrame: message.
Custom views are subclasses of NSView for which Xcode does not have an available implementation.
Typically, these are viewsthat you define in your application and use to provide custom visual content.
Custom views do not include standard system views(like NSSlider) that are part of the default library
or part of an integrated third-party plug-in.
When it encounters a custom view, Xcode encodes a special NSCustomView object into your nib file.
The custom view object includesthe information it needsto build the real view subclass you specified.
At load time, the NSCustomView object sends an alloc and initWithFrame: message to the real
view class and then swaps the resulting view object in for itself. The net effect is that the real view
object handles subsequent interactions during the nib-loading process.
Custom views in iOS do not use the initWithFrame: method for initialization.
c. Custom objects other than those described in the preceding steps receive an init message.
3. It reestablishes all connections(actions, outlets, and bindings) between objectsin the nib file. Thisincludes
connections to File’s Owner and other placeholder objects. The approach for establishing connections
differs depending on the platform:
● Outlet connections
●
In OS X, the nib-loading code tries to reconnect outlets using the object’s own methods first. For
each outlet, Cocoa looks for a method of the form setOutletName: and calls it if such a method
is present. If it cannot find such a method, Cocoa searchesthe object for an instance variable with
the corresponding outlet name and tries to set the value directly. If the instance variable cannot
be found, no connection is created.
In OS X v10.5 and later, setting an outlet also generates a key-value observing (KVO) notification
for any registered observers. These notifications may occur before all inter-object connections
are reestablished and definitely occur before any awakeFromNib methods of the objects have
been called. Prior to v10.5, these notifications are not generated. For more information about
KVO notifications, see Key-Value Observing Programming Guide .
Nib Files
The Nib Object Life Cycle
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
13●
In iOS, the nib-loading code uses the setValue:forKey: method to reconnect each outlet.
That method similarly looks for an appropriate accessor method and falls back on other means
when that fails. For more information about how this method sets values, see its description in
NSKeyValueCoding Protocol Reference .
Setting an outlet in iOS also generates a KVO notification for any registered observers. These
notifications may occur before all inter-object connections are reestablished and definitely occur
before any awakeFromNib methods of the objects have been called. For more information about
KVO notifications, see Key-Value Observing Programming Guide .
● Action connections
●
In OS X, the nib-loading code uses the source object’s setTarget: and setAction: methods
to establish the connection to the target object. If the target object does not respond to the
action method, no connection is created. If the target object is nil, the action is handled by the
responder chain.
●
In iOS, the nib-loading code uses the addTarget:action:forControlEvents: method of
the UIControl object to configure the action. If the target is nil, the action is handled by the
responder chain.
● Bindings
●
In OS X, Cocoa usesthe bind:toObject:withKeyPath:options: method of the source object
to create the connection between it and its target object.
● Bindings are not supported in iOS.
4. It sends an awakeFromNib message to the appropriate objects in the nib file that define the matching
selector:
●
In OS X, this message is sent to any interface objects that define the method. It is also sent to the File’s
Owner and any placeholder objects that define it as well.
●
In iOS, this message is sent only to the interface objects that were instantiated by the nib-loading
code. It is not sent to File’s Owner, First Responder, or any other placeholder objects.
5. It displays any windows whose “Visible at launch time” attribute was enabled in the nib file.
The order in which the nib-loading code calls the awakeFromNib methods of objects is not guaranteed. In
OS X, Cocoa tries to call the awakeFromNib method of File’s Owner last but does not guarantee that behavior.
If you need to configure the objects in your nib file further at load time, the most appropriate time to do so is
after your nib-loading call returns. At that point, all of the objects are created, initialized, and ready for use.
Nib Files
The Nib Object Life Cycle
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
14Managing the Lifetimes of Objects from Nib Files
Each time you ask the NSBundle or NSNib class to load a nib file, the underlying code creates a new copy of
the objects in that file and returns them to you. (The nib-loading code does not recycle nib file objects from a
previous load attempt.) You need to ensure that you maintain the new object graph as long as necessary, and
disown it when you are finished with it. You typically need strong references to top-level objects to ensure
that they are not deallocated; you don’t need strong references to objects lower down in the graph because
they’re owned by their parents, and you should minimize the risk of creating strong reference cycles.
From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should
generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard
scene) which should be strong. Outlets that you create should therefore typically be weak, because:
● Outlets that you create to subviews of a view controller’s view or a window controller’s window, for
example, are arbitrary references between objects that do not imply ownership.
● The strong outlets are frequently specified by framework classes (for example, UIViewController’s
view outlet, or NSWindowController’s window outlet).
@property (weak) IBOutlet MyView *viewContainerSubview;
@property (strong) IBOutlet MyOtherClass *topLevelObject;
Note: InOS X, not all classessupport weak references; these are NSATSTypesetter, NSColorSpace,
NSFont, NSFontManager, NSFontPanel, NSImage, NSMenuView, NSParagraphStyle,
NSSimpleHorizontalTypesetter, NSTableCellView, NSTextView, NSViewController,
NSWindow, and NSWindowController, and all classes in the AV Foundation framework.
In cases where you cannot therefore specify weak, you should instead use assign:
@property (assign) IBOutlet NSTextView *textView;
Outlets may be considered private to the defining class; if you prefer, you can hide the property declarations
a class extension. For example:
// MyClass.h
@interface MyClass : MySuperclass
@end
Nib Files
Managing the Lifetimes of Objects from Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
15// MyClass.m
@interface MyClass ()
@property (weak) IBOutlet MyView *viewContainerSubview;
@property (strong) IBOutlet MyOtherClass *topLevelObject;
@end
These patterns extend to references from a container view to its subviews where you have to consider the
internal consistency of your object graph. For example, in the case of a table view cell, outlets to specific
subviews should again typically be weak. If a table view contains an image view and a text view, then these
remain valid so long as they are subviews of the table view cell itself.
Outlets should be changed to strong when the outlet should be considered to own the referenced object:
● Asindicated previously, thisis often the case with File’s Owner—top level objectsin a nib file are frequently
considered to be owned by the File’s Owner.
● You may in some situations need an object from a nib file to exist outside of its original container. For
example, you might have an outlet for a view that can be temporarily removed from itsinitial view hierarchy
and must therefore be maintained independently.
Classes that you expect to be subclassed (in particular abstract classes) expose outlets publicly so that they
can be used appropriately by subclasses (e.g. UIViewController’s view outlet). Outlets might also be
exposed where there is an expectation that consumers of the class will need to interact with the property; for
example a table view cell might expose subviews. In thislatter case, it may be appropriate to expose a read-only
public outlet that is redefined privately as read-write, for example:
// MyClass.h
@interface MyClass : UITableViewCell
@property (weak, readonly) MyType *outletName;
@end
// MyClass.m
@interface MyClass ()
@property (weak, readwrite) IBOutlet MyType *outletName;
@end
Nib Files
Managing the Lifetimes of Objects from Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
16Top-level Objects in OS X May Need Special Handling
For historical reasons, in OS X the top-level objects in a nib file are created with an additional reference count.
The Application Kit offers a couple of features that help to ensure that nib objects are properly released:
● NSWindow objects (including panels) have an isReleasedWhenClosed attribute, which if set to YES
instructs the window to release itself (and consequently all dependent objects in its view hierarchy) when
it is closed. In the nib file, you set this option through the “Release when closed” check box in the Attributes
pane of the Xcode inspector.
●
If the File’s Owner of a nib file is an NSWindowController object (the default in document nibs in
document-based applications—recall that NSDocument manages an instance of NSWindowController)
or an NSViewController object, it automatically disposes of the windows it manages.
If the File’s Owner is not an instance of NSWindowController or NSViewController, then you need to
decrement the reference count of the top level objects yourself. With manual reference counting, it was possible
to achieve this by sending top-level objects a release message. You cannot do this with ARC. Instead, you
cast references to top-level objects to a Core Foundation type and use CFRelease. (If you don’t want to have
outlets to all top-level objects, you can use the instantiateNibWithOwner:topLevelObjects: method
of the NSNib class to get an array of a nib file’s top-level objects.)
Legacy Patterns
Prior to ARC, the rules for managing nib objects are different from those described above. How you manage
the objects depends on the platform and on the memory model in use. Whichever platform you develop for,
you should define outlets using the Objective-C declared properties feature.
The general form of the declaration should be:
@property (attributes) IBOutlet UserInterfaceElementClass *anOutlet;
Because the behavior of outlets depends on the platform, the actual declaration differs:
● For iOS, you should use:
@property (nonatomic, retain) IBOutlet UserInterfaceElementClass *anOutlet;
● For OS X, you should use:
@property (assign) IBOutlet UserInterfaceElementClass *anOutlet;
Nib Files
Managing the Lifetimes of Objects from Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
17You should then either synthesize the corresponding accessor methods, or implement them according to the
declaration, and (in iOS) release the corresponding variable in dealloc.
This pattern also works if you use the modern runtime and synthesize the instance variables, so it remains
consistent across all situations.
Managing Nib Objects in iOS
Top-Level Objects
Objects in the nib file are created with a retain count of 1 and then autoreleased. As it rebuilds the object
hierarchy, UIKit reestablishes connections between the objects using setValue:forKey:, which uses the
available setter method or retains the object by default if no setter method is available. This means that
(assuming you follow the pattern shown above) any object for which you have an outlet remains valid. If there
are any top-level objects you do not store in outlets, however, you must retain either the array returned by
the loadNibNamed:owner:options: method or the objects inside the array to prevent those objects from
being released prematurely.
Memory Warnings
When a view controller receives a memory warning (didReceiveMemoryWarning), it should relinquish
ownership of resources that are currently not needed and that can be recreated later if required. One such
resource is the view controller's view itself. If it does not have a superview, the view is disposed of (in its
implementation of didReceiveMemoryWarning, UIViewController invokes [self setView:nil]).
Because outlets to elements within the nib file are typically retained, however, even though the main view is
disposed of, absent any further action the outlets are not disposed of. This is not in and of itself a problem—if
and when the main view is reloaded, they will simply be replaced—but it does mean that the beneficial effect
of the didReceiveMemoryWarning is reduced. To ensure that you properly relinquish ownership of outlets,
in your custom view controller class you can implement viewDidUnload to invoke your accessor methods
to set outlets to nil.
- (void)viewDidUnload {
self.anOutlet = nil;
[super viewDidUnload];
}
Nib Files
Managing the Lifetimes of Objects from Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
18Managing Nib Objects in OS X
In OS X, the File’s Owner of a nib file is by default responsible for releasing the top-level objects in a nib file as
well as any non-object resources created by the objects in the nib. The release of the root object of an object
graph sets in motion the release of all dependent objects. The File’s Owner of an application’s main nib file
(which containsthe application menu and possibly other items) isthe global application object NSApp. However,
when a Cocoa application terminates, top level objects in the main nib do not automatically get dealloc
messages just because NSApp is being deallocated. In other words, even in the main nib file, you have to
manage the memory of top-level objects.
The Application Kit offers a couple of features that help to ensure that nib objects are properly released:
● NSWindow objects (including panels) have an isReleasedWhenClosed attribute, which if set to YES
instructs the window to release itself (and consequently all dependent objects in its view hierarchy) when
it is closed. In the nib file, you set this option through the “Release when closed” check box in the Attributes
pane of the inspector.
●
If the File’s Owner of a nib file is an NSWindowController object (the default in document nibs in
document-based applications—recall that NSDocument manages an instance of NSWindowController),
it automatically disposes of the windows it manages.
So in general, you are responsible for releasing top-level objects in a nib file. But in practice, if your nib file’s
owner is an instance of NSWindowController it releases the top-level object for you. If one of your objects
loads the nib itself (and the owner is not an instance of NSWindowController), you can define outlets to
each top-level object so that at the appropriate time you can release them using those references. If you don’t
wantto have outletsto alltop-level objects, you can use the instantiateNibWithOwner:topLevelObjects:
method of the NSNib class to get an array of a nib file’s top-level objects.
The issue of responsibility for nib object disposal becomes clearer when you consider the various kinds of
applications. Most Cocoa applications are of two kinds: single window applications and document-based
applications. In both cases, memory management of nib objects is automatically handled for you to some
degree. With single-window applications, objects in the main nib file persist through the runtime life of the
application and are released when the application terminates; however, dealloc is not guaranteed to be
automatically invoked on objects from the main nib file when an application terminates. In document-based
applications each document window is managed by an NSWindowController object which handles memory
management for a document nib file.
Some applications may have a more complex arrangement of nib files and top-level objects. For example, an
application could have multiple nib files with multiple window controllers, loadable panels, and inspectors.
But in most of these cases, if you use NSWindowController objects to manage windows and panels or if you
set the “released when closed” window attribute, memory management is largely taken care of. If you decide
against using window controllers and do not want to set the “release when closed” attribute, you should
Nib Files
Managing the Lifetimes of Objects from Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
19explicitly free your nib file’s windows and other top-level objects when the window is closed. Also, if your
application uses an inspector panel, (after being lazily loaded) the panel should typically persist throughout
the lifetime of the application—there is no need to dispose of the inspector and its resources.
Action Methods
Broadly speaking, action methods(see Target-Action in OS X or Target-Action in iOS) are methodsthat are typically
invoked by another object in a nib file. Action methods use type qualifier IBAction, which is used in place of
the void return type, to flag the declared method as an action so that Xcode is aware of it.
@interface MyClass
- (IBAction)myActionMethod:(id)sender;
@end
You may choose to regard action methods as being private to your class and thus not declare them in the
public @interface. (Because Xcode parses implementation files, there is no need to declare them in the
header.)
// MyClass.h
@interface MyClass
@end
// MyClass.m
@implementation MyClass
- (IBAction)myActionMethod:(id)sender {
// Implementation.
}
@end
You should typically not invoke an action method programmatically. If your class needs to perform the work
associated with the action method, then you should factor the implementation into a different method that
is then invoked by the action method.
// MyClass.h
Nib Files
Action Methods
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
20@interface MyClass
@end
// MyClass.m
@interface MyClass (PrivateMethods)
- (void)doSomething;
- (void)doWorkThatRequiresMeToDoSomething;
@end
@implementation MyClass
- (IBAction)myActionMethod:(id)sender {
[self doSomething];
}
- (void)doSomething {
// Implementation.
}
- (void)doWorkThatRequiresMeToDoSomething {
// Pre-processing.
[self doSomething];
// Post-processing.
}
@end
Built-In Support For Nib Files
The AppKit and UIKit frameworks both provide a certain amount of automated behavior for loading and
managing nib files in an application. Both frameworks provide infrastructure for loading an application’s main
nib file. In addition, the AppKit framework providessupport for loading other nib filesthrough the NSDocument
and NSWindowController classes. The following sections describe the built-in support for nib files, how you
can take advantage of it, and ways to modify that support in your own applications.
Nib Files
Built-In Support For Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
21The Application Loads the Main Nib File
Most of the Xcode project templates for applications come preconfigured with a main nib file already in place.
All you have to do is modify this default nib file in the nib file and build your application. At launch time, the
application’s default configuration data tells the application object where to find this nib file so that it can load
it. In applications based on either AppKit and UIKit, this configuration data is located in the application’s
Info.plist file. When an application is first loaded, the default application startup code looks in the
Info.plist file for the NSMainNibFile key. If it findsit, it looksin the application bundle for a nib file whose
name (with or without the filename extension) matches the value of that key and loads it.
Each View Controller Manages its Own Nib File
The UIViewController (iOS) and NSViewController (OS X) classessupport the automatic loading of their
associated nib file. If you specify a nib file when creating the view controller, that nib file isloaded automatically
when you try to access the view controller’s view. Any connections between the view controller and the nib
file objects are created automatically, and in iOS, the UIViewController object also receives additional
notifications when the views are finally loaded and displayed on screen. To help manage memory better, the
UIViewController class also handles the unloading of its nib file (as appropriate) during low-memory
conditions.
For more information about how you use the UIViewController class and how you configure it, see View
Controller Programming Guide for iOS .
Document and Window Controllers Load Their Associated Nib File
In the AppKit framework, the NSDocument class works with the default window controller to load the nib file
containing your document window. The windowNibName method of NSDocument is a convenience method
that you can use to specify the nib file containing the corresponding document window. When a new document
is created, the document object passes the nib file name you specify to the default window controller object,
which loads and manages the contents of the nib file. If you use the standard templates provided by Xcode,
the only thing you have to do is add the contents of your document window to the nib file.
The NSWindowController class also provides automatic support for loading nib files. If you create custom
window controllers programmatically, you have the option of initializing them with an NSWindow object or
with the name of a nib file. If you choose the latter option, the NSWindowController class automatically
loads the specified nib file the first time a client tries to access the window. After that, the window controller
keeps the window around in memory; it does not reload it from the nib file, even if the window’s “Release
when closed” attribute is set.
Nib Files
Built-In Support For Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
22Important: When using either NSWindowController or NSDocument to load windows automatically, it
is important that your nib file be configured correctly. Both classes include a window outlet that you must
connect to the window you want them to manage. If you do not connect this outlet to a window object,
the nib file is loaded but the document or window controller does not display the window. For more
information about the Cocoa document architecture, see Document-Based App Programming Guide for
Mac .
Loading Nib Files Programmatically
Both OS X and iOS provide convenience methods for loading nib files into your application. Both the AppKit
and UIKit framework define additional methods on the NSBundle class that support the loading of nib files.
In addition, the AppKit framework also provides the NSNib class, which provides similar nib-loading behavior
as NSBundle but offers some additional advantages that might be useful in specific situations.
As you plan out your application, make sure any nib files you plan to load manually are configured in a way
that simplifies the loading process. Choosing an appropriate object for File’s Owner and keeping your nib files
small can greatly improve their ease of use and memory efficiency. For more tips on configuring your nib files,
see “Nib File Design Guidelines” (page 11).
Loading Nib Files Using NSBundle
The AppKit and UIKit frameworks define additional methods on the NSBundle class (using Objective-C
categories) to support the loading of nib file resources. The semantics for how you use the methods differs
between the two platforms as doesthe syntax for the methods. In AppKit, there are more optionsfor accessing
bundles in general and so there are correspondingly more methods for loading nib files from those bundles.
In UIKit, applications can load nib files only from their main bundle and so fewer options are needed. The
methods available on the two platforms are as follows:
● AppKit
● loadNibNamed:owner: class method
● loadNibFile:externalNameTable:withZone: class method
● loadNibFile:externalNameTable:withZone: instance method
● UIKit
● loadNibNamed:owner:options: instance method
Nib Files
Loading Nib Files Programmatically
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
23Whenever loading a nib file, you should always specify an object to act as File’s Owner of that nib file. The role
of the File’s Owner is an important one. It is the primary interface between your running code and the new
objects that are about to be created in memory. All of the nib-loading methods provide a way to specify the
File’s Owner, either directly or as a parameter in an options dictionary.
One of the semantic differences between the way the AppKit and UIKit frameworks handle nib loading is the
way the top-level nib objects are returned to your application. In the AppKit framework, you must explicitly
request them using one of the loadNibFile:externalNameTable:withZone: methods. In UIKit, the
loadNibNamed:owner:options: method returns an array of these objects directly. The simplest way to
avoid having to worry about the top-level objects in either case is to store them in outlets of your File’s Owner
object and to make sure the setter methods for those outlets retain their values. Because each platform uses
different retain semantics, however, you must be sure to send the proper retain or release messages when
appropriate. For information about the retention semantics for nib objects, see “Managing the Lifetimes of
Objects from Nib Files” (page 15).
Listing 1-1 shows a simple example of how to load a nib file using the NSBundle class in an AppKit–based
application. As soon as the loadNibNamed:owner: method returns, you can begin using any outlets that
refer to the nib file objects. In other words, the entire nib-loading process occurs within the confines of that
single call. The nib-loading methods in the AppKit framework return a Boolean value to indicate whether the
load operation was successful.
Listing 1-1 Loading a nib file from the current bundle
- (BOOL)loadMyNibFile
{
// The myNib file must be in the bundle that defines self's class.
if (![NSBundle loadNibNamed:@"myNib" owner:self])
{
NSLog(@"Warning! Could not load myNib file.\n");
return NO;
}
return YES;
}
Listing 1-2 shows an example of how to load a nib file in a UIKit–based application. In this case, the method
checks the returned array to see if the nib objects were loaded successfully. (Every nib file should have at least
one top-level object representing the contents of the nib file.) This example shows the simple case when the
nib file contains no placeholder objects other than the File’s Owner object. For an example of how to specify
additional placeholder objects, see “Replacing Proxy Objects at Load Time” (page 28).
Nib Files
Loading Nib Files Programmatically
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
24Listing 1-2 Loading a nib in an iPhone application
- (BOOL)loadMyNibFile
{
NSArray* topLevelObjs = nil;
topLevelObjs = [[NSBundle mainBundle] loadNibNamed:@"myNib" owner:self
options:nil];
if (topLevelObjs == nil)
{
NSLog(@"Error! Could not load myNib file.\n");
return NO;
}
return YES;
}
Note: If you are developing a Universal application for iOS, you can use the device-specific naming
conventionsto load the correct nib file for the underlying device automatically. For more information
about how to name your nib files, see “iOS Supports Device-Specific Resources” (page 7).
Getting a Nib File’s Top-Level Objects
The easiest way to get the top-level objects of your nib file is to define outlets in the File’s Owner object along
with setter methods (or better yet, properties) for accessing those objects. This approach ensures that the
top-level objects are retained by your object and that you always have references to them.
Listing 1-3 shows the interface and implementation of a simplified Cocoa class that uses an outlet to retain
the nib file’s only top-level object. In this case, the only top-level object in the nib file is an NSWindow object.
Because top-level objects in Cocoa have an initial retain count of 1, an extra release message is included. This
is fine because by the time the release call is made, the property has already been retained the window. You
would not want to release top-level objects in this manner in an iPhone application.
Listing 1-3 Using outlets to get the top-level objects
// Class interface
@interface MyController : NSObject {
NSWindow *window;
}
Nib Files
Loading Nib Files Programmatically
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
25@property(retain) IBOutlet NSWindow *window;
- (void)loadMyWindow;
@end
// Class implementation
@implementation MyController
// The synthesized property retains the window automatically.
@synthesize window;
- (void)loadMyWindow
{
[NSBundle loadNibNamed:@"myNib" owner:self];
// The window starts off with a retain count of 1
// and is then retained by the property, so add an extra release.
[window release];
}
@end
If you do not want to use outlets to store references to your nib file’s top-level objects, you must retrieve those
objects manually in your code. The technique for obtaining the top-level objects differs depending on the
target platform. In OS X, you must ask for the objects explicitly, whereas in iOS they are returned to you
automatically.
Listing 1-4 showsthe processfor getting the top-level objects of a nib file in OS X. This method places a mutable
array into the nameTable dictionary and associatesit with the NSNibTopLevelObjects key. The nib-loading
code looks for this array object and, if present, places the top-level objects in it. Because each object starts
with a retain count of 1 before it is added to the array, simply releasing the array is not enough to release the
objects in the array as well. As a result, this method sends a release message to each of the objects to ensure
that the array is the only entity holding a reference to them.
Listing 1-4 Getting the top-level objects from a nib file at runtime
- (NSArray*)loadMyNibFile
{
Nib Files
Loading Nib Files Programmatically
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
26NSBundle* aBundle = [NSBundle mainBundle];
NSMutableArray* topLevelObjs = [NSMutableArray array];
NSDictionary* nameTable = [NSDictionary dictionaryWithObjectsAndKeys:
self, NSNibOwner,
topLevelObjs, NSNibTopLevelObjects,
nil];
if (![aBundle loadNibFile:@"myNib" externalNameTable:nameTable withZone:nil])
{
NSLog(@"Warning! Could not load myNib file.\n");
return nil;
}
// Release the objects so that they are just owned by the array.
[topLevelObjs makeObjectsPerformSelector:@selector(release)];
return topLevelObjs;
}
Obtaining the top-level objects in an iPhone application is much simpler and is shown in Listing 1-2 (page 25).
In the UIKit framework, the loadNibNamed:owner:options: method of NSBundle automatically returns
an array with the top-level objects. In addition, by the time the array is returned, the retain counts on the
objects are adjusted so that you do not need to send each object an extra release message. The returned array
is the only owner of the objects.
Loading Nib Files Using UINib and NSNib
The UINib (iOS) and NSNib (OS X) classes provide better performance in situations where you want to create
multiple copies of a nib file’s contents. The normal nib-loading process involves reading the nib file from disk
and then instantiating the objects it contains. However, with the UINib and NSNib classes, the nib file is read
from disk once and the contents are stored in memory. Because they are in memory, creating successive sets
of objects takes less time because it does not require accessing the disk.
Using the UINib and NSNib classes is always a two-step process. First, you create an instance of the class and
initialize it with the nib file’s location information. Second, you instantiate the contents of the nib file to load
the objects into memory. Each time you instantiate the nib file, you specify a different File’s Owner object and
receive a new set of top-level objects.
Nib Files
Loading Nib Files Programmatically
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
27Listing 1-5 shows one way to load the contents of a nib file using the NSNib class in OS X. The array returned
to you by the instantiateNibWithOwner:topLevelObjects: method comes already autoreleased. If
you intend to use that array for any period of time, you should make a copy of it.
Listing 1-5 Loading a nib file using NSNib
- (NSArray*)loadMyNibFile
{
NSNib* aNib = [[NSNib alloc] initWithNibNamed:@"MyPanel" bundle:nil];
NSArray* topLevelObjs = nil;
if (![aNib instantiateNibWithOwner:self topLevelObjects:&topLevelObjs])
{
NSLog(@"Warning! Could not load nib file.\n");
return nil;
}
// Release the raw nib data.
[aNib release];
// Release the top-level objects so that they are just owned by the array.
[topLevelObjs makeObjectsPerformSelector:@selector(release)];
// Do not autorelease topLevelObjs.
return topLevelObjs;
}
Replacing Proxy Objects at Load Time
In iOS, it is possible to create nib files that include placeholder objects besides the File’s Owner. Proxy objects
represent objects created outside of the nib file but which have some connection to the nib file’s contents.
Proxies are commonly used to support navigation controllers in iPhone applications. When working with
navigation controllers, you typically connect the File’s Owner object to some common object such as your
application delegate. Proxy objects therefore represent the parts of the navigation controller object hierarchy
that are already loaded in memory, because they were created programmatically or loaded from a different
nib file.
Nib Files
Loading Nib Files Programmatically
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
28Note: Custom placeholder objects (other than File’s Owner) are not supported in OS X nib files.
Each placeholder object you add to a nib file must have a unique name. To assign a name to an object, select
the object in Xcode and open the inspector window. The Attributes pane of the inspector contains a Name
field, which you use to specify the name for your placeholder object. The name you assign should be descriptive
of the object’s behavior or type, but really it can be anything you want.
When you are ready to load a nib file containing placeholder objects, you mustspecify the replacement objects
for any proxies when you call the loadNibNamed:owner:options: method. The options parameter of
this method accepts a dictionary of additional information. You use this dictionary to pass in the information
about your placeholder objects. The dictionary must contain the UINibExternalObjects key whose value
is another dictionary containing the name and object for each placeholder replacement.
Listing 1-6 shows a sample version of an applicationDidFinishLaunching: method that loads the
application’s main nib file manually. Because the application’s delegate object is created by the
UIApplicationMain function, this method uses a placeholder (with the name “AppDelegate”) in the main
nib file to represent that object. The proxies dictionary stores the placeholder object information and the
options dictionary wraps that dictionary.
Listing 1-6 Replacing placeholder objects in a nib file
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
NSArray* topLevelObjs = nil;
NSDictionary* proxies = [NSDictionary dictionaryWithObject:self
forKey:@"AppDelegate"];
NSDictionary* options = [NSDictionary dictionaryWithObject:proxies
forKey:UINibExternalObjects];
topLevelObjs = [[NSBundle mainBundle] loadNibNamed:@"Main" owner:self
options:options];
if ([topLevelObjs count] == 0)
{
NSLog(@"Warning! Could not load myNib file.\n");
return;
}
// Show window
[window makeKeyAndVisible];
Nib Files
Loading Nib Files Programmatically
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
29}
For more information about the options dictionary of the loadNibNamed:owner:options: method, see
NSBundle UIKit Additions Reference .
Accessing the Contents of a Nib File
Upon the successful loading a nib file, its contents become ready for you to use immediately. If you configured
outlets in your File’s Owner to point to nib file objects, you can now use those outlets. If you did not configure
your File’s Owner with any outlets, you should make sure you obtain a reference to the top-level objects in
some manner so that you can release them later.
Because outlets are populated with real objects when a nib file is loaded, you can subsequently use outlets as
you would any other object you created programmatically. For example, if you have an outlet pointing to a
window, you could send that window a makeKeyAndOrderFront: message to show it on the user’s screen.
When you are done using the objects in your nib file, you must release them like any other objects.
Important: You are responsible for releasing the top-level objects of any nib files you load when you are
finished with those objects. Failure to do so is a cause of memory leaksin many applications. After releasing
the top-level objects, it is a good idea to clear any outlets pointing to objects in the nib file by setting them
to nil. You should clear outlets associated with all of the nib file’s objects, not just the top-level objects.
Connecting Menu Items Across Nib Files
The items in an OS X application’s menu bar often need to interact with many different objects, including your
application’s documents and windows. The problem is that many of these objects cannot (or should not) be
accessed directly from the main nib file. The File’s Owner of the main nib file is always set to an instance of the
NSApplication class. And although you might be able to instantiate a number of custom objects in your
main nib file, doing so is hardly practical or necessary. In the case of document objects, connecting directly to
a specific document object is not even possible because the number of document objects can change
dynamically and can even be zero.
Most menu items send action messages to one of the following:
● A fixed object that always handles the command
● A dynamic object, such as a document or window
Nib Files
Connecting Menu Items Across Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
30Messaging fixed objects is a relatively straightforward process that is usually best handled through the
application delegate. The application delegate object assiststhe NSApplication objectin running the application
and is one of the few objects that rightfully belongs in the main nib file. If the menu item refers to an
application-level command, you can implement that command directly in the application delegate or just have
the delegate forward the message to the appropriate object elsewhere in your application.
If you have a menu item that acts on the contents of the frontmost window, you need to link the menu item
to the First Responder placeholder object. If the action method associated with the menu item is specific to
one of your objects(and not defined by Cocoa), you must add that action to the First Responder before creating
the connection.
After creating the connection, you need to implement the action method in your custom class. That object
should also implement the validateMenuItem: method to enable the menu item at appropriate times. For
more information about how the responder chain handles commands, see Cocoa Event Handling Guide .
Nib Files
Connecting Menu Items Across Nib Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
31An important part of the localization process is to localize all of the text strings displayed by your application.
By their nature, strings located in nib files can be readily localized along with the rest of the nib file contents.
Strings embedded in your code, however, must be extracted, localized, and then reinserted back into your
code. To simplify this process—and to make the maintenance of your code easier—OS X and iOS provide the
infrastructure needed to separate strings from your code and place them into resource files where they can
be localized easily.
Resource filesthat contain localizable strings are referred to as strings files because of their filename extension,
which is .strings. You can create strings files manually or programmatically depending on your needs. The
standard strings file format consists of one or more key-value pairs along with optional comments. The key
and value in a given pair are strings of text enclosed in double quotation marks and separated by an equal
sign. (You can also use a property list format for strings files. In such a case, the top-level node is a dictionary
and each key-value pair of that dictionary is a string entry.)
Listing 2-1 shows a simple strings file that contains non-localized entries for the default language. When you
need to display a string, you pass the string on the left to one of the available string-loading routines. What
you get back isthe matching value string containing the text translation that is most appropriate for the current
user. For the development language, it is common to use the same string for both the key and value, but doing
so is not required.
Listing 2-1 A simple strings file
/* Insert Element menu item */
"Insert Element" = "Insert Element";
/* Error string used for unknown error types. */
"ErrorString_1" = "An unknown error occurred.";
A typical application has at least one strings file per localization, that is, one strings file in each of the bundle’s
.lproj subdirectories. The name of the default strings file is Localizable.strings but you can create
stringsfiles with any file name you choose. Creating stringsfilesis discussed in more depth in “Creating Strings
Resource Files” (page 33).
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
32
String ResourcesNote: It is recommended that you save strings files using the UTF-16 encoding, which is the default
encoding forstandard stringsfiles. It is possible to create stringsfiles using other property-list formats,
including binary property-list formats and XML formats that use the UTF-8 encoding, but doing so
is not recommended. For more information about the standard strings file format, see “Creating
Strings Resource Files” (page 33). For more information about Unicode and its text encodings, go
to http://www.unicode.org/ or http://en.wikipedia.org/wiki/Unicode.
The loading of string resources (both localized and nonlocalized) ultimately relies on the bundle and
internationalization supportfound in bothOS X and iOS. Forinformation about bundles,see Bundle Programming
Guide . For more information about internationalization and localization,see Internationalization Programming
Topics.
Creating Strings Resource Files
Although you can create strings files manually, it is rarely necessary to do so. The easiest way to create strings
files is to write your code using the appropriate string-loading macros and then use the genstrings
command-line tool to extract those strings and create strings files for you.
The following sections describe the process of how to set up your source files to facilitate the use of the
genstrings tool. For detailed information about the tool, see genstrings man page.
Choosing Which Strings to Localize
When it comes to localizing your application’s interface, it is not always appropriate to localize every string
used by your application. Translation is a costly process, and translating strings that are never seen by the user
is a waste of time and money. Strings that are not displayed to the user, such as notification names used
internally by your application, do not need to be translated. Consider the following example:
if (CFStringHasPrefix(value, CFSTR("-")) { CFArrayAppendValue(myArray, value);};
In this example, the string “-” is used internally and is never seen by the user; therefore, it does not need to
be placed in a strings file.
The following code shows another example of a string the user would not see. The string "%d %d %s" does
not need to be localized, since the user never sees it and it has no effect on anything that the user does see.
matches = sscanf(s, "%d %d %s", &first, &last, &other);
String Resources
Creating Strings Resource Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
33Because nib files are localized separately, you do not need to include strings that are already located inside of
a nib file. Some of the strings you should localize, however, include the following:
● Strings that are programmatically added to a window, panel, view, or control and subsequently displayed
to the user. This includes strings you pass into standard routines, such as those that display alert boxes.
● Menu item title strings if those strings are added programmatically. For example, if you use custom strings
for the Undo menu item, those strings should be in a strings file.
● Error messages that are displayed to the user.
● Any boilerplate text that is displayed to the user.
● Some stringsfromyour application’sinformation property list(Info.plist) file;see Runtime Configuration
Guidelines.
● New file and document names.
About the String-Loading Macros
The Foundation and Core Foundation frameworks define the following macros to make loading strings from a
strings file easier:
● Core Foundation macros:
● CFCopyLocalizedString
● CFCopyLocalizedStringFromTable
● CFCopyLocalizedStringFromTableInBundle
● CFCopyLocalizedStringWithDefaultValue
● Foundation macros:
● NSLocalizedString
● NSLocalizedStringFromTable
● NSLocalizedStringFromTableInBundle
● NSLocalizedStringWithDefaultValue
You use these macrosin yoursource code to load stringsfrom one of your application’sstringsfiles. The macros
take the user’s current language preferences into account when retrieving the actual string value. In addition,
the genstrings tool searches for these macros and uses the information they contain to build the initial set
of strings files for your application.
For additional information about how to use these macros,see “Loading String ResourcesInto Your Code” (page
37).
String Resources
Creating Strings Resource Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
34Using the genstrings Tool to Create Strings Files
At some point during your development, you need to create the strings files needed by your code. If you wrote
your code using the Core Foundation and Foundation macros, the simplest way to create your strings files is
using the genstrings command-line tool. You can use thistool to generate a new set ofstringsfiles or update
a set of existing files based on your source code.
To use the genstrings tool, you typically provide at least two arguments:
● A list of source files
● An optional output directory
The genstrings tool can parse C, Objective-C, and Java code files with the .c, .m, or .java filename extensions.
Although not strictly required, specifying an output directory is recommended and is where genstrings
places the resulting strings files. In most cases, you would want to specify the directory containing the project
resources for your development language.
The following example shows a simple command for running the genstrings tool. This command causes
the tool to parse all Objective-C source files in the current directory and put the resulting strings files in the
en.lproj subdirectory, which must already exist.
genstrings -o en.lproj *.m
The first time you run the genstrings tool, it creates a set of new stringsfilesfor you. Subsequent runsreplace
the contents of those strings files with the current string entries found in your source code. For subsequent
runs, it is a good idea to save a copy of your current strings files before running genstrings. You can then
diff the new and old versions to determine which strings were added to (or changed in) your project. You can
then use this information to update any already localized versions of your strings files, rather than replacing
those files and localizing them again.
Within a single strings file, each key must be unique. Fortunately, the genstrings tool is smart enough to
coalesce any duplicate entries it finds. When it discovers a key string used more than once in a single strings
file, the tool merges the comments from the individual entries into one comment string and generates a
warning. (You can suppressthe duplicate entries warning with the -q option.) If the same key string is assigned
to strings in different strings files, no warning is generated.
For more information about using the genstrings tool, see the genstrings man page.
String Resources
Creating Strings Resource Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
35Creating Strings Files Manually
Although the genstrings tool is the most convenient way to create strings files, you can also create them
manually. To create a stringsfile manually, create a new file in TextEdit (or your preferred text-editing application)
and save it using the Unicode UTF-16 encoding. (When saving files, TextEdit usually chooses an appropriate
encoding by default. To force a specific encoding, you must change the save options in the application
preferences.) The contents of thisfile consists of a set of key-value pairs along with optional comments describing
the purpose of each key-value pair. Key and value strings are separated by an equal sign, and the entire entry
must be terminated with a semicolon character. By convention, comments are enclosed inside C-style comment
delimiters (/* and */) and are placed immediately before the entry they describe.
Listing 2-2 shows the basic format of a strings file. The entries in this example come from the English version
of the Localizable.strings file from the TextEdit application. The string on the left side of each equal sign
representsthe key, and the string on the rightside representsthe value. A common convention when developing
applications is to use a key name that equals the value in the language used to develop the application.
Therefore, because TextEdit was developed using the English language, the English version of the
Localizable.strings file has keys and values that match.
Listing 2-2 Strings localized for English
/* Menu item to make the current document plain text */
"Make Plain Text" = "Make Plain Text";
/* Menu item to make the current document rich text */
"Make Rich Text" = "Make Rich Text";
Listing 2-3 shows the German translation of the same entries. These entries also live inside a file called
Localizable.strings, but this version of the file is located in the German language project directory of
the TextEdit application. Notice that the keys are still in English, but the values assigned to those keys are in
German. This is because the key strings are never seen by end users. They are used by the code to retrieve the
corresponding value string, which in this case is in German.
Listing 2-3 Strings localized for German
/* Menu item to make the current document plain text */
"Make Plain Text" = "In reinen Text umwandeln";
/* Menu item to make the current document rich text */
"Make Rich Text" = "In formatierten Text umwandeln";
String Resources
Creating Strings Resource Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
36Detecting Non-localizable Strings
AppKit–based applications can take advantage of built-in support to detect strings that do not need to be
localized and those that need to be localized but currently are not. To use this built-in support, you must launch
your application from the command line. In addition to entering the path to your executable, you must also
include the name of the desired setting along with a Boolean value to indicate whether the setting should be
enabled or disabled. The available settings are as follows:
● The NSShowNonLocalizableStrings setting identifies strings that are not localizable. The strings are
logged to the shell in upper case. This option occasionally generates some false positives but is still useful
overall.
● The NSShowNonLocalizedStrings setting locates strings that were meant to be localized but could
not be found in the application’s existing strings files. You can use this setting to catch problems with
out-of-date localizations.
For example, to use the NSShowNonLocalizedStrings setting with the TextEdit application, you would
enter the following in Terminal:
/Applications/TextEdit.app/Contents/MacOS/TextEdit -NSShowNonLocalizedStrings YES
Loading String Resources Into Your Code
The Core Foundation and Foundation frameworks provide macrosfor retrieving both localized and nonlocalized
strings stored in strings files. Although the main purpose of these macros is to load strings at runtime, they
also serve a secondary purpose by acting as markers that the genstrings tool can use to locate your
application’s string resources. It is this second purpose that explains why many of the macros let you specify
much more information than would normally be required for loading a string. The genstrings tool uses the
information you provide to create or update your application’s strings files automatically. Table 2-1 lists the
types of information you can specify for these routines and describes how that information is used by the
genstrings tool.
Table 2-1 Common parameters found in string-loading routines
Parameter Description
The string used to look up the corresponding value. This string must not contain any
characters from the extended ASCII character set, which includes accented versions of
ASCII characters. If you want the initial value string to contain extended ASCII characters,
use a routine that lets you specify a default value parameter. (For information about
the extended ASCII character set, see the corresponding Wikipedia entry.)
Key
String Resources
Loading String Resources Into Your Code
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
37Parameter Description
The name of the strings file in which the specified key is located. The genstrings tool
interprets this parameter as the name of the strings file in which the string should be
placed. If no table name is provided, the string is placed in the default
Localizable.strings file. (When specifying a value for this parameter, include the
filename without the .strings extension.)
Table name
The default value to associate with a given key. If no default value is specified, the
genstrings tool uses the key string as the initial value. Default value strings may
contain extended ASCII characters.
Default
value
Translation comments to include with the string. You can use comments to provide
clues to the translation team about how a given string is used. The genstrings tool
putsthese commentsin the stringsfile and enclosesthem in C-style comment delimiters
(/* and */) immediately above the associated entry.
Comment
An NSBundle object or CFBundleRef type corresponding to the bundle containing
the stringsfile. You can use thisto load stringsfrom bundles other than your application’s
main bundle. For example, you might use this to load localized strings from a framework
or plug-in.
Bundle
When you request a string from a strings file, the string that is returned depends on the available localizations
(if any). The Cocoa and Core Foundation macros use the built-in bundle internationalization support to retrieve
the string whose localization matchesthe user’s current language preferences. Aslong as your localized resource
files are placed in the appropriate language-specific project directories, loading a string with these macros
should yield the appropriate string automatically. If no appropriate localized string resource is found, the
bundle’s loading code automatically chooses the appropriate nonlocalized string instead.
For information about internationalization in general and how to create language-specific project directories,
see Internationalization Programming Topics. For information about the bundle structure and how resource
files are chosen from a bundle directory, see Bundle Programming Guide .
Using the Core Foundation Framework
The Core Foundation framework defines a single function and several macrosfor loading localized stringsfrom
your application bundle. The CFBundleCopyLocalizedString function provides the basic implementation
for retrieving the strings. However, it is recommended that you use the following macros instead:
● CFCopyLocalizedString(key, comment)
● CFCopyLocalizedStringFromTable(key, tableName, comment)
● CFCopyLocalizedStringFromTableInBundle(key, tableName, bundle, comment)
String Resources
Loading String Resources Into Your Code
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
38● CFCopyLocalizedStringWithDefaultValue(key, tableName, bundle, value, comment)
There are several reasons to use the macros instead of the CFBundleCopyLocalizedString function. First,
the macros are easier to use for certain common cases. Second, the macros let you associate a comment string
with the string entry. Third, the macros are recognized by the genstrings tool but the
CFBundleCopyLocalizedString function is not.
For information about the syntax of the preceding macros, see CFBundle Reference .
Using the Foundation Framework
The Foundation framework defines a single method and several macros for loading string resources. The
localizedStringForKey:value:table: method of the NSBundle classloadsthe specified string resource
from a strings file residing in the current bundle. Cocoa also defines the following macros for getting localized
strings:
● NSLocalizedString(key, comment)
● NSLocalizedStringFromTable(key, tableName, comment)
● NSLocalizedStringFromTableInBundle(key, tableName, bundle, comment)
● NSLocalizedStringWithDefaultValue(key, tableName, bundle, value, comment)
As with Core Foundation, Apple recommends that you use the Cocoa convenience macros for loading strings.
The main advantage to these macros is that they can be parsed by the genstrings tool and used to create
your application’s strings files. They are also simpler to use and let you associate translation comments with
each entry.
For information about the syntax of the preceding macros, see Foundation Functions Reference . Additional
methods for loading strings are also defined in NSBundle Class Reference .
Examples of Getting Strings
The following examples demonstrate the basic techniques for using the Foundation and Core Foundation
macros to retrieve strings. Each example assumes that the current bundle contains a strings file with the name
Custom.strings that has been translated into French. This translated file includes the following strings:
/* A comment */
"Yes" = "Oui";
"The same text in English" = "Le même texte en anglais";
String Resources
Loading String Resources Into Your Code
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
39Using the Foundation framework, you can get the value of the “Yes” string using the
NSLocalizedStringFromTable macro, as shown in the following example:
NSString* theString;
theString = NSLocalizedStringFromTable (@"Yes", @"Custom", @"A comment");
Using the Core Foundation framework, you could get the same string using the
CFCopyLocalizedStringFromTable macro, as shown in this example:
CFStringRef theString;
theString = CFCopyLocalizedStringFromTable(CFSTR("Yes"), CFSTR("Custom"), "A
comment");
In both examples, the code specifies the key to retrieve, which is the string “Yes”. They also specify the strings
file (or table) in which to look for the key, which in this case isthe Custom.strings file. During string retrieval,
the comment string is ignored.
Advanced Strings File Tips
The following sections provide some additional tips for working with strings files and string resources.
Searching for Custom Functions With genstrings
The genstrings tool searches for the Core Foundation and Foundation string macros by default. It uses the
information in these macros to create the string entries in your project’s strings files. You can also direct
genstrings to look for custom string-loading functions in your code and use those functions in addition to
the standard macros. You might use custom functionsto wrap the built-in string-loading routines and perform
some extra processing or you might replace the defaultstring handling behavior with your own custom model.
If you want to use genstrings with your own custom functions, your functions must use the naming and
formatting conventions used by the Foundation macros. The parameters for your functions must match the
parameters for the corresponding macros exactly. When you invoke genstrings, you specify the -s option
followed by the name of the function that correspondsto the NSLocalizedString macro. Your other function
names should then build from this base name. For example, if you specified the function name
MyStringFunction, your other function names should be MyStringFunctionFromTable,
MyStringFunctionFromTableInBundle, and MyStringFunctionWithDefaultValue. The genstrings
tool looks for these functions and uses them to build the corresponding strings files.
String Resources
Advanced Strings File Tips
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
40Formatting String Resources
For some strings, you may not want to (or be able to) encode the entire string in a string resource because
portions of the string might change at runtime. For example, if a string contains the name of a user document,
you need to be able to insert that document name into the string dynamically. When creating your string
resources, you can use any of the formatting characters you would normally use for handling string replacement
in the Foundation and Core Foundation frameworks. Listing 2-4 shows several string resources that use basic
formatting characters:
Listing 2-4 Strings with formatting characters
"Windows must have at least %d columns and %d rows." =
"Les fenêtres doivent être composes au minimum de %d colonnes et %d lignes.";
"File %@ not found." = "Le fichier %@ n’existe pas.";
To replace formatting characters with actual values, you use the stringWithFormat: method of NSString
or the CFStringCreateWithFormat function, using the string resource as the format string. Foundation
and Core Foundation support most of the standard formatting characters used in printf statements. In
addition, you can use the %@ specifiershown in the preceding example to insert the descriptive text associated
with arbitrary Objective-C objects. See “Formatting String Objects” in String Programming Guide for the complete
list of specifiers.
One problem that often occurs during translation is that the translator may need to reorder parameters inside
translated strings to account for differences in the source and target languages. If a string contains multiple
arguments, the translator can insert special tags of the form n$ (where n specifies the position of the original
argument) in between the formatting characters. These tags let the translator reorder the arguments that
appear in the original string. The following example shows a string whose two arguments are reversed in the
translated string:
/* Message in alert dialog when something fails */
"%@ Error! %@ failed!" = "%2$@ blah blah, %1$@ blah!";
Using Special Characters in String Resources
Just as in C, some characters must be prefixed with a backslash before you can include them in the string.
These characters include double quotation marks, the backslash character itself, and special control characters
such as linefeed (\n) and carriage returns (\r).
"File \"%@\" cannot be opened" = " ... ";
"Type \"OK\" when done" = " ... ";
String Resources
Advanced Strings File Tips
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
41You can include arbitrary Unicode characters in a value string by specifying \U followed immediately by up to
four hexadecimal digits. The four digits denote the entry for the desired Unicode character; for example, the
space character is represented by hexadecimal 20 and thus would be \U0020 when specified as a Unicode
character. This option is useful if a string must include Unicode characters that for some reason cannot be
typed. If you use this option, you must also pass the -u option to genstrings in order for the hexadecimal
digits to be interpreted correctly in the resulting strings file. The genstrings tool assumes your strings are
low-ASCII by default and only interprets backslash sequences if the -u option is specified.
Note: The genstrings tool always generatesstringsfiles using the UTF-16 encoding. If you include
Unicode characters in your strings and do not use genstrings to create your strings files, be sure
to save your strings files in the UTF-16 encoding.
Debugging Strings Files
If you run into problems during testing and find that the functions and macros for retrieving strings are always
returning the same key (as opposed to the translated value), run the /usr/bin/plutil tool on your strings
file. A strings file is essentially a property-list file formatted in a special way. Running plutil with the -lint
option can uncover hidden characters or other errorsthat are preventing stringsfrom being retrieved correctly.
String Resources
Advanced Strings File Tips
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
42The OS X and iOS platforms were built to provide a rich multimedia experience. To support that experience,
both platforms provide plenty of support for loading and using image, sound, and video resources in your
application. Image resources are commonly used to draw portions of an application’s user interface. Sound
and video resources are used less frequently but can also enhance the basic appearance and appeal of an
application. The following sections describe the support available for working with image, sound, and video
resources in your applications.
Images and Sounds in Nib Files
Using Xcode, you can reference your application’s sound and image files from within nib files. You might do
so to associate those images or sounds with different properties of a view or control. For example, you might
set the default image to display in an image view or set the image to display for a button. Creating such a
connection in a nib file saves you the hassle of having to make that connection later when the nib file isloaded.
To make image and sound resources available in a nib file, all you have to do is add them to your Xcode project;
Xcode then lists them in the library pane. When you make a connection to a given resource file, Xcode makes
a note of that connection in the nib file. At load time, the nib-loading code looksfor that resource in the project
bundle, where it should have been placed by Xcode at build time.
When you load a nib file that contains references to image and sound resources, the nib-loading code caches
resources whenever possible for easy retrieval later. For example, after loading a nib file, you can retrieve an
image associated with that nib file using the imageNamed: method of either NSImage or UIImage (depending
on your platform). In OS X you can retrieve cached sound resources using the soundNamed: method of
NSSound.
Loading Image Resources
Image resources are commonly used in most applications. Even very simple applications use images to create
a custom look for controls and views. OS X and iOS provide extensive support for manipulating image data
using Objective-C objects. These objects make using image images extremely easy, often requiring only a few
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
43
Image, Sound, and Video Resourceslines of code to load and draw the image. If you prefer not to use the Objective-C objects, you can also use
Quartz to load images using a C-based interface. The following sections describe the processfor loading image
resource files using each of the available techniques.
Loading Images in Objective-C
To load images in Objective-C, you use either the NSImage or UIImage object, depending on the current
platform. Applications built for OS X using the AppKit framework use the NSImage object to load images and
draw them. Applications built for iOS use the UIImage object. Functionally, both of these objects provide
almost identical behavior when it comesto loading existing image resources. You initialize the object by passing
it a pointer to the image file in your application bundle and the image object takes care of the details of loading
the image data.
Listing 3-1 shows how to load an image resource using the NSImage class in OS X. After you locate the image
resource, which in this case is in the application bundle, you simply use that path to initialize the image object.
After initialization, you can draw the image using the methods of NSImage or passthat object to other methods
that can use it. To perform the exactsame task in iOS, all you would need to do is change references of NSImage
to UIImage.
Listing 3-1 Loading an image resource
NSString* imageName = [[NSBundle mainBundle] pathForResource:@"image1"
ofType:@"png"];
NSImage* imageObj = [[NSImage alloc] initWithContentsOfFile:imageName];
You can use image objectsto open any type of image supported on the target platform. Each object istypically
a lightweight wrapper for more advanced image handling code. To draw an image in the current graphics
context, you would simply use one of its drawing related methods. Both NSImage and UIImage have methods
for drawing the image in several different ways. The NSImage class also provides extra support for manipulating
the images you load.
For information about the methods of the NSImage and UIImage classes, see NSImage Class Reference and
UIImage Class Reference . For more detailed information about the additional features of the NSImage class,
see “Images” in Cocoa Drawing Guide .
Image, Sound, and Video Resources
Loading Image Resources
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
44Loading Images Using Quartz
If you are writing C-based code, you can use a combination of Core Foundation and Quartz calls to load image
resources into your applications. Core Foundation provides the initial support for locating image resources
and loading the corresponding image data into memory. Quartz takes the image data you load into memory
and turns it into a usable CGImageRef that your code can then use to draw the image.
There are two ways to load images using Quartz: data providers and image source objects. Data providers are
available in both iOS and OS X. Image source objects are available only in OS X v10.4 and later but take advantage
of the Image I/O framework to enhance the basic image handling capabilities of data providers. When it comes
to loading and displaying image resources, both technologies are well suited for the job. The only time you
might prefer image sources over data providers is when you want greater access to the image-related data.
Listing 3-2 shows how to use a data provider to load a JPEG image. This method uses the Core Foundation
bundle support to locate the image in the application’s main bundle and get a URL to it. It then uses that URL
to create the data provider object and then create a CGImageRef for the corresponding JPEG data. (For brevity
this example omits any error-handling code. Your own code should make sure that any referenced data
structures are valid.)
Listing 3-2 Using data providers to load image resources
CGImageRef MyCreateJPEGImageRef (const char *imageName);
{
CGImageRef image;
CGDataProviderRef provider;
CFStringRef name;
CFURLRef url;
CFBundleRef mainBundle = CFBundleGetMainBundle();
// Get the URL to the bundle resource.
name = CFStringCreateWithCString (NULL, imageName, kCFStringEncodingUTF8);
url = CFBundleCopyResourceURL(mainBundle, name, CFSTR("jpg"), NULL);
CFRelease(name);
// Create the data provider object
provider = CGDataProviderCreateWithURL (url);
CFRelease (url);
// Create the image object from that provider.
Image, Sound, and Video Resources
Loading Image Resources
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
45image = CGImageCreateWithJPEGDataProvider (provider, NULL, true,
kCGRenderingIntentDefault);
CGDataProviderRelease (provider);
return (image);
}
For detailed information about working with Quartz images, see Quartz 2D Programming Guide . For reference
information about data providers, see Quartz 2D Reference Collection (OS X) or Core Graphics Framework
Reference (iOS).
Specifying High-Resolution Images in iOS
An iOS app should include high-resolution versions of its image resources. When the app is run on a device
that has a high-resolution screen, high-resolution images provide extra detail and look better because they
do not need to be scaled to fit the space. You provide high-resolution images for each image resource in your
application bundle, including icons and launch images.
To specify a high-resolution version of an image, create a version whose width and height (measured in pixels)
are twice that of the original. You use the extra pixels in the image to provide additional detail. When saving
the image, use the same base name but include the string @2x between the base filename and the filename
extension. For example, if you have an image named MyImage.png, the name of the high-resolution version
would be MyImage@2x.png. Put the high-resolution and original versions of your image in the same location
in your application bundle.
The bundle- and image-loading routines automatically look for image files with the @2x string when the
underlying device has a high-resolution screen. If you combine the @2x string with other modifiers, the @2x
string should come before any device modifiers but after all other modifiers, such as launch orientation or URL
scheme modifiers. For example:
MyImage.png - Default version of an image resource.
MyImage@2x.png - High-resolution version of an image resource for devices with Retina displays.
MyImage~iphone.png - Version of an image for iPhone and iPod touch.
MyImage@2x~iphone.png - High-resolution version of an image for iPhone and iPod touch devices with
Retina displays.
Image, Sound, and Video Resources
Loading Image Resources
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
46When you want to load an image, do not include the @2x or any device modifiers when specifying the image
name in your code. For example, if your application bundle included the image files from the preceding list,
you would ask for an image named MyImage.png. The system automatically determines which version of the
image is most appropriate and loads it. Similarly, when using or drawing that image, you do not have to know
whether it is the original resolution or high-resolution version. The image-drawing routines automatically
adjust based on the image that wasloaded. However, if you still want to know whether an image isthe original
or high-resolution version, you can check its scale factor. If the image is the high-resolution version, its scale
factor is set to a value other than 1.0.
For more information about how to support high-resolution devices, see “Supporting High-Resolution Screens”.
Image, Sound, and Video Resources
Loading Image Resources
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
47Separating your application’s data from its code can make it easier to modify your application later. If you store
the configuration data for your application in resource files, you can change that configuration without having
to recompile your application. Data resource files can be used to store any type of information. The following
sections highlight some of the data resource types supported by iOS and OS X.
Property List Files
Property list files are a way to store custom configuration data outside of your application code. OS X and iOS
use property lists extensively to implement features such as user preferences and information property list
files for bundles. You can similarly use property lists to store private (or public) configuration data for your
applications.
A property-list file is essentially a set of structured data values. You can create and edit property lists either
programmatically or using the Property List Editor application (located in
/Developer/Applications/Utilities). The structure of custom property-list files is completely up to
you. You can use property liststo store string, number, Boolean, date, and raw data values. By default, a property
list stores data in a single dictionary structure, but you can assign additional dictionaries and arrays as values
to create a more hierarchical data set.
For information about using property lists,see Property List Programming Guide and Property List Programming
Topics for Core Foundation .
OS X Data Resource Files
Table 4-1 lists some additional resource file types that are supported in Mac apps.
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
48
Data Resource FilesTable 4-1 Other resource types
Resource Description
Type
In OS X, AppleScript terminology and suite files contain information about the
scriptability of an application. These files can use the file extensions .sdef,
.scriptSuite, or .scriptTerminology. Because the actual AppleScript commands
used to script an application are visible in userscripts and the Script Editor application,
these resources need to be localized. For information on supporting AppleScript, see
AppleScript Overview.
AppleScript
files
In OS X, help content typically consists of a set of HTML files created using a standard
text-editing program and registered with the Help Viewer application. (For information
on how to register with Help Viewer, see Apple Help Programming Guide .) It is also
possible to embed PDF files, RTF files, HTML files or other custom documents in your
bundle and open them using an external application, such as Preview or Safari. For
information on how to open files, see Launch Services Programming Guide .
Help files
Data Resource Files
OS X Data Resource Files
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
49This table describes the changes to Resource Programming Guide .
Date Notes
Modified discussion of high-resolution image resources to include all
Retina displays.
2012-06-11
2011-10-12 Updated for ARC and iOS 5.
Corrected information about how you specify high-resolution image
resource filenames.
2010-09-15
2010-05-25 Updated references to the Apple developer website.
2009-01-06 Added information about KVO notifications during nib loading.
2008-06-26 Updated for iOS.
Clarified the process of how objects are instantiated when a nib file is
loaded.
2007-09-04
Reorganized content and added new information. Changed title from
"Loading Resources".
2007-02-08
2005-11-09 Corrected the misidentification of a class method as an instance method.
Added “Instantiating Nibs From Memory” and the link to the NSNib class
reference.
2003-07-09
2003-05-28 Section on initializing nib file objects corrected and expanded.
Revision history was added to existing topic. It will be used to record
changes to the content of the topic.
2002-11-12
2012-06-11 | © 2012 Apple Inc. All Rights Reserved.
50
Document Revision HistoryApple Inc.
© 2012 Apple Inc.
All rights reserved.
No part of this publication may be reproduced,
stored in a retrievalsystem, or transmitted, in any
form or by any means, mechanical, electronic,
photocopying, recording, or otherwise, without
prior written permission of Apple Inc., with the
following exceptions: Any person is hereby
authorized to store documentation on a single
computer for personal use only and to print
copies of documentation for personal use
provided that the documentation contains
Apple’s copyright notice.
No licenses, express or implied, are granted with
respect to any of the technology described in this
document. Apple retains all intellectual property
rights associated with the technology described
in this document. This document is intended to
assist application developers to develop
applications only for Apple-labeled computers.
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, AppleScript, Cocoa, iPad,
iPhone, iPod, iPod touch, Mac, Objective-C, OS X,
Quartz, Safari, and Xcode are trademarks of Apple
Inc., registered in the U.S. and other countries.
Retina is a trademark of Apple Inc.
Java is a registered trademark of Oracle and/or
its affiliates.
iOS is a trademark or registered trademark of
Cisco in the U.S. and other countries and is used
under license.
Even though Apple has reviewed this document,
APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS
DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
PURPOSE.ASARESULT, THISDOCUMENT IS PROVIDED
“AS IS,” AND YOU, THE READER, ARE ASSUMING THE
ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL,OR CONSEQUENTIAL
DAMAGES RESULTING FROM ANY DEFECT OR
INACCURACY IN THIS DOCUMENT, even if advised of
the possibility of such damages.
THE WARRANTY AND REMEDIES SET FORTH ABOVE
ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL
OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,
agent, or employee is authorized to make any
modification, extension, or addition to this warranty.
Some states do not allow the exclusion or limitation
of implied warranties or liability for incidental or
consequential damages, so the above limitation or
exclusion may not apply to you. This warranty gives
you specific legal rights, and you may also have other
rights which vary from state to state.
Safari CSS Visual Effects
GuideContents
Introduction 8
At a Glance 9
Use CSS Properties to Add Gradients, Masks, Reflections, and Filters 9
Animate Changes in CSS Properties 9
Apply 2D and 3D Transformations to Any HTML Element 10
How to Use This Document 10
Prerequisites 11
See Also 11
Using Gradients 12
Creating Linear Gradients 12
Setting the Direction of Change 13
Setting the Rate of Change 14
Creating Gradient Fades 16
Creating Radial Gradients 17
Moving the Center 18
Changing the Ending Color Location 19
Adding Color Stops 20
Creating a Radial Fade 22
Creating Repeating Gradients 23
Using a Gradient as a Border Image 24
Prior Syntax (-webkit-gradient) 26
Using Masks 28
Using an Image as a Mask 28
Using a Gradient as a Mask 32
Working with WebKit Mask Properties 35
Using Reflections 37
Adding a Reflection 37
Adjusting the Reflection’s Position 38
Masking a Reflection 39
Inner Reflections 41
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
2Using CSS Filters 43
Using CSS Filters 43
Animating CSS Transitions 45
Setting Transition Properties 46
Using Timing Functions 47
Delaying the Start 48
Setting Several Transition Properties At Once 48
Handling Intermediate States and Events 49
Animating With Keyframes 50
Creating a Keyframe Animation 51
Creating Keyframes 52
Setting Animation Properties 53
Animation Timing Functions 54
Starting Animations 55
Controlling Animation Using JavaScript 56
Handling Animation Events 58
Using 2D and 3D Transforms 61
2D Transform Functions 62
2D Translation 63
2D Rotation 63
2D Scaling 65
Setting Multiple Transforms 66
Changing the Origin 67
3D Transforms 69
Adding 3D Perspective 70
Creating a 3D Space 74
3D Transform Functions 76
Back Face Visibility 80
Using Transformation Matrices 81
2D Matrix Operations 82
3D Matrix Operations 84
Working with Transforms in JavaScript 84
Example: Animated Rotating Box Under JavaScript Control 86
Adding Interactive Control to Visual Effects 90
Using a Click or Tap to Trigger a Transition Effect 90
Controlling a 3D Transform with a Click, Touch, or Swipe 91
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
3
ContentsUsing Gestures to Scale and Rotate Elements 95
Document Revision History 99
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
4
ContentsFigures and Listings
Using Gradients 12
Figure 1-1 Simple linear gradient 13
Figure 1-2 Rainbow gradient 13
Figure 1-3 Diagonal gradients 14
Figure 1-4 Setting color stop percentages 15
Figure 1-5 Solid color band and abrupt color change 15
Figure 1-6 Linear gradient fade 16
Figure 1-7 Simple radial gradient 17
Figure 1-8 Circular gradient 18
Figure 1-9 3D lighting effect 19
Figure 1-10 Closest-corner gradient fills 20
Figure 1-11 Multicolor gradient 21
Figure 1-12 Red color stop at 20% 21
Figure 1-13 Color band and abrupt color change using color stops 22
Figure 1-14 Spotlight gradient 23
Figure 1-15 Repeating gradient patterns 24
Figure 1-16 Linear gradient border 25
Figure 1-17 Radial gradient border 26
Listing 1-1 Linear fade 16
Listing 1-2 Radial fade 22
Using Masks 28
Figure 2-1 Heart-shaped “cookie-cutter” 29
Figure 2-2 Masking a border 30
Figure 2-3 Stacking masks 31
Figure 2-4 Applying a mask with a fuzzy border 32
Figure 2-5 Result of applying a gradient mask 33
Figure 2-6 Horizontal gradient mask with color stops 34
Figure 2-7 Masking text with a radial gradient 35
Listing 2-1 Stacking masked elements 30
Using Reflections 37
Figure 3-1 Reflection below a heading 38
Figure 3-2 Reflection with negative offset 39
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
5Figure 3-3 Reflection with image as mask 40
Figure 3-4 Image with reflection and gradient mask 41
Figure 3-5 Inner reflection, reflected 42
Using CSS Filters 43
Figure 4-1 CSS filters on a video 43
Listing 4-1 Applying CSS filters to HTML elements 44
Animating CSS Transitions 45
Figure 5-1 Card Flip example 45
Figure 5-2 Cubic Bezier timing function 47
Figure 5-3 Transition of two properties 49
Listing 5-1 Setting transition properties 46
Listing 5-2 Creating multiple transitions at once 47
Listing 5-3 Defining a custom timing function 48
Listing 5-4 Detecting transition end events 49
Animating With Keyframes 50
Figure 6-1 Animated text elements 50
Figure 6-2 Animation timing function control points 54
Figure 6-3 JavaScript control of animation 58
Listing 6-1 Simple keyframe animation 51
Listing 6-2 Declaring keyframes 52
Listing 6-3 Starting an animation 56
Listing 6-4 Pausing and continuing an animation 57
Listing 6-5 Handling animation events 59
Using 2D and 3D Transforms 61
Figure 7-1 HTML page with rotation and perspective transforms 61
Figure 7-2 A translated element and its offspring 63
Figure 7-3 Rotating an element 64
Figure 7-4 Scaling an element up 66
Figure 7-5 Element rotated around the top-right corner 68
Figure 7-6 3D coordinate space 69
Figure 7-7 Setting the perspective 72
Figure 7-8 Perspective origin effects 74
Figure 7-9 Text rotated relative to 3D backdrop 76
Figure 7-10 Z-axis translation in perspective 78
Figure 7-11 X and y rotation 79
Figure 7-12 Cardflip example 81
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
6
Figures and ListingsFigure 7-13 2D transformation matrix parameter positions 82
Figure 7-14 Matrix mirroring transforms 83
Figure 7-15 3D matrix parameters 84
Figure 7-16 3D transforms under JavaScript control 89
Listing 7-1 Animating 2D rotation 64
Listing 7-2 Setting multiple transforms using a list 67
Listing 7-3 Nesting 2D transforms 67
Listing 7-4 Rotating an element around the top-right corner 68
Listing 7-5 Adding a perspective slider 70
Listing 7-6 Effects of perspective origin 73
Listing 7-7 Nested 3D rotations 75
Listing 7-8 Hiding the back side of a card 80
Listing 7-9 Matrix example 82
Adding Interactive Control to Visual Effects 90
Figure 8-1 Click and tap handler 91
Figure 8-2 Page flip in action 93
Figure 8-3 Element rotated by a gesture 96
Listing 8-1 Simple touch or tap handler 90
Listing 8-2 Page flip on click, tap, or swipe 93
Listing 8-3 Responding to gesture events 96
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
7
Figures and ListingsUse CSS to create stunning visual effects—masks, gradients, reflections, lighting effects, animations, transitions,
3D rotations, and more. Apply any or all of these effects interactively, triggered by mouse events or touch
events; make HTML elements visibly respond to the user—without requiring plug-ins, graphics libraries, or
elaborate JavaScript programs.
There are advantages to using CSS instead of graphic images to create visual effects:
● Because they are resolution-independent, CSS effects scale up smoothly when zoomed.
● Text formatted with CSS is searchable; images are not.
● CSS is compact and compresses well compared with graphic images.
● CSS is just text; it can be quickly modified using a text editor or the output of a script.
Safari supports CSS visual effects on Mac OS X and iOS.
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
8
IntroductionAt a Glance
Safari CSS visual effectsfall into three categories: new visual CSS properties, animation, and 2D and 3D transforms.
Use CSS Properties to Add Gradients, Masks, Reflections, and Filters
New visual CSS properties include gradients, masks, reflections, and filters. Gradients let you add beautiful,
resolution-independent color blends to backgrounds and borders, with a single line of CSS.
Use masks to render portions of HTML elements transparent for elegant compositing. Apply a mask as you
would a background or a border image. You can use an image as a mask. You can also use a gradient as a
mask, and you can mask any HTML element, not just images.
Add a reflection to any element; use a gradient as a mask for a reflection to make the reflection fade to
transparency.
Filters allow you to add hardware-accelerated visual effects to HTML elements, including images and videos.
Relevant chapters: “Using Gradients” (page 12), “Using a Gradient as a Mask” (page 32), “Using
Reflections” (page 37), “Using CSS Filters” (page 43).
Animate Changes in CSS Properties
CSS makes animation easy: specify the properties you want animated, and optionally supply a duration for the
animation, and any change to those CSS properties is automatically made into an animation of the HTML
element, without using graphic plug-ins or even JavaScript. Use CSS pseudoclasses such as :hover to make
the animations interactive—have elements fade in, grow, or enter from offscreen in response to touch or
mouse events.
CSS animations come in two flavors: implicit animations that render changes smoothly over a defined period,
and keyframe animations that allow for more complex behavior, such as moving from side to side or starting
and stopping en route.
Introduction
At a Glance
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
9Relevant chapters: “Animating CSS Transitions” (page 45), “Animating With Keyframes” (page 50).
Apply 2D and 3D Transformations to Any HTML Element
You can apply 2D or 3D transforms to any HTML element, turning a group of div elements into the faces of a
box or the pages of a book, for example. Apply perspective and animation, and you can open and close the
box, turn it to look inside, flip the pages of the book, and so on. 2D transforms include scaling, translation,
shearing, reflection, and rotation. 3D transforms add rotation about the x and y axis and displacement on the
z axis.
Add touch and mouse interaction to trigger transformations by implementing CSS pseudoclasses, such as
:hover, or by writing your own JavaScript functions.
Relevant chapters: “Using 2D and 3D Transforms” (page 61), “Adding Interactive Control to Visual
Effects” (page 90).
How to Use This Document
The visual effects described in this document are WebKit extensions of CSS. Most of the extensions are proposals
for W3C standards;some are in W3C draftsfor CSS3. Asthe standards evolve,syntax for these effectsis modified.
This change is done carefully to allow new syntax to coexist with existing syntax, however. This means you
can experiment with CSS extensions without having your website suddenly break when the standard is
modified—in most cases, the old syntax still works. This document describes the current syntax as of this
writing; many of the extensions have prior syntax that still works but is no longer recommended.
Introduction
How to Use This Document
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
10Note: Because these extensions are WebKit-specific, they are not supported in all browsers. Most
of the extensions have equivalentsin other WebKit-based browsers, however, and for mobile-specific
sites, WebKit-based browsers account for nearly all traffic. Many of the extensions are currently in
W3C working drafts and have equivalents in non-WebKit browsers as well, using the same syntax.
Nevertheless, unless you are writing an iOS web app, you should code your website to degrade
gracefully for browsersthat do notsupport these extensions. For the most part, thisis automatic—an
image may not have a reflection in some browsers, or a change in CSS properties may be immediate
instead of animated—but the site remains functional and the layout is not broken. As always, you
should test your website using all the browsers that you wish to support to ensure that all of your
users have an aesthetically pleasing experience.
Prerequisites
You need a solid understanding of HTML and some familiarity with JavaScript and CSS to make good use of
this document.
See Also
You may also find the following documents helpful:
● Safari DOM Additions Reference—describes the touch event classes that you use to handle multi-touch
gestures in JavaScript.
● Safari CSS Reference—describes the CSS properties supported by various Safari and WebKit applications.
● Safari Web Content Guide—describes how to create content that is compatible with, optimized for, and
customized for iOS.
●
iOS Human Interface Guidelines—provides user interface guidelines for designing webpages and web
applications for Safari on iOS.
● FingerTips—demonstrates how to build an interactive 3D carousel using CSS,JavaScript and touch events.
● http://dev.w3.org/csswg/css3-images/—W3C draft for gradients.
● http://www.w3.org/TR/css3-transitions/—W3C draft for animated transitions.
● http://www.w3.org/TR/css3-animations/—W3C draft for keyframe animations.
● http://www.w3.org/TR/css3-2d-transforms/—W3C draft for 2D transforms.
● http://www.w3.org/TR/css3-3d-transforms/—W3C draft for 3D transforms.
Introduction
Prerequisites
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
11Use gradients as color fills that blend smoothly from one color to another. Use a CSS gradient anywhere that
you can use an image, such as for the background of an element, an element border, or a mask. Because
gradients are resolution-independent and compact, a line or two of CSS can replace hundreds of kilobytes—or
even megabytes—of graphic imagery. Unlike graphic images, gradients have no inherentsize, and automatically
expand to fill a container.
To create a gradient, specify a starting color and an ending color, and optionally intermediate colors and a
direction. Safari supports two types of CSS gradients: linear and radial. This chapter describes both types of
gradients. Safari 5.1 on the desktop, and Safari on iOS 5.0, use the -webkit- prefix for specifying gradients,
but otherwise conform to the 17 February 2011 working draft for CSS3 gradients: http://dev.w3.org/csswg/css3-
images/.
Note: Recent drafts of the W3C proposal have simplified the syntax. This chapter describesthe most
recent implementation shipping in Safari. You should expect Safari’ssyntax for gradientsto continue
to change as the W3C standard evolves. While new syntax is expected, the existing syntax—and
prior syntax—should still work.
The -webkit-linear-gradient and webkit-radial-gradient properties require iOS 5.0 or
later, or Safari 5.1 or later on the desktop. If you need to support earlier releases of iOS or Safari, see
“Prior Syntax (-webkit-gradient)” (page 26).
Creating Linear Gradients
A linear gradient defines a color change along a specified line. Each point on the line has a particular color.
The width of the line, perpendicular to the direction of the line, extendsto the edges of the gradient’s container.
You can use a linear gradient to fill any two-dimensional shape. By default, a linear gradient changes colors
from top to bottom. For example:
background: -webkit-linear-gradient(aqua, white)
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
12
Using Gradientsdefines a linear gradient that starts as aqua at the top of the element and ends as white at the bottom of the
element. The gradient fills the element completely, as Figure 1-1 illustrates.
Figure 1-1 Simple linear gradient
If you specify intermediate colors between the starting and ending color, the gradient blends from color to
color. For example:
background: -webkit-linear-gradient(red, yellow, orange, green, blue, purple);
defines a rainbow gradient as a background. Apply this style to a div element, and the element is drawn with
a rainbow background, as Figure 1-2 illustrates.
Figure 1-2 Rainbow gradient
Setting the Direction of Change
You can define a linear gradient with the color change going in any direction: from any edge or corner to its
opposite edge or corner, or at any specified angle. To specify a direction from edge-to-edge or corner-to-corner,
just specify the beginning edge or corner. For example:
● background: -webkit-linear-gradient(left, black, white);
creates a horizontal gradient going from left to right.
● background: -webkit-linear-gradient(bottom right, black, white);
Using Gradients
Creating Linear Gradients
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
13creates a diagonal gradient from bottom right to top left.
You can also specify color change direction by supplying an angle. Angles are given in degrees, with 0deg
being straight up and proceeding counterclockwise-positive, so that 90deg is horizontal left and 180deg is
straight down. For example:
-webkit-linear-gradient(45deg, black, white)
creates a gradient at a 45 degree angle up and to the left.
Note: If you specify a gradient from corner to corner, the angle of the gradient changesif the parent
element is resized and the shape of the element changes. Specify the direction in degrees to create
a gradient with a fixed angle.
Figure 1-3 shows a diagonal gradient starting at the bottom left corner.
Figure 1-3 Diagonal gradients
Setting the Rate of Change
By default, the rate of color change for a gradient remains constant; if the gradient has three colors, the blend
starts with the first color at 0% of the gradient length, reaches the second color at 50% of the gradient length,
and reaches the third color at 100% of the gradient length. In other words, the first line of the gradient is the
starting color, the middle line is the second color, and the last line is the third color. To modify this behavior,
specify color stops. For example, the following snippet creates a gradient that changes gradually from white
to cornflower blue over 90% of the gradient length then blends quickly from to black over the remaining 10%:
-webkit-linear-gradient(left, white, cornflowerblue 90%, black)
Using Gradients
Creating Linear Gradients
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
14Figure 1-4 shows such a gradient.
Figure 1-4 Setting color stop percentages
Color stops can create some striking effects. For example, specify the same color at two consecutive stops to
create a band of solid color, or specify two different colors at the same percentage point to create an abrupt
change in color. Figure 1-5 shows the effect these kind of color stops create.
background: -webkit-linear-gradient(left,black,blue 10%,blue 90%,black);
background: -webkit-linear-gradient(left,white,blue 50%,purple 50%,white);
Figure 1-5 Solid color band and abrupt color change
Using Gradients
Creating Linear Gradients
2012-07-23 | © 2012 Apple Inc. All Rights Reserved.
15Creating Gradient Fades
Use RGBa colors in a gradient to soften or fade colors into the background by decreasing the alpha value of
the gradient. For example, Listing 1-1 creates a div element with a white background that fadesto transparent.
Two consecutive white color stops are used, so the div element’s background stays white for 50% of its width
and then fades into the background of the element’s parent. Figure 1-6 shows the result.
Listing 1-1 Linear fade
rgba gradient
RGBa Gradient Fades