Merge pull request #2219 from dreampiggy/feature_image_transformer
Feature image transformer
This commit is contained in:
commit
3196a6b678
|
@ -388,6 +388,30 @@
|
|||
32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; };
|
||||
32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; };
|
||||
32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; };
|
||||
32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0722030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C06D2030114C00873181 /* SDWebImageTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0752030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; };
|
||||
32F7C0762030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; };
|
||||
32F7C0772030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; };
|
||||
32F7C0782030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; };
|
||||
32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; };
|
||||
32F7C07A2030114C00873181 /* SDWebImageTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C06E2030114C00873181 /* SDWebImageTransformer.m */; };
|
||||
32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; };
|
||||
32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; };
|
||||
32F7C0802030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; };
|
||||
32F7C0812030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; };
|
||||
32F7C0822030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; };
|
||||
32F7C0832030719600873181 /* UIImage+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F7C07C2030719600873181 /* UIImage+Transform.m */; };
|
||||
32F7C0842030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0852030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0862030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0872030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0882030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32F7C0892030719600873181 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F7C07D2030719600873181 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4314D1231D0E0E3B004B36C9 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D86148C56230056699D /* SDImageCache.m */; };
|
||||
4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 53922D8C148C56230056699D /* SDWebImageDownloader.m */; };
|
||||
4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; };
|
||||
|
@ -1391,6 +1415,10 @@
|
|||
32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = "<group>"; };
|
||||
32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = "<group>"; };
|
||||
32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = "<group>"; };
|
||||
32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = "<group>"; };
|
||||
32F7C06E2030114C00873181 /* SDWebImageTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformer.m; sourceTree = "<group>"; };
|
||||
32F7C07C2030719600873181 /* UIImage+Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Transform.m"; sourceTree = "<group>"; };
|
||||
32F7C07D2030719600873181 /* UIImage+Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Transform.h"; sourceTree = "<group>"; };
|
||||
4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
431BB7031D06D2C1006A3455 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4369C2751D9807EC007E863A /* UIView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = "<group>"; };
|
||||
|
@ -1835,6 +1863,8 @@
|
|||
53EDFB921762547C00698166 /* UIImage+WebP.m */,
|
||||
321E60BC1F38E91700405457 /* UIImage+ForceDecode.h */,
|
||||
321E60BD1F38E91700405457 /* UIImage+ForceDecode.m */,
|
||||
32F7C07D2030719600873181 /* UIImage+Transform.h */,
|
||||
32F7C07C2030719600873181 /* UIImage+Transform.m */,
|
||||
4397D2F41D0DE2DF00BB2784 /* NSImage+Additions.h */,
|
||||
4397D2F51D0DE2DF00BB2784 /* NSImage+Additions.m */,
|
||||
AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */,
|
||||
|
@ -1878,6 +1908,8 @@
|
|||
325312C7200F09910046BF1E /* SDWebImageTransition.m */,
|
||||
32C0FDDF2013426C001B8F2D /* SDWebImageIndicator.h */,
|
||||
32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */,
|
||||
32F7C06D2030114C00873181 /* SDWebImageTransformer.h */,
|
||||
32F7C06E2030114C00873181 /* SDWebImageTransformer.m */,
|
||||
);
|
||||
name = Utils;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2125,11 +2157,13 @@
|
|||
80377C5F1F2F666300F89830 /* utils.h in Headers */,
|
||||
80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */,
|
||||
323F8BF91F38EF770092B609 /* animi.h in Headers */,
|
||||
32F7C0872030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
80377C4F1F2F666300F89830 /* filters_utils.h in Headers */,
|
||||
80377C4C1F2F666300F89830 /* color_cache_utils.h in Headers */,
|
||||
32C0FDE42013426C001B8F2D /* SDWebImageIndicator.h in Headers */,
|
||||
321E60C11F38E91700405457 /* UIImage+ForceDecode.h in Headers */,
|
||||
80377DBE1F2F66A700F89830 /* dsp.h in Headers */,
|
||||
32F7C0722030114C00873181 /* SDWebImageTransformer.h in Headers */,
|
||||
80377EB81F2F66D400F89830 /* alphai_dec.h in Headers */,
|
||||
00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */,
|
||||
80377C551F2F666300F89830 /* quant_levels_dec_utils.h in Headers */,
|
||||
|
@ -2152,8 +2186,10 @@
|
|||
321E60BF1F38E91700405457 /* UIImage+ForceDecode.h in Headers */,
|
||||
80377EA61F2F66D400F89830 /* webpi_dec.h in Headers */,
|
||||
807A12291F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */,
|
||||
32F7C0852030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
80377C141F2F666300F89830 /* bit_reader_utils.h in Headers */,
|
||||
323F8C0F1F38EF770092B609 /* muxi.h in Headers */,
|
||||
32F7C0702030114C00873181 /* SDWebImageTransformer.h in Headers */,
|
||||
80377C2B1F2F666300F89830 /* utils.h in Headers */,
|
||||
4314D1621D0E0E3B004B36C9 /* mux_types.h in Headers */,
|
||||
4314D1631D0E0E3B004B36C9 /* demux.h in Headers */,
|
||||
|
@ -2255,6 +2291,7 @@
|
|||
80377E211F2F66A800F89830 /* neon.h in Headers */,
|
||||
80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */,
|
||||
323F8B541F38EF770092B609 /* backward_references_enc.h in Headers */,
|
||||
32F7C0882030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
43A62A1F1D0E0A800089D7DD /* mux.h in Headers */,
|
||||
431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */,
|
||||
80377ED41F2F66D500F89830 /* vp8li_dec.h in Headers */,
|
||||
|
@ -2289,6 +2326,7 @@
|
|||
323F8BFA1F38EF770092B609 /* animi.h in Headers */,
|
||||
431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */,
|
||||
321E60B41F38E90100405457 /* SDWebImageWebPCoder.h in Headers */,
|
||||
32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */,
|
||||
431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */,
|
||||
80377DF51F2F66A800F89830 /* common_sse2.h in Headers */,
|
||||
323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */,
|
||||
|
@ -2305,6 +2343,7 @@
|
|||
80377ED81F2F66D500F89830 /* alphai_dec.h in Headers */,
|
||||
321E60A71F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */,
|
||||
324DF4B9200A14DC008A84CC /* SDWebImageDefine.h in Headers */,
|
||||
32F7C0892030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
80377EDA1F2F66D500F89830 /* common_dec.h in Headers */,
|
||||
80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */,
|
||||
4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */,
|
||||
|
@ -2340,6 +2379,7 @@
|
|||
32CF1C0C1FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */,
|
||||
43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
|
||||
4397D2D81D0DDD8C00BB2784 /* UIButton+WebCache.h in Headers */,
|
||||
32F7C0742030114C00873181 /* SDWebImageTransformer.h in Headers */,
|
||||
80377E641F2F66A800F89830 /* mips_macro.h in Headers */,
|
||||
323F8BDD1F38EF770092B609 /* vp8i_enc.h in Headers */,
|
||||
323F8B671F38EF770092B609 /* cost_enc.h in Headers */,
|
||||
|
@ -2452,11 +2492,13 @@
|
|||
4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */,
|
||||
323F8BF81F38EF770092B609 /* animi.h in Headers */,
|
||||
80377C351F2F666300F89830 /* filters_utils.h in Headers */,
|
||||
32F7C0862030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
80377C321F2F666300F89830 /* color_cache_utils.h in Headers */,
|
||||
321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */,
|
||||
32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */,
|
||||
80377D791F2F66A700F89830 /* dsp.h in Headers */,
|
||||
80377EA81F2F66D400F89830 /* alphai_dec.h in Headers */,
|
||||
32F7C0712030114C00873181 /* SDWebImageTransformer.h in Headers */,
|
||||
4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */,
|
||||
80377C3B1F2F666300F89830 /* quant_levels_dec_utils.h in Headers */,
|
||||
80377EB11F2F66D400F89830 /* vp8_dec.h in Headers */,
|
||||
|
@ -2473,6 +2515,7 @@
|
|||
431738BE1CDFC2660008FEB9 /* demux.h in Headers */,
|
||||
80377BFC1F2F665300F89830 /* bit_writer_utils.h in Headers */,
|
||||
32CF1C071FA496B000004BD1 /* SDWebImageCoderHelper.h in Headers */,
|
||||
32F7C0842030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
431738BF1CDFC2660008FEB9 /* encode.h in Headers */,
|
||||
53761316155AD0D5005750A4 /* SDImageCache.h in Headers */,
|
||||
323F8C0E1F38EF770092B609 /* muxi.h in Headers */,
|
||||
|
@ -2507,6 +2550,7 @@
|
|||
80377C0F1F2F665300F89830 /* thread_utils.h in Headers */,
|
||||
321E60BE1F38E91700405457 /* UIImage+ForceDecode.h in Headers */,
|
||||
5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */,
|
||||
32F7C06F2030114C00873181 /* SDWebImageTransformer.h in Headers */,
|
||||
324DF4B4200A14DC008A84CC /* SDWebImageDefine.h in Headers */,
|
||||
80377CE11F2F66A100F89830 /* common_sse2.h in Headers */,
|
||||
80377C0B1F2F665300F89830 /* random_utils.h in Headers */,
|
||||
|
@ -2796,6 +2840,7 @@
|
|||
80377DAE1F2F66A700F89830 /* argb_sse2.c in Sources */,
|
||||
323F8B7D1F38EF770092B609 /* frame_enc.c in Sources */,
|
||||
80377EBB1F2F66D500F89830 /* frame_dec.c in Sources */,
|
||||
32F7C0782030114C00873181 /* SDWebImageTransformer.m in Sources */,
|
||||
80377DAF1F2F66A700F89830 /* argb.c in Sources */,
|
||||
323F8B6B1F38EF770092B609 /* delta_palettization_enc.c in Sources */,
|
||||
00733A5B1BC4880000A5A117 /* NSData+ImageContentType.m in Sources */,
|
||||
|
@ -2828,6 +2873,7 @@
|
|||
80377DE31F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */,
|
||||
80377EBD1F2F66D500F89830 /* io_dec.c in Sources */,
|
||||
80377EBC1F2F66D500F89830 /* idec_dec.c in Sources */,
|
||||
32F7C0812030719600873181 /* UIImage+Transform.m in Sources */,
|
||||
323F8B991F38EF770092B609 /* near_lossless_enc.c in Sources */,
|
||||
80377DE81F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */,
|
||||
80377EC31F2F66D500F89830 /* vp8l_dec.c in Sources */,
|
||||
|
@ -3016,6 +3062,7 @@
|
|||
3237F9EC20161AE000A88143 /* NSImage+Additions.m in Sources */,
|
||||
4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */,
|
||||
80377D561F2F66A700F89830 /* rescaler_neon.c in Sources */,
|
||||
32F7C0762030114C00873181 /* SDWebImageTransformer.m in Sources */,
|
||||
80377D551F2F66A700F89830 /* rescaler_msa.c in Sources */,
|
||||
80377D5E1F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */,
|
||||
80377D611F2F66A700F89830 /* yuv.c in Sources */,
|
||||
|
@ -3056,6 +3103,7 @@
|
|||
4314D1551D0E0E3B004B36C9 /* UIImageView+HighlightedWebCache.m in Sources */,
|
||||
80377E991F2F66D400F89830 /* buffer_dec.c in Sources */,
|
||||
80377C201F2F666300F89830 /* quant_levels_dec_utils.c in Sources */,
|
||||
32F7C07F2030719600873181 /* UIImage+Transform.m in Sources */,
|
||||
80377D471F2F66A700F89830 /* lossless_enc_sse2.c in Sources */,
|
||||
80377C1E1F2F666300F89830 /* huffman_utils.c in Sources */,
|
||||
);
|
||||
|
@ -3164,6 +3212,7 @@
|
|||
3237F9EA20161AE000A88143 /* NSImage+Additions.m in Sources */,
|
||||
431BB6B61D06D2C1006A3455 /* UIImage+WebP.m in Sources */,
|
||||
80377E251F2F66A800F89830 /* rescaler_neon.c in Sources */,
|
||||
32F7C0792030114C00873181 /* SDWebImageTransformer.m in Sources */,
|
||||
80377E241F2F66A800F89830 /* rescaler_msa.c in Sources */,
|
||||
80377E2D1F2F66A800F89830 /* yuv_mips_dsp_r2.c in Sources */,
|
||||
431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */,
|
||||
|
@ -3204,6 +3253,7 @@
|
|||
80377C6E1F2F666400F89830 /* quant_levels_dec_utils.c in Sources */,
|
||||
80377EC91F2F66D500F89830 /* buffer_dec.c in Sources */,
|
||||
80377C6C1F2F666400F89830 /* huffman_utils.c in Sources */,
|
||||
32F7C0822030719600873181 /* UIImage+Transform.m in Sources */,
|
||||
80377E161F2F66A800F89830 /* lossless_enc_sse2.c in Sources */,
|
||||
431BB6C71D06D2C1006A3455 /* UIImageView+HighlightedWebCache.m in Sources */,
|
||||
);
|
||||
|
@ -3348,6 +3398,7 @@
|
|||
32C0FDEC2013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
|
||||
80377E5E1F2F66A800F89830 /* lossless_mips_dsp_r2.c in Sources */,
|
||||
80377E3D1F2F66A800F89830 /* cost_sse2.c in Sources */,
|
||||
32F7C0832030719600873181 /* UIImage+Transform.m in Sources */,
|
||||
321E60BB1F38E90100405457 /* SDWebImageWebPCoder.m in Sources */,
|
||||
80377E3C1F2F66A800F89830 /* cost_mips32.c in Sources */,
|
||||
80377E421F2F66A800F89830 /* dec_mips32.c in Sources */,
|
||||
|
@ -3355,6 +3406,7 @@
|
|||
323F8B851F38EF770092B609 /* histogram_enc.c in Sources */,
|
||||
80377EE51F2F66D500F89830 /* webp_dec.c in Sources */,
|
||||
4397D2B01D0DDD8C00BB2784 /* SDImageCache.m in Sources */,
|
||||
32F7C07A2030114C00873181 /* SDWebImageTransformer.m in Sources */,
|
||||
80377E4F1F2F66A800F89830 /* enc_sse41.c in Sources */,
|
||||
80377E701F2F66A800F89830 /* upsampling_sse2.c in Sources */,
|
||||
);
|
||||
|
@ -3395,6 +3447,7 @@
|
|||
80377D6A1F2F66A700F89830 /* argb.c in Sources */,
|
||||
323F8B7C1F38EF770092B609 /* frame_enc.c in Sources */,
|
||||
80377EAB1F2F66D400F89830 /* frame_dec.c in Sources */,
|
||||
32F7C0772030114C00873181 /* SDWebImageTransformer.m in Sources */,
|
||||
43C8929D1D9D6DD90022038D /* anim_decode.c in Sources */,
|
||||
323F8B6A1F38EF770092B609 /* delta_palettization_enc.c in Sources */,
|
||||
43CE75D41CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */,
|
||||
|
@ -3427,6 +3480,7 @@
|
|||
4A2CAE1E1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.m in Sources */,
|
||||
80377EAD1F2F66D400F89830 /* io_dec.c in Sources */,
|
||||
80377EAC1F2F66D400F89830 /* idec_dec.c in Sources */,
|
||||
32F7C0802030719600873181 /* UIImage+Transform.m in Sources */,
|
||||
323F8B981F38EF770092B609 /* near_lossless_enc.c in Sources */,
|
||||
80377D6F1F2F66A700F89830 /* cost.c in Sources */,
|
||||
80377EB31F2F66D400F89830 /* vp8l_dec.c in Sources */,
|
||||
|
@ -3547,6 +3601,7 @@
|
|||
323F8B7A1F38EF770092B609 /* frame_enc.c in Sources */,
|
||||
80377E8B1F2F66D000F89830 /* frame_dec.c in Sources */,
|
||||
43C8929A1D9D6DD70022038D /* anim_decode.c in Sources */,
|
||||
32F7C0752030114C00873181 /* SDWebImageTransformer.m in Sources */,
|
||||
323F8B681F38EF770092B609 /* delta_palettization_enc.c in Sources */,
|
||||
43CE75D31CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */,
|
||||
323F8B5C1F38EF770092B609 /* cost_enc.c in Sources */,
|
||||
|
@ -3579,6 +3634,7 @@
|
|||
80377E8D1F2F66D000F89830 /* io_dec.c in Sources */,
|
||||
80377E8C1F2F66D000F89830 /* idec_dec.c in Sources */,
|
||||
323F8B961F38EF770092B609 /* near_lossless_enc.c in Sources */,
|
||||
32F7C07E2030719600873181 /* UIImage+Transform.m in Sources */,
|
||||
80377CE51F2F66A100F89830 /* cost.c in Sources */,
|
||||
80377E931F2F66D000F89830 /* vp8l_dec.c in Sources */,
|
||||
321E609A1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */,
|
||||
|
|
|
@ -34,7 +34,12 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
|
|||
/**
|
||||
* By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously.
|
||||
*/
|
||||
SDImageCacheQueryDiskSync = 1 << 1
|
||||
SDImageCacheQueryDiskSync = 1 << 1,
|
||||
/**
|
||||
* We usually don't apply transform on animated images as most transformers could not manage animated images.
|
||||
* Use this flag to transform them anyway.
|
||||
*/
|
||||
SDImageCacheTransformAnimatedImage = 1 << 2,
|
||||
};
|
||||
|
||||
typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import "NSImage+Additions.h"
|
||||
#import "SDWebImageCodersManager.h"
|
||||
#import "SDWebImageTransformer.h"
|
||||
|
||||
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
#define UNLOCK(lock) dispatch_semaphore_signal(lock);
|
||||
|
@ -532,11 +533,18 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
diskImage = image;
|
||||
cacheType = SDImageCacheTypeMemory;
|
||||
} else if (diskData) {
|
||||
NSString *cacheKey = key;
|
||||
if ([context valueForKey:SDWebImageContextCustomTransformer]) {
|
||||
// grab the transformed disk image if transformer provided
|
||||
id<SDWebImageTransformer> transformer = [context valueForKey:SDWebImageContextCustomTransformer];
|
||||
NSString *transformerKey = [transformer transformerKey];
|
||||
cacheKey = SDTransformedKeyForKey(key, transformerKey);
|
||||
}
|
||||
// decode image data only if in-memory cache missed
|
||||
diskImage = [self diskImageForKey:key data:diskData];
|
||||
diskImage = [self diskImageForKey:cacheKey data:diskData];
|
||||
if (diskImage && self.config.shouldCacheImagesInMemory) {
|
||||
NSUInteger cost = SDCacheCostForImage(diskImage);
|
||||
[self.memCache setObject:diskImage forKey:key cost:cost];
|
||||
[self.memCache setObject:diskImage forKey:cacheKey cost:cost];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
#ifndef UIView
|
||||
#define UIView NSView
|
||||
#endif
|
||||
#ifndef UIColor
|
||||
#define UIColor NSColor
|
||||
#endif
|
||||
#else
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
|
||||
#error SDWebImage doesn't support Deployment Target version < 5.0
|
||||
|
|
|
@ -20,3 +20,8 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetIma
|
|||
A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager)
|
||||
*/
|
||||
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomManager;
|
||||
|
||||
/**
|
||||
A id<SDWebImageTransformer> instance which conforms SDWebImageTransformer protocol. It's used for image transform after the image load finished and store the transformed image to cache. If you provide one, it will ignore the `transformer` in manager and use provided one instead. (id<SDWebImageTransformer>)
|
||||
*/
|
||||
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextCustomTransformer;
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
|
||||
SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup";
|
||||
SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager";
|
||||
SDWebImageContextOption const SDWebImageContextCustomTransformer = @"customTransformer";
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#import "SDWebImageOperation.h"
|
||||
#import "SDWebImageDownloader.h"
|
||||
#import "SDImageCache.h"
|
||||
#import "SDWebImageTransformer.h"
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
|
||||
/**
|
||||
|
@ -76,8 +77,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
|
|||
SDWebImageDelayPlaceholder = 1 << 9,
|
||||
|
||||
/**
|
||||
* We usually don't call transformDownloadedImage delegate method on animated images,
|
||||
* as most transformation code would mangle it.
|
||||
* We usually don't apply transform on animated images as most transformers could not manage animated images.
|
||||
* Use this flag to transform them anyway.
|
||||
*/
|
||||
SDWebImageTransformAnimatedImage = 1 << 10,
|
||||
|
@ -115,7 +115,7 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
|
|||
/**
|
||||
* By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well.
|
||||
*/
|
||||
SDWebImageForceTransition = 1 << 16
|
||||
SDWebImageForceTransition = 1 << 16,
|
||||
};
|
||||
|
||||
typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL);
|
||||
|
@ -141,7 +141,7 @@ typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull i
|
|||
*
|
||||
* @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
|
||||
*/
|
||||
- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nullable NSURL *)imageURL;
|
||||
- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nonnull NSURL *)imageURL;
|
||||
|
||||
/**
|
||||
* Controls the complicated logic to mark as failed URLs when download error occur.
|
||||
|
@ -153,18 +153,6 @@ typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull i
|
|||
*/
|
||||
- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldBlockFailedURL:(nonnull NSURL *)imageURL withError:(nonnull NSError *)error;
|
||||
|
||||
/**
|
||||
* Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
|
||||
* NOTE: This method is called from a global queue in order to not to block the main thread.
|
||||
*
|
||||
* @param imageManager The current `SDWebImageManager`
|
||||
* @param image The image to transform
|
||||
* @param imageURL The url of the image to transform
|
||||
*
|
||||
* @return The transformed image object.
|
||||
*/
|
||||
- (nullable UIImage *)imageManager:(nonnull SDWebImageManager *)imageManager transformDownloadedImage:(nullable UIImage *)image withURL:(nullable NSURL *)imageURL;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
@ -196,6 +184,13 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
|
|||
@property (strong, nonatomic, readonly, nullable) SDImageCache *imageCache;
|
||||
@property (strong, nonatomic, readonly, nullable) SDWebImageDownloader *imageDownloader;
|
||||
|
||||
/**
|
||||
The image transformer for manager. It's used for image transform after the image load finished and store the transformed image to cache, see `SDWebImageTransformer`.
|
||||
Defaults to nil, which means no transform is applied.
|
||||
@note This will affect all the load requests for this manager if you provide. However, you can pass `SDWebImageContextCustomTransformer` in context arg to explicitly use that transformer instead.
|
||||
*/
|
||||
@property (strong, nonatomic, nullable) id<SDWebImageTransformer> transformer;
|
||||
|
||||
/**
|
||||
* The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can
|
||||
* be used to remove dynamic part of an image URL.
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#import "SDWebImageManager.h"
|
||||
#import "NSImage+Additions.h"
|
||||
#import <objc/message.h>
|
||||
|
||||
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
|
||||
|
||||
|
@ -153,6 +152,19 @@
|
|||
SDImageCacheOptions cacheOptions = 0;
|
||||
if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory;
|
||||
if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync;
|
||||
if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage;
|
||||
|
||||
// Image transformer
|
||||
id<SDWebImageTransformer> transformer;
|
||||
if ([context valueForKey:SDWebImageContextCustomTransformer]) {
|
||||
transformer = [context valueForKey:SDWebImageContextCustomTransformer];
|
||||
} else if (self.transformer) {
|
||||
// Transformer from manager
|
||||
transformer = self.transformer;
|
||||
NSMutableDictionary<SDWebImageContextOption, id> *mutableContext = [NSMutableDictionary dictionaryWithDictionary:context];
|
||||
[mutableContext setValue:transformer forKey:SDWebImageContextCustomTransformer];
|
||||
context = [mutableContext copy];
|
||||
}
|
||||
|
||||
__weak SDWebImageCombinedOperation *weakOperation = operation;
|
||||
operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) {
|
||||
|
@ -238,11 +250,12 @@
|
|||
|
||||
if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) {
|
||||
// Image refresh hit the NSURLCache cache, do not call the completion block
|
||||
} else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
|
||||
} else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && transformer) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
|
||||
|
||||
UIImage *transformedImage = [transformer transformedImageWithImage:downloadedImage forKey:key];
|
||||
if (transformedImage && finished) {
|
||||
NSString *transformerKey = [transformer transformerKey];
|
||||
NSString *cacheKey = SDTransformedKeyForKey(key, transformerKey);
|
||||
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
|
||||
NSData *cacheData;
|
||||
// pass nil if the image was transformed, so we can recalculate the data from the image
|
||||
|
@ -251,7 +264,7 @@
|
|||
} else {
|
||||
cacheData = (imageWasTransformed ? nil : downloadedData);
|
||||
}
|
||||
[self.imageCache storeImage:transformedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil];
|
||||
[self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey toDisk:cacheOnDisk completion:nil];
|
||||
}
|
||||
|
||||
[self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
#import "UIImage+Transform.h"
|
||||
|
||||
/**
|
||||
Return the transformed cache key which applied with specify transformerKey.
|
||||
|
||||
@param key The original cache key
|
||||
@param transformerKey The transformer key from the transformer
|
||||
@return The transformed cache key
|
||||
*/
|
||||
FOUNDATION_EXPORT NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * _Nonnull transformerKey);
|
||||
|
||||
/**
|
||||
A transformer protocol to transform the image load from cache or from download.
|
||||
You can provide transformer to cache and manager (Through the `transformer` property or context option `SDWebImageContextCustomTransformer`).
|
||||
|
||||
@note The transform process is called from a global queue in order to not to block the main queue.
|
||||
*/
|
||||
@protocol SDWebImageTransformer <NSObject>
|
||||
|
||||
@required
|
||||
/**
|
||||
For each transformer, it must contains its cache key to used to store the image cache or query from the cache. This key will be appened after the original cache key generated by URL or from user.
|
||||
|
||||
@return The cache key to appended after the original cache key. Should not be nil.
|
||||
*/
|
||||
- (nonnull NSString *)transformerKey;
|
||||
|
||||
/**
|
||||
Transform the image to another image.
|
||||
|
||||
@param image The image to be transformed
|
||||
@param key The cache key associated to the image
|
||||
@return The transformed image, or nil if transform failed
|
||||
*/
|
||||
- (nullable UIImage *)transformedImageWithImage:(nonnull UIImage *)image forKey:(nonnull NSString *)key;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Pipeline
|
||||
|
||||
// Pipeline transformer. Which you can bind multiple transformers together to let the image to be transformed one by one in order and generate the final image.
|
||||
// Because transformers are lightweight, if you want to append or arrange transfomers, create another pipeline transformer instead. This class is considered as immutable.
|
||||
@interface SDWebImagePipelineTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, copy, readonly, nonnull) NSArray<id<SDWebImageTransformer>> *transformers;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithTransformers:(nonnull NSArray<id<SDWebImageTransformer>> *)transformers;
|
||||
|
||||
@end
|
||||
|
||||
// There are some built-in transformers based on the `UIImage+Transformer` category to provide the common image geometry, image blending and image effect process. Those transform are useful for static image only but you can create your own to support animated image as well.
|
||||
// Because transformers are lightweight, these class are considered as immutable.
|
||||
#pragma mark - Image Geometry
|
||||
|
||||
// Image round corner transformer
|
||||
@interface SDWebImageRoundCornerTransformer: NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, assign, readonly) CGFloat cornerRadius;
|
||||
@property (nonatomic, assign, readonly) SDRectCorner corners;
|
||||
@property (nonatomic, assign, readonly) CGFloat borderWidth;
|
||||
@property (nonatomic, strong, readonly, nullable) UIColor *borderColor;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(nullable UIColor *)borderColor;
|
||||
|
||||
@end
|
||||
|
||||
// Image resizing transformer
|
||||
@interface SDWebImageResizingTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, assign, readonly) CGSize size;
|
||||
@property (nonatomic, assign, readonly) SDImageScaleMode scaleMode;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode;
|
||||
|
||||
@end
|
||||
|
||||
// Image cropping transformer
|
||||
@interface SDWebImageCroppingTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, assign, readonly) CGRect rect;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithRect:(CGRect)rect;
|
||||
|
||||
@end
|
||||
|
||||
// Image flipping transformer
|
||||
@interface SDWebImageFlippingTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, assign, readonly) BOOL horizontal;
|
||||
@property (nonatomic, assign, readonly) BOOL vertical;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical;
|
||||
|
||||
@end
|
||||
|
||||
// Image rotation transformer
|
||||
@interface SDWebImageRotationTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, assign, readonly) CGFloat angle;
|
||||
@property (nonatomic, assign, readonly) BOOL fitSize;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Image Blending
|
||||
|
||||
// Image tint color transformer
|
||||
@interface SDWebImageTintTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, strong, readonly, nonnull) UIColor *tintColor;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithColor:(nonnull UIColor *)tintColor;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Image Effect
|
||||
|
||||
// Image blur effect transformer
|
||||
@interface SDWebImageBlurTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, assign, readonly) CGFloat blurRadius;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithRadius:(CGFloat)blurRadius;
|
||||
|
||||
@end
|
||||
|
||||
#if SD_UIKIT || SD_MAC
|
||||
// Core Image filter transformer
|
||||
@interface SDWebImageFilterTransformer: NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, strong, readonly, nonnull) CIFilter *filter;
|
||||
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
+ (nonnull instancetype)transformerWithFilter:(nonnull CIFilter *)filter;
|
||||
|
||||
@end
|
||||
#endif
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageTransformer.h"
|
||||
#if SD_UIKIT || SD_MAC
|
||||
#import <CoreImage/CoreImage.h>
|
||||
#endif
|
||||
|
||||
// Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDWebImageFlippingTransformer(1,0)-SDWebImageRotationTransformer(0.78539816339,1).png'
|
||||
static NSString * const SDWebImageTransformerKeySeparator = @"-";
|
||||
|
||||
NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * _Nonnull transformerKey) {
|
||||
if (!key || !transformerKey) {
|
||||
return nil;
|
||||
}
|
||||
return [[key stringByAppendingString:SDWebImageTransformerKeySeparator] stringByAppendingString:transformerKey];
|
||||
}
|
||||
|
||||
@interface UIColor (HexString)
|
||||
|
||||
/**
|
||||
Convenience way to get hex string from color. The output should always be 32-bit RGBA hex string like `#00000000`.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIColor (HexString)
|
||||
|
||||
- (NSString *)sd_hexString {
|
||||
CGFloat red, green, blue, alpha;
|
||||
#if SD_UIKIT
|
||||
if (![self getRed:&red green:&green blue:&blue alpha:&alpha]) {
|
||||
[self getWhite:&red alpha:&alpha];
|
||||
green = red;
|
||||
blue = red;
|
||||
}
|
||||
#else
|
||||
@try {
|
||||
[self getRed:&red green:&green blue:&blue alpha:&alpha];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[self getWhite:&red alpha:&alpha];
|
||||
green = red;
|
||||
blue = red;
|
||||
}
|
||||
#endif
|
||||
|
||||
red = roundf(red * 255.f);
|
||||
green = roundf(green * 255.f);
|
||||
blue = roundf(blue * 255.f);
|
||||
alpha = roundf(alpha * 255.f);
|
||||
|
||||
uint hex = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)green << 8) | ((uint)blue);
|
||||
|
||||
return [NSString stringWithFormat:@"#%08x", hex];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface SDWebImagePipelineTransformer ()
|
||||
|
||||
@property (nonatomic, copy, readwrite, nonnull) NSArray<id<SDWebImageTransformer>> *transformers;
|
||||
@property (nonatomic, copy, readwrite) NSString *transformerKey;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImagePipelineTransformer
|
||||
|
||||
+ (instancetype)transformerWithTransformers:(NSArray<id<SDWebImageTransformer>> *)transformers {
|
||||
SDWebImagePipelineTransformer *transformer = [SDWebImagePipelineTransformer new];
|
||||
transformer.transformers = transformers;
|
||||
transformer.transformerKey = [[self class] cacheKeyForTransformers:transformers];
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
+ (NSString *)cacheKeyForTransformers:(NSArray<id<SDWebImageTransformer>> *)transformers {
|
||||
if (transformers.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSMutableArray<NSString *> *cacheKeys = [NSMutableArray arrayWithCapacity:transformers.count];
|
||||
[transformers enumerateObjectsUsingBlock:^(id<SDWebImageTransformer> _Nonnull transformer, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
NSString *cacheKey = transformer.transformerKey;
|
||||
[cacheKeys addObject:cacheKey];
|
||||
}];
|
||||
|
||||
return [cacheKeys componentsJoinedByString:SDWebImageTransformerKeySeparator];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
UIImage *transformedImage = image;
|
||||
for (id<SDWebImageTransformer> transformer in self.transformers) {
|
||||
transformedImage = [transformer transformedImageWithImage:transformedImage forKey:key];
|
||||
}
|
||||
return transformedImage;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface SDWebImageRoundCornerTransformer ()
|
||||
|
||||
@property (nonatomic, assign) CGFloat cornerRadius;
|
||||
@property (nonatomic, assign) SDRectCorner corners;
|
||||
@property (nonatomic, assign) CGFloat borderWidth;
|
||||
@property (nonatomic, strong, nullable) UIColor *borderColor;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageRoundCornerTransformer
|
||||
|
||||
+ (instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor {
|
||||
SDWebImageRoundCornerTransformer *transformer = [SDWebImageRoundCornerTransformer new];
|
||||
transformer.cornerRadius = cornerRadius;
|
||||
transformer.corners = corners;
|
||||
transformer.borderWidth = borderWidth;
|
||||
transformer.borderColor = borderColor;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
return [NSString stringWithFormat:@"SDWebImageRoundCornerTransformer(%f,%lu,%f,%@)", self.cornerRadius, (unsigned long)self.corners, self.borderWidth, self.borderColor.sd_hexString];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_roundedCornerImageWithRadius:self.cornerRadius corners:self.corners borderWidth:self.borderWidth borderColor:self.borderColor];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface SDWebImageResizingTransformer ()
|
||||
|
||||
@property (nonatomic, assign) CGSize size;
|
||||
@property (nonatomic, assign) SDImageScaleMode scaleMode;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageResizingTransformer
|
||||
|
||||
+ (instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode {
|
||||
SDWebImageResizingTransformer *transformer = [SDWebImageResizingTransformer new];
|
||||
transformer.size = size;
|
||||
transformer.scaleMode = scaleMode;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
CGSize size = self.size;
|
||||
return [NSString stringWithFormat:@"SDWebImageResizingTransformer({%f,%f},%lu)", size.width, size.height, (unsigned long)self.scaleMode];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_resizedImageWithSize:self.size scaleMode:self.scaleMode];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface SDWebImageCroppingTransformer ()
|
||||
|
||||
@property (nonatomic, assign) CGRect rect;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageCroppingTransformer
|
||||
|
||||
+ (instancetype)transformerWithRect:(CGRect)rect {
|
||||
SDWebImageCroppingTransformer *transformer = [SDWebImageCroppingTransformer new];
|
||||
transformer.rect = rect;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
CGRect rect = self.rect;
|
||||
return [NSString stringWithFormat:@"SDWebImageCroppingTransformer({%f,%f,%f,%f})", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_croppedImageWithRect:self.rect];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface SDWebImageFlippingTransformer ()
|
||||
|
||||
@property (nonatomic, assign) BOOL horizontal;
|
||||
@property (nonatomic, assign) BOOL vertical;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageFlippingTransformer
|
||||
|
||||
+ (instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical {
|
||||
SDWebImageFlippingTransformer *transformer = [SDWebImageFlippingTransformer new];
|
||||
transformer.horizontal = horizontal;
|
||||
transformer.vertical = vertical;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
return [NSString stringWithFormat:@"SDWebImageFlippingTransformer(%d,%d)", self.horizontal, self.vertical];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_flippedImageWithHorizontal:self.horizontal vertical:self.vertical];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface SDWebImageRotationTransformer ()
|
||||
|
||||
@property (nonatomic, assign) CGFloat angle;
|
||||
@property (nonatomic, assign) BOOL fitSize;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageRotationTransformer
|
||||
|
||||
+ (instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize {
|
||||
SDWebImageRotationTransformer *transformer = [SDWebImageRotationTransformer new];
|
||||
transformer.angle = angle;
|
||||
transformer.fitSize = fitSize;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
return [NSString stringWithFormat:@"SDWebImageRotationTransformer(%f,%d)", self.angle, self.fitSize];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_rotatedImageWithAngle:self.angle fitSize:self.fitSize];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Image Blending
|
||||
|
||||
@interface SDWebImageTintTransformer ()
|
||||
|
||||
@property (nonatomic, strong, nonnull) UIColor *tintColor;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageTintTransformer
|
||||
|
||||
+ (instancetype)transformerWithColor:(UIColor *)tintColor {
|
||||
SDWebImageTintTransformer *transformer = [SDWebImageTintTransformer new];
|
||||
transformer.tintColor = tintColor;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
return [NSString stringWithFormat:@"SDWebImageTintTransformer(%@)", self.tintColor.sd_hexString];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_tintedImageWithColor:self.tintColor];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Image Effect
|
||||
|
||||
@interface SDWebImageBlurTransformer ()
|
||||
|
||||
@property (nonatomic, assign) CGFloat blurRadius;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageBlurTransformer
|
||||
|
||||
+ (instancetype)transformerWithRadius:(CGFloat)blurRadius {
|
||||
SDWebImageBlurTransformer *transformer = [SDWebImageBlurTransformer new];
|
||||
transformer.blurRadius = blurRadius;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
return [NSString stringWithFormat:@"SDWebImageBlurTransformer(%f)", self.blurRadius];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_blurredImageWithRadius:self.blurRadius];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#if SD_UIKIT || SD_MAC
|
||||
@interface SDWebImageFilterTransformer ()
|
||||
|
||||
@property (nonatomic, strong, nonnull) CIFilter *filter;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageFilterTransformer
|
||||
|
||||
+ (instancetype)transformerWithFilter:(CIFilter *)filter {
|
||||
SDWebImageFilterTransformer *transformer = [SDWebImageFilterTransformer new];
|
||||
transformer.filter = filter;
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
return [NSString stringWithFormat:@"SDWebImageFilterTransformer(%@)", self.filter.name];
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
return [image sd_filteredImageWithFilter:self.filter];
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SDImageScaleMode) {
|
||||
SDImageScaleModeFill = 0,
|
||||
SDImageScaleModeAspectFit = 1,
|
||||
SDImageScaleModeAspectFill = 2
|
||||
};
|
||||
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
typedef UIRectCorner SDRectCorner;
|
||||
#else
|
||||
typedef NS_OPTIONS(NSUInteger, SDRectCorner) {
|
||||
SDRectCornerTopLeft = 1 << 0,
|
||||
SDRectCornerTopRight = 1 << 1,
|
||||
SDRectCornerBottomLeft = 1 << 2,
|
||||
SDRectCornerBottomRight = 1 << 3,
|
||||
SDRectCornerAllCorners = ~0UL
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
Provide some commen method for `UIImage`.
|
||||
Image process is based on Core Graphics and vImage.
|
||||
*/
|
||||
@interface UIImage (Transform)
|
||||
|
||||
#pragma mark - Image Geometry
|
||||
|
||||
/**
|
||||
Returns a new image which is resized from this image.
|
||||
You can specify a larger or smaller size than the image size. The image content will be changed with the scale mode.
|
||||
|
||||
@param size The new size to be resized, values should be positive.
|
||||
@param scaleMode The scale mode for image content.
|
||||
@return The new image with the given size.
|
||||
*/
|
||||
- (nullable UIImage *)sd_resizedImageWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode;
|
||||
|
||||
/**
|
||||
Returns a new image which is cropped from this image.
|
||||
|
||||
@param rect Image's inner rect.
|
||||
@return The new image with the cropping rect.
|
||||
*/
|
||||
- (nullable UIImage *)sd_croppedImageWithRect:(CGRect)rect;
|
||||
|
||||
/**
|
||||
Rounds a new image with a given corner radius and corners.
|
||||
|
||||
@param cornerRadius The radius of each corner oval. Values larger than half the
|
||||
rectangle's width or height are clamped appropriately to
|
||||
half the width or height.
|
||||
@param corners A bitmask value that identifies the corners that you want
|
||||
rounded. You can use this parameter to round only a subset
|
||||
of the corners of the rectangle.
|
||||
@param borderWidth The inset border line width. Values larger than half the rectangle's
|
||||
width or height are clamped appropriately to half the width
|
||||
or height.
|
||||
@param borderColor The border stroke color. nil means clear color.
|
||||
@return The new image with the round corner.
|
||||
*/
|
||||
- (nullable UIImage *)sd_roundedCornerImageWithRadius:(CGFloat)cornerRadius
|
||||
corners:(SDRectCorner)corners
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
borderColor:(nullable UIColor *)borderColor;
|
||||
|
||||
/**
|
||||
Returns a new rotated image (relative to the center).
|
||||
|
||||
@param angle Rotated radians in counterclockwise.⟲
|
||||
@param fitSize YES: new image's size is extend to fit all content.
|
||||
NO: image's size will not change, content may be clipped.
|
||||
@return The new image with the rotation.
|
||||
*/
|
||||
- (nullable UIImage *)sd_rotatedImageWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize;
|
||||
|
||||
/**
|
||||
Returns a new horizontally(vertically) flipped image.
|
||||
|
||||
@param horizontal YES to flip the image horizontally. ⇋
|
||||
@param vertical YES to flip the image vertically. ⥯
|
||||
@return The new image with the flipping.
|
||||
*/
|
||||
- (nullable UIImage *)sd_flippedImageWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical;
|
||||
|
||||
#pragma mark - Image Blending
|
||||
|
||||
/**
|
||||
Return a tinted image with the given color. This actually use alpha blending of current image and the tint color.
|
||||
|
||||
@param tintColor The tint color.
|
||||
@return The new image with the tint color.
|
||||
*/
|
||||
- (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor;
|
||||
|
||||
/**
|
||||
Return the pixel color at specify position. The point is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based.
|
||||
@note The point's x/y should not be smaller than 0, or greater than or equal to width/height.
|
||||
@note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself.
|
||||
|
||||
@param point The position of pixel
|
||||
@return The color for specify pixel, or nil if any error occur
|
||||
*/
|
||||
- (nullable UIColor *)sd_colorAtPoint:(CGPoint)point;
|
||||
|
||||
/**
|
||||
Return the pixel color array with specify rectangle. The rect is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based.
|
||||
@note The rect's width/height should not be smaller than or equal to 0. The minX/minY should not be smaller than 0. The maxX/maxY should not be greater than width/height. Attention this limit is different from `sd_colorAtPoint:` (point: (0, 0) like rect: (0, 0, 1, 1))
|
||||
@note The overhead of object creation means this method is best suited for infrequent color sampling. For heavy image processing, grab the raw bitmap data and process yourself.
|
||||
|
||||
@param rect The rectangle of pixels
|
||||
@return The color array for specify pixels, or nil if any error occur
|
||||
*/
|
||||
- (nullable NSArray<UIColor *> *)sd_colorsWithRect:(CGRect)rect;
|
||||
|
||||
#pragma mark - Image Effect
|
||||
|
||||
/**
|
||||
Return a new image applied a blur effect.
|
||||
|
||||
@param blurRadius The radius of the blur in points, 0 means no blur effect.
|
||||
|
||||
@return The new image with blur effect, or nil if an error occurs (e.g. no enough memory).
|
||||
*/
|
||||
- (nullable UIImage *)sd_blurredImageWithRadius:(CGFloat)blurRadius;
|
||||
|
||||
#if SD_UIKIT || SD_MAC
|
||||
/**
|
||||
Return a new image applied a CIFilter.
|
||||
|
||||
@param filter The CIFilter to be applied to the image.
|
||||
@return The new image with the CIFilter, or nil if an error occurs (e.g. no
|
||||
enough memory).
|
||||
*/
|
||||
- (nullable UIImage *)sd_filteredImageWithFilter:(nonnull CIFilter *)filter;
|
||||
#endif
|
||||
|
||||
@end
|
|
@ -0,0 +1,687 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "UIImage+Transform.h"
|
||||
#import "NSImage+Additions.h"
|
||||
#import <Accelerate/Accelerate.h>
|
||||
#if SD_UIKIT || SD_MAC
|
||||
#import <CoreImage/CoreImage.h>
|
||||
#endif
|
||||
|
||||
#if SD_MAC
|
||||
static CGContextRef SDCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGFloat scale) {
|
||||
size_t width = ceil(size.width * scale);
|
||||
size_t height = ceil(size.height * scale);
|
||||
if (width < 1 || height < 1) return NULL;
|
||||
|
||||
//pre-multiplied ARGB, 8-bits per component
|
||||
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
|
||||
CGImageAlphaInfo alphaInfo = (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst);
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo);
|
||||
CGColorSpaceRelease(space);
|
||||
return context;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
|
||||
#else
|
||||
CGContextRef context = SDCGContextCreateARGBBitmapContext(size, opaque, scale);
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO];
|
||||
CGContextRelease(context);
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
NSGraphicsContext.currentContext = graphicsContext;
|
||||
#endif
|
||||
}
|
||||
|
||||
static CGContextRef SDGraphicsGetCurrentContext(void) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
return UIGraphicsGetCurrentContext();
|
||||
#else
|
||||
return NSGraphicsContext.currentContext.CGContext;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SDGraphicsEndImageContext(void) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIGraphicsEndImageContext();
|
||||
#else
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
#endif
|
||||
}
|
||||
|
||||
static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
return UIGraphicsGetImageFromCurrentImageContext();
|
||||
#else
|
||||
CGContextRef context = SDGraphicsGetCurrentContext();
|
||||
if (!context) {
|
||||
return nil;
|
||||
}
|
||||
CGImageRef imageRef = CGBitmapContextCreateImage(context);
|
||||
if (!imageRef) {
|
||||
return nil;
|
||||
}
|
||||
NSImage *image = [[NSImage alloc] initWithCGImage:imageRef size:NSZeroSize];
|
||||
CGImageRelease(imageRef);
|
||||
return image;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline CGRect SDCGRectFitWithScaleMode(CGRect rect, CGSize size, SDImageScaleMode scaleMode) {
|
||||
rect = CGRectStandardize(rect);
|
||||
size.width = size.width < 0 ? -size.width : size.width;
|
||||
size.height = size.height < 0 ? -size.height : size.height;
|
||||
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
|
||||
switch (scaleMode) {
|
||||
case SDImageScaleModeAspectFit:
|
||||
case SDImageScaleModeAspectFill: {
|
||||
if (rect.size.width < 0.01 || rect.size.height < 0.01 ||
|
||||
size.width < 0.01 || size.height < 0.01) {
|
||||
rect.origin = center;
|
||||
rect.size = CGSizeZero;
|
||||
} else {
|
||||
CGFloat scale;
|
||||
if (scaleMode == SDImageScaleModeAspectFit) {
|
||||
if (size.width / size.height < rect.size.width / rect.size.height) {
|
||||
scale = rect.size.height / size.height;
|
||||
} else {
|
||||
scale = rect.size.width / size.width;
|
||||
}
|
||||
} else {
|
||||
if (size.width / size.height < rect.size.width / rect.size.height) {
|
||||
scale = rect.size.width / size.width;
|
||||
} else {
|
||||
scale = rect.size.height / size.height;
|
||||
}
|
||||
}
|
||||
size.width *= scale;
|
||||
size.height *= scale;
|
||||
rect.size = size;
|
||||
rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5);
|
||||
}
|
||||
} break;
|
||||
case SDImageScaleModeFill:
|
||||
default: {
|
||||
rect = rect;
|
||||
}
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitmapInfo) {
|
||||
// Get alpha info, byteOrder info
|
||||
CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask;
|
||||
CGImageByteOrderInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask;
|
||||
CGFloat r = 0, g = 0, b = 0, a = 255.0;
|
||||
|
||||
BOOL byteOrderNormal = NO;
|
||||
switch (byteOrderInfo) {
|
||||
case kCGBitmapByteOrderDefault: {
|
||||
byteOrderNormal = YES;
|
||||
} break;
|
||||
case kCGBitmapByteOrder32Little: {
|
||||
} break;
|
||||
case kCGBitmapByteOrder32Big: {
|
||||
byteOrderNormal = YES;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
switch (alphaInfo) {
|
||||
case kCGImageAlphaPremultipliedFirst:
|
||||
case kCGImageAlphaFirst: {
|
||||
if (byteOrderNormal) {
|
||||
// ARGB8888
|
||||
a = pixel[0] / 255.0;
|
||||
r = pixel[1] / 255.0;
|
||||
g = pixel[2] / 255.0;
|
||||
b = pixel[3] / 255.0;
|
||||
} else {
|
||||
// BGRA8888
|
||||
b = pixel[0] / 255.0;
|
||||
g = pixel[1] / 255.0;
|
||||
r = pixel[2] / 255.0;
|
||||
a = pixel[3] / 255.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCGImageAlphaPremultipliedLast:
|
||||
case kCGImageAlphaLast: {
|
||||
if (byteOrderNormal) {
|
||||
// RGBA8888
|
||||
r = pixel[0] / 255.0;
|
||||
g = pixel[1] / 255.0;
|
||||
b = pixel[2] / 255.0;
|
||||
a = pixel[3] / 255.0;
|
||||
} else {
|
||||
// ABGR8888
|
||||
a = pixel[0] / 255.0;
|
||||
b = pixel[1] / 255.0;
|
||||
g = pixel[2] / 255.0;
|
||||
r = pixel[3] / 255.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCGImageAlphaNone: {
|
||||
if (byteOrderNormal) {
|
||||
// RGB
|
||||
r = pixel[0] / 255.0;
|
||||
g = pixel[1] / 255.0;
|
||||
b = pixel[2] / 255.0;
|
||||
} else {
|
||||
// BGR
|
||||
b = pixel[0] / 255.0;
|
||||
g = pixel[1] / 255.0;
|
||||
r = pixel[2] / 255.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCGImageAlphaNoneSkipLast: {
|
||||
if (byteOrderNormal) {
|
||||
// RGBX
|
||||
r = pixel[0] / 255.0;
|
||||
g = pixel[1] / 255.0;
|
||||
b = pixel[2] / 255.0;
|
||||
} else {
|
||||
// XBGR
|
||||
b = pixel[1] / 255.0;
|
||||
g = pixel[2] / 255.0;
|
||||
r = pixel[3] / 255.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCGImageAlphaNoneSkipFirst: {
|
||||
if (byteOrderNormal) {
|
||||
// XRGB
|
||||
r = pixel[1] / 255.0;
|
||||
g = pixel[2] / 255.0;
|
||||
b = pixel[3] / 255.0;
|
||||
} else {
|
||||
// BGRX
|
||||
b = pixel[0] / 255.0;
|
||||
g = pixel[1] / 255.0;
|
||||
r = pixel[2] / 255.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCGImageAlphaOnly:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return [UIColor colorWithRed:r green:g blue:b alpha:a];
|
||||
}
|
||||
|
||||
#if SD_MAC
|
||||
@interface NSBezierPath (RoundedCorners)
|
||||
|
||||
/**
|
||||
Convenience way to create a bezier path with the specify rounding corners on macOS. Same as the one on `UIBezierPath`.
|
||||
*/
|
||||
+ (nonnull instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSBezierPath (RoundedCorners)
|
||||
|
||||
+ (instancetype)sd_bezierPathWithRoundedRect:(NSRect)rect byRoundingCorners:(SDRectCorner)corners cornerRadius:(CGFloat)cornerRadius {
|
||||
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||
|
||||
CGFloat maxCorner = MIN(NSWidth(rect), NSHeight(rect)) / 2;
|
||||
|
||||
CGFloat topLeftRadius = MIN(maxCorner, (corners & SDRectCornerTopLeft) ? cornerRadius : 0);
|
||||
CGFloat topRightRadius = MIN(maxCorner, (corners & SDRectCornerTopRight) ? cornerRadius : 0);
|
||||
CGFloat bottomLeftRadius = MIN(maxCorner, (corners & SDRectCornerBottomLeft) ? cornerRadius : 0);
|
||||
CGFloat bottomRightRadius = MIN(maxCorner, (corners & SDRectCornerBottomRight) ? cornerRadius : 0);
|
||||
|
||||
NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
|
||||
NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
|
||||
NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect));
|
||||
NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect));
|
||||
|
||||
[path moveToPoint:NSMakePoint(NSMidX(rect), NSMaxY(rect))];
|
||||
[path appendBezierPathWithArcFromPoint:topLeft toPoint:bottomLeft radius:topLeftRadius];
|
||||
[path appendBezierPathWithArcFromPoint:bottomLeft toPoint:bottomRight radius:bottomLeftRadius];
|
||||
[path appendBezierPathWithArcFromPoint:bottomRight toPoint:topRight radius:bottomRightRadius];
|
||||
[path appendBezierPathWithArcFromPoint:topRight toPoint:topLeft radius:topRightRadius];
|
||||
[path closePath];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
||||
@implementation UIImage (Transform)
|
||||
|
||||
- (void)sd_drawInRect:(CGRect)rect withScaleMode:(SDImageScaleMode)scaleMode clipsToBounds:(BOOL)clips {
|
||||
CGRect drawRect = SDCGRectFitWithScaleMode(rect, self.size, scaleMode);
|
||||
if (drawRect.size.width == 0 || drawRect.size.height == 0) return;
|
||||
if (clips) {
|
||||
CGContextRef context = SDGraphicsGetCurrentContext();
|
||||
if (context) {
|
||||
CGContextSaveGState(context);
|
||||
CGContextAddRect(context, rect);
|
||||
CGContextClip(context);
|
||||
[self drawInRect:drawRect];
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
} else {
|
||||
[self drawInRect:drawRect];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)sd_resizedImageWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode {
|
||||
if (size.width <= 0 || size.height <= 0) return nil;
|
||||
SDGraphicsBeginImageContextWithOptions(size, NO, self.scale);
|
||||
[self sd_drawInRect:CGRectMake(0, 0, size.width, size.height) withScaleMode:scaleMode clipsToBounds:NO];
|
||||
UIImage *image = SDGraphicsGetImageFromCurrentImageContext();
|
||||
SDGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)sd_croppedImageWithRect:(CGRect)rect {
|
||||
if (!self.CGImage) return nil;
|
||||
rect.origin.x *= self.scale;
|
||||
rect.origin.y *= self.scale;
|
||||
rect.size.width *= self.scale;
|
||||
rect.size.height *= self.scale;
|
||||
if (rect.size.width <= 0 || rect.size.height <= 0) return nil;
|
||||
CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
|
||||
if (!imageRef) {
|
||||
return nil;
|
||||
}
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
|
||||
#else
|
||||
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale];
|
||||
#endif
|
||||
CGImageRelease(imageRef);
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)sd_roundedCornerImageWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor {
|
||||
if (!self.CGImage) return nil;
|
||||
SDGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
|
||||
CGContextRef context = SDGraphicsGetCurrentContext();
|
||||
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
|
||||
|
||||
CGFloat minSize = MIN(self.size.width, self.size.height);
|
||||
if (borderWidth < minSize / 2) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(cornerRadius, cornerRadius)];
|
||||
#else
|
||||
NSBezierPath *path = [NSBezierPath sd_bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadius:cornerRadius];
|
||||
#endif
|
||||
[path closePath];
|
||||
|
||||
CGContextSaveGState(context);
|
||||
[path addClip];
|
||||
CGContextDrawImage(context, rect, self.CGImage);
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
if (borderColor && borderWidth < minSize / 2 && borderWidth > 0) {
|
||||
CGFloat strokeInset = (floor(borderWidth * self.scale) + 0.5) / self.scale;
|
||||
CGRect strokeRect = CGRectInset(rect, strokeInset, strokeInset);
|
||||
CGFloat strokeRadius = cornerRadius > self.scale / 2 ? cornerRadius - self.scale / 2 : 0;
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(strokeRadius, strokeRadius)];
|
||||
#else
|
||||
NSBezierPath *path = [NSBezierPath sd_bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadius:strokeRadius];
|
||||
#endif
|
||||
[path closePath];
|
||||
|
||||
path.lineWidth = borderWidth;
|
||||
[borderColor setStroke];
|
||||
[path stroke];
|
||||
}
|
||||
|
||||
UIImage *image = SDGraphicsGetImageFromCurrentImageContext();
|
||||
SDGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIImage *)sd_rotatedImageWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize {
|
||||
if (!self.CGImage) return nil;
|
||||
size_t width = (size_t)CGImageGetWidth(self.CGImage);
|
||||
size_t height = (size_t)CGImageGetHeight(self.CGImage);
|
||||
CGRect newRect = CGRectApplyAffineTransform(CGRectMake(0., 0., width, height),
|
||||
fitSize ? CGAffineTransformMakeRotation(angle) : CGAffineTransformIdentity);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(NULL,
|
||||
(size_t)newRect.size.width,
|
||||
(size_t)newRect.size.height,
|
||||
8,
|
||||
(size_t)newRect.size.width * 4,
|
||||
colorSpace,
|
||||
kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
if (!context) return nil;
|
||||
|
||||
CGContextSetShouldAntialias(context, true);
|
||||
CGContextSetAllowsAntialiasing(context, true);
|
||||
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
|
||||
|
||||
CGContextTranslateCTM(context, +(newRect.size.width * 0.5), +(newRect.size.height * 0.5));
|
||||
CGContextRotateCTM(context, angle);
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(-(width * 0.5), -(height * 0.5), width, height), self.CGImage);
|
||||
CGImageRef imgRef = CGBitmapContextCreateImage(context);
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation];
|
||||
#else
|
||||
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale];
|
||||
#endif
|
||||
CGImageRelease(imgRef);
|
||||
CGContextRelease(context);
|
||||
return img;
|
||||
}
|
||||
|
||||
- (UIImage *)sd_flippedImageWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical {
|
||||
if (!self.CGImage) return nil;
|
||||
size_t width = (size_t)CGImageGetWidth(self.CGImage);
|
||||
size_t height = (size_t)CGImageGetHeight(self.CGImage);
|
||||
size_t bytesPerRow = width * 4;
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
if (!context) return nil;
|
||||
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage);
|
||||
UInt8 *data = (UInt8 *)CGBitmapContextGetData(context);
|
||||
if (!data) {
|
||||
CGContextRelease(context);
|
||||
return nil;
|
||||
}
|
||||
vImage_Buffer src = { data, height, width, bytesPerRow };
|
||||
vImage_Buffer dest = { data, height, width, bytesPerRow };
|
||||
if (vertical) {
|
||||
vImageVerticalReflect_ARGB8888(&src, &dest, kvImageBackgroundColorFill);
|
||||
}
|
||||
if (horizontal) {
|
||||
vImageHorizontalReflect_ARGB8888(&src, &dest, kvImageBackgroundColorFill);
|
||||
}
|
||||
CGImageRef imgRef = CGBitmapContextCreateImage(context);
|
||||
CGContextRelease(context);
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation];
|
||||
#else
|
||||
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale];
|
||||
#endif
|
||||
CGImageRelease(imgRef);
|
||||
return img;
|
||||
}
|
||||
|
||||
#pragma mark - Image Blending
|
||||
|
||||
- (UIImage *)sd_tintedImageWithColor:(UIColor *)tintColor {
|
||||
if (!self.CGImage) return nil;
|
||||
if (!tintColor.CGColor) return nil;
|
||||
|
||||
BOOL hasTint = CGColorGetAlpha(tintColor.CGColor) > __FLT_EPSILON__;
|
||||
if (!hasTint) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:self.imageOrientation];
|
||||
#else
|
||||
return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale];
|
||||
#endif
|
||||
}
|
||||
|
||||
CGSize size = self.size;
|
||||
CGRect rect = { CGPointZero, size };
|
||||
CGFloat scale = self.scale;
|
||||
|
||||
// blend mode, see https://en.wikipedia.org/wiki/Alpha_compositing
|
||||
CGBlendMode blendMode = kCGBlendModeSourceAtop;
|
||||
|
||||
SDGraphicsBeginImageContextWithOptions(size, NO, scale);
|
||||
CGContextRef context = SDGraphicsGetCurrentContext();
|
||||
CGContextDrawImage(context, rect, self.CGImage);
|
||||
CGContextSetBlendMode(context, blendMode);
|
||||
CGContextSetFillColorWithColor(context, tintColor.CGColor);
|
||||
CGContextFillRect(context, rect);
|
||||
UIImage *image = SDGraphicsGetImageFromCurrentImageContext();
|
||||
SDGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIColor *)sd_colorAtPoint:(CGPoint)point {
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
CGImageRef imageRef = self.CGImage;
|
||||
if (!imageRef) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Check point
|
||||
CGFloat width = CGImageGetWidth(imageRef);
|
||||
CGFloat height = CGImageGetHeight(imageRef);
|
||||
if (point.x < 0 || point.y < 0 || point.x >= width || point.y >= height) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get pixels
|
||||
CGDataProviderRef provider = CGImageGetDataProvider(imageRef);
|
||||
if (!provider) {
|
||||
return nil;
|
||||
}
|
||||
CFDataRef data = CGDataProviderCopyData(provider);
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get pixel at point
|
||||
size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
|
||||
size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef);
|
||||
|
||||
CFRange range = CFRangeMake(bytesPerRow * point.y + components * point.x, 4);
|
||||
if (CFDataGetLength(data) < range.location + range.length) {
|
||||
CFRelease(data);
|
||||
return nil;
|
||||
}
|
||||
Pixel_8888 pixel = {0};
|
||||
CFDataGetBytes(data, range, pixel);
|
||||
CFRelease(data);
|
||||
|
||||
// Convert to color
|
||||
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
|
||||
return SDGetColorFromPixel(pixel, bitmapInfo);
|
||||
}
|
||||
|
||||
- (NSArray<UIColor *> *)sd_colorsWithRect:(CGRect)rect {
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
CGImageRef imageRef = self.CGImage;
|
||||
if (!imageRef) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Check rect
|
||||
CGFloat width = CGImageGetWidth(imageRef);
|
||||
CGFloat height = CGImageGetHeight(imageRef);
|
||||
if (CGRectGetWidth(rect) <= 0 || CGRectGetHeight(rect) <= 0 || CGRectGetMinX(rect) < 0 || CGRectGetMinY(rect) < 0 || CGRectGetMaxX(rect) > width || CGRectGetMaxY(rect) > height) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get pixels
|
||||
CGDataProviderRef provider = CGImageGetDataProvider(imageRef);
|
||||
if (!provider) {
|
||||
return nil;
|
||||
}
|
||||
CFDataRef data = CGDataProviderCopyData(provider);
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get pixels with rect
|
||||
size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
|
||||
size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef);
|
||||
|
||||
size_t start = bytesPerRow * CGRectGetMinY(rect) + components * CGRectGetMinX(rect);
|
||||
size_t end = bytesPerRow * (CGRectGetMaxY(rect) - 1) + components * CGRectGetMaxX(rect);
|
||||
if (CFDataGetLength(data) < (CFIndex)end) {
|
||||
CFRelease(data);
|
||||
return nil;
|
||||
}
|
||||
|
||||
const UInt8 *pixels = CFDataGetBytePtr(data);
|
||||
size_t row = CGRectGetMinY(rect);
|
||||
size_t col = CGRectGetMaxX(rect);
|
||||
|
||||
// Convert to color
|
||||
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
|
||||
NSMutableArray<UIColor *> *colors = [NSMutableArray arrayWithCapacity:CGRectGetWidth(rect) * CGRectGetHeight(rect)];
|
||||
for (size_t index = start; index < end; index += 4) {
|
||||
if (index >= row * bytesPerRow + col * components) {
|
||||
// Index beyond the end of current row, go next row
|
||||
row++;
|
||||
index = row * bytesPerRow + CGRectGetMinX(rect) * components;
|
||||
index -= 4;
|
||||
continue;
|
||||
}
|
||||
Pixel_8888 pixel = {pixels[index], pixels[index+1], pixels[index+2], pixels[index+3]};
|
||||
UIColor *color = SDGetColorFromPixel(pixel, bitmapInfo);
|
||||
[colors addObject:color];
|
||||
}
|
||||
CFRelease(data);
|
||||
|
||||
return [colors copy];
|
||||
}
|
||||
|
||||
#pragma mark - Image Effect
|
||||
|
||||
// We use vImage to do box convolve for performance and support for watchOS. However, you can just use `CIFilter.CIBoxBlur`. For other blur effect, use any filter in `CICategoryBlur`
|
||||
- (UIImage *)sd_blurredImageWithRadius:(CGFloat)blurRadius {
|
||||
if (self.size.width < 1 || self.size.height < 1) {
|
||||
return nil;
|
||||
}
|
||||
if (!self.CGImage) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
BOOL hasBlur = blurRadius > __FLT_EPSILON__;
|
||||
if (!hasBlur) {
|
||||
return self;
|
||||
}
|
||||
|
||||
CGFloat scale = self.scale;
|
||||
CGImageRef imageRef = self.CGImage;
|
||||
|
||||
vImage_Buffer effect = {}, scratch = {};
|
||||
vImage_Buffer *input = NULL, *output = NULL;
|
||||
|
||||
vImage_CGImageFormat format = {
|
||||
.bitsPerComponent = 8,
|
||||
.bitsPerPixel = 32,
|
||||
.colorSpace = NULL,
|
||||
.bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little, //requests a BGRA buffer.
|
||||
.version = 0,
|
||||
.decode = NULL,
|
||||
.renderingIntent = kCGRenderingIntentDefault
|
||||
};
|
||||
|
||||
vImage_Error err;
|
||||
err = vImageBuffer_InitWithCGImage(&effect, &format, NULL, imageRef, kvImagePrintDiagnosticsToConsole);
|
||||
if (err != kvImageNoError) {
|
||||
NSLog(@"UIImage+Transform error: vImageBuffer_InitWithCGImage returned error code %zi for inputImage: %@", err, self);
|
||||
return nil;
|
||||
}
|
||||
err = vImageBuffer_Init(&scratch, effect.height, effect.width, format.bitsPerPixel, kvImageNoFlags);
|
||||
if (err != kvImageNoError) {
|
||||
NSLog(@"UIImage+Transform error: vImageBuffer_Init returned error code %zi for inputImage: %@", err, self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
input = &effect;
|
||||
output = &scratch;
|
||||
|
||||
if (hasBlur) {
|
||||
// A description of how to compute the box kernel width from the Gaussian
|
||||
// radius (aka standard deviation) appears in the SVG spec:
|
||||
// http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
|
||||
//
|
||||
// For larger values of 's' (s >= 2.0), an approximation can be used: Three
|
||||
// successive box-blurs build a piece-wise quadratic convolution kernel, which
|
||||
// approximates the Gaussian kernel to within roughly 3%.
|
||||
//
|
||||
// let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
|
||||
//
|
||||
// ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
|
||||
//
|
||||
CGFloat inputRadius = blurRadius * scale;
|
||||
if (inputRadius - 2.0 < __FLT_EPSILON__) inputRadius = 2.0;
|
||||
uint32_t radius = floor((inputRadius * 3.0 * sqrt(2 * M_PI) / 4 + 0.5) / 2);
|
||||
radius |= 1; // force radius to be odd so that the three box-blur methodology works.
|
||||
int iterations;
|
||||
if (blurRadius * scale < 0.5) iterations = 1;
|
||||
else if (blurRadius * scale < 1.5) iterations = 2;
|
||||
else iterations = 3;
|
||||
NSInteger tempSize = vImageBoxConvolve_ARGB8888(input, output, NULL, 0, 0, radius, radius, NULL, kvImageGetTempBufferSize | kvImageEdgeExtend);
|
||||
void *temp = malloc(tempSize);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
vImageBoxConvolve_ARGB8888(input, output, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend);
|
||||
vImage_Buffer *tmp = input;
|
||||
input = output;
|
||||
output = tmp;
|
||||
}
|
||||
free(temp);
|
||||
}
|
||||
|
||||
CGImageRef effectCGImage = NULL;
|
||||
effectCGImage = vImageCreateCGImageFromBuffer(input, &format, NULL, NULL, kvImageNoAllocate, NULL);
|
||||
if (effectCGImage == NULL) {
|
||||
effectCGImage = vImageCreateCGImageFromBuffer(input, &format, NULL, NULL, kvImageNoFlags, NULL);
|
||||
free(input->data);
|
||||
}
|
||||
free(output->data);
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIImage *outputImage = [UIImage imageWithCGImage:effectCGImage scale:self.scale orientation:self.imageOrientation];
|
||||
#else
|
||||
UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale];
|
||||
#endif
|
||||
CGImageRelease(effectCGImage);
|
||||
|
||||
return outputImage;
|
||||
}
|
||||
|
||||
#if SD_UIKIT || SD_MAC
|
||||
- (UIImage *)sd_filteredImageWithFilter:(CIFilter *)filter {
|
||||
if (!self.CGImage) return nil;
|
||||
|
||||
CIContext *context = [CIContext context];
|
||||
CIImage *inputImage = [CIImage imageWithCGImage:self.CGImage];
|
||||
if (!inputImage) return nil;
|
||||
|
||||
[filter setValue:inputImage forKey:kCIInputImageKey];
|
||||
CIImage *outputImage = filter.outputImage;
|
||||
if (!outputImage) return nil;
|
||||
|
||||
CGImageRef imageRef = [context createCGImage:outputImage fromRect:outputImage.extent];
|
||||
if (!imageRef) return nil;
|
||||
|
||||
#if SD_UIKIT
|
||||
UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
|
||||
#else
|
||||
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale];
|
||||
#endif
|
||||
CGImageRelease(imageRef);
|
||||
|
||||
return image;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
|
@ -12,6 +12,10 @@
|
|||
2D7AF0601F329763000083C2 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; };
|
||||
321259EC1F39E3240096FE0E /* TestImageStatic.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259EB1F39E3240096FE0E /* TestImageStatic.webp */; };
|
||||
321259EE1F39E4110096FE0E /* TestImageAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 321259ED1F39E4110096FE0E /* TestImageAnimated.webp */; };
|
||||
3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; };
|
||||
3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */; };
|
||||
3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; };
|
||||
3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */; };
|
||||
32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; };
|
||||
32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7AF05F1F329763000083C2 /* SDTestCase.m */; };
|
||||
32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */; };
|
||||
|
@ -56,6 +60,9 @@
|
|||
2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = "<group>"; };
|
||||
321259EB1F39E3240096FE0E /* TestImageStatic.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageStatic.webp; sourceTree = "<group>"; };
|
||||
321259ED1F39E4110096FE0E /* TestImageAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageAnimated.webp; sourceTree = "<group>"; };
|
||||
3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransformerTests.m; sourceTree = "<group>"; };
|
||||
3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestTransformer.h; sourceTree = "<group>"; };
|
||||
3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestTransformer.m; sourceTree = "<group>"; };
|
||||
32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = "<group>"; };
|
||||
32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
|
@ -185,6 +192,7 @@
|
|||
1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */,
|
||||
433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */,
|
||||
4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */,
|
||||
3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */,
|
||||
4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */,
|
||||
32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */,
|
||||
37D122861EC48B5E00D98CEB /* SDMockFileManager.h */,
|
||||
|
@ -193,6 +201,8 @@
|
|||
2D7AF05F1F329763000083C2 /* SDTestCase.m */,
|
||||
32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */,
|
||||
32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */,
|
||||
3264FF2D205D42CB00F6BD48 /* SDWebImageTestTransformer.h */,
|
||||
3264FF2E205D42CB00F6BD48 /* SDWebImageTestTransformer.m */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -439,6 +449,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */,
|
||||
3254C32120641077008D1022 /* SDWebImageTransformerTests.m in Sources */,
|
||||
32B99E9C203B2EE40017FD66 /* SDCategoriesTests.m in Sources */,
|
||||
32B99EAA203B365F0017FD66 /* SDImageCacheTests.m in Sources */,
|
||||
32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */,
|
||||
|
@ -447,6 +458,7 @@
|
|||
32B99E9E203B2F810017FD66 /* SDMockFileManager.m in Sources */,
|
||||
32B99EAB203B36620017FD66 /* SDWebImageManagerTests.m in Sources */,
|
||||
32B99EA9203B34B60017FD66 /* SDWebImageDecoderTests.m in Sources */,
|
||||
3264FF30205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */,
|
||||
32B99E9B203B2EDD0017FD66 /* SDTestCase.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -456,6 +468,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */,
|
||||
3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */,
|
||||
1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */,
|
||||
37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */,
|
||||
4369C2741D9804B1007E863A /* SDWebCacheCategoriesTests.m in Sources */,
|
||||
|
@ -464,6 +477,7 @@
|
|||
DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */,
|
||||
DA248D6B195476AC00390AB0 /* SDWebImageManagerTests.m in Sources */,
|
||||
32B99E8B203AF8690017FD66 /* SDCategoriesTests.m in Sources */,
|
||||
3264FF2F205D42CB00F6BD48 /* SDWebImageTestTransformer.m in Sources */,
|
||||
433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#import "SDTestCase.h"
|
||||
#import <SDWebImage/SDWebImageManager.h>
|
||||
#import "SDWebImageTestTransformer.h"
|
||||
|
||||
@interface SDWebImageManagerTests : SDTestCase
|
||||
|
||||
|
@ -135,4 +136,23 @@
|
|||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout * 2 handler:nil];
|
||||
}
|
||||
|
||||
- (void)test08ThatImageTransformerWork {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"];
|
||||
NSURL *imageURL = [NSURL URLWithString:kTestJpegURL];
|
||||
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *testImagePath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"];
|
||||
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:testImagePath];
|
||||
SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] downloader:[SDWebImageDownloader sharedDownloader]];
|
||||
manager.transformer = transformer;
|
||||
[[SDImageCache sharedImageCache] removeImageForKey:kTestJpegURL withCompletion:^{
|
||||
[manager loadImageWithURL:imageURL options:SDWebImageTransformAnimatedImage progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
expect(image).equal(transformer.testImage);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
* (c) Matt Galloway
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <SDWebImage/SDWebImageTransformer.h>
|
||||
|
||||
@interface SDWebImageTestTransformer : NSObject <SDWebImageTransformer>
|
||||
|
||||
@property (nonatomic, strong, nullable) UIImage *testImage;
|
||||
|
||||
@end
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
* (c) Matt Galloway
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageTestTransformer.h"
|
||||
|
||||
@implementation SDWebImageTestTransformer
|
||||
|
||||
- (NSString *)transformerKey {
|
||||
return @"SDWebImageTestTransformer";
|
||||
}
|
||||
|
||||
- (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
|
||||
return self.testImage;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
* (c) Matt Galloway
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDTestCase.h"
|
||||
#import <SDWebImage/UIImage+Transform.h>
|
||||
#import <CoreImage/CoreImage.h>
|
||||
#import <SDWebImage/SDWebImageTransformer.h>
|
||||
|
||||
// Internal header
|
||||
@interface UIColor (HexString)
|
||||
|
||||
@property (nonatomic, copy, readonly, nonnull) NSString *sd_hexString;
|
||||
|
||||
@end
|
||||
|
||||
@interface SDWebImageTransformerTests : SDTestCase
|
||||
|
||||
@property (nonatomic, strong) UIImage *testImage;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageTransformerTests
|
||||
|
||||
#pragma mark - UIImage+Transform
|
||||
|
||||
// UIImage+Transform test is hard to write because it's more about visual effect. Current it's tied to the `TestImage.png`, please keep that image or write new test with new image
|
||||
- (void)test01UIImageTransformResize {
|
||||
CGSize scaleDownSize = CGSizeMake(200, 100);
|
||||
UIImage *scaledDownImage = [self.testImage sd_resizedImageWithSize:scaleDownSize scaleMode:SDImageScaleModeFill];
|
||||
expect(CGSizeEqualToSize(scaledDownImage.size, scaleDownSize)).beTruthy();
|
||||
CGSize scaleUpSize = CGSizeMake(2000, 1000);
|
||||
UIImage *scaledUpImage = [self.testImage sd_resizedImageWithSize:scaleUpSize scaleMode:SDImageScaleModeAspectFit];
|
||||
expect(CGSizeEqualToSize(scaledUpImage.size, scaleUpSize)).beTruthy();
|
||||
}
|
||||
|
||||
- (void)test02UIImageTransformCrop {
|
||||
CGRect rect = CGRectMake(50, 50, 200, 200);
|
||||
UIImage *croppedImage = [self.testImage sd_croppedImageWithRect:rect];
|
||||
expect(CGSizeEqualToSize(croppedImage.size, CGSizeMake(200, 200))).beTruthy();
|
||||
UIColor *startColor = [croppedImage sd_colorAtPoint:CGPointZero];
|
||||
expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy();
|
||||
}
|
||||
|
||||
- (void)test03UIImageTransformRoundedCorner {
|
||||
CGFloat radius = 50;
|
||||
#if SD_UIKIT
|
||||
SDRectCorner corners = UIRectCornerAllCorners;
|
||||
#else
|
||||
SDRectCorner corners = SDRectCornerAllCorners;
|
||||
#endif
|
||||
CGFloat borderWidth = 1;
|
||||
UIColor *borderColor = [UIColor blackColor];
|
||||
UIImage *roundedCornerImage = [self.testImage sd_roundedCornerImageWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderColor];
|
||||
expect(CGSizeEqualToSize(roundedCornerImage.size, CGSizeMake(300, 300))).beTruthy();
|
||||
UIColor *startColor = [roundedCornerImage sd_colorAtPoint:CGPointZero];
|
||||
expect([startColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy();
|
||||
// Check the left center pixel, should be border :)
|
||||
UIColor *checkBorderColor = [roundedCornerImage sd_colorAtPoint:CGPointMake(1, 150)];
|
||||
expect([checkBorderColor.sd_hexString isEqualToString:borderColor.sd_hexString]).beTruthy();
|
||||
}
|
||||
|
||||
- (void)test04UIImageTransformRotate {
|
||||
CGFloat angle = M_PI_4;
|
||||
UIImage *rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO];
|
||||
// Not fit size and no change
|
||||
expect(CGSizeEqualToSize(rotatedImage.size, self.testImage.size)).beTruthy();
|
||||
// Fit size, may change size
|
||||
rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:YES];
|
||||
CGSize rotatedSize = CGSizeMake(floor(300 * 1.414), floor(300 * 1.414)); // 45º, square length * sqrt(2)
|
||||
expect(CGSizeEqualToSize(rotatedImage.size, rotatedSize)).beTruthy();
|
||||
rotatedImage = [self.testImage sd_rotatedImageWithAngle:angle fitSize:NO];
|
||||
}
|
||||
|
||||
- (void)test05UIImageTransformFlip {
|
||||
BOOL horizontal = YES;
|
||||
BOOL vertical = YES;
|
||||
UIImage *flippedImage = [self.testImage sd_flippedImageWithHorizontal:horizontal vertical:vertical];
|
||||
expect(CGSizeEqualToSize(flippedImage.size, self.testImage.size)).beTruthy();
|
||||
// Test pixel colors method here
|
||||
UIColor *checkColor = [flippedImage sd_colorAtPoint:CGPointMake(75, 75)];
|
||||
expect(checkColor);
|
||||
NSArray<UIColor *> *checkColors = [flippedImage sd_colorsWithRect:CGRectMake(75, 75, 10, 10)]; // Rect are all same color
|
||||
expect(checkColors.count).to.equal(10 * 10);
|
||||
for (UIColor *color in checkColors) {
|
||||
expect([color isEqual:checkColor]).to.beTruthy();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)test06UIImageTransformTint {
|
||||
UIColor *tintColor = [UIColor blackColor];
|
||||
UIImage *tintedImage = [self.testImage sd_tintedImageWithColor:tintColor];
|
||||
expect(CGSizeEqualToSize(tintedImage.size, self.testImage.size)).beTruthy();
|
||||
// Check center color, should keep clear
|
||||
UIColor *centerColor = [tintedImage sd_colorAtPoint:CGPointMake(150, 150)];
|
||||
expect([centerColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]);
|
||||
// Check left color, should be tinted
|
||||
UIColor *leftColor = [tintedImage sd_colorAtPoint:CGPointMake(80, 150)];
|
||||
expect([leftColor.sd_hexString isEqualToString:tintColor.sd_hexString]);
|
||||
}
|
||||
|
||||
- (void)test07UIImageTransformBlur {
|
||||
CGFloat radius = 50;
|
||||
UIImage *blurredImage = [self.testImage sd_blurredImageWithRadius:radius];
|
||||
expect(CGSizeEqualToSize(blurredImage.size, self.testImage.size)).beTruthy();
|
||||
// Check left color, should be blurred
|
||||
UIColor *leftColor = [blurredImage sd_colorAtPoint:CGPointMake(80, 150)];
|
||||
// Hard-code from the output
|
||||
UIColor *expectedColor = [UIColor colorWithRed:0.431373 green:0.101961 blue:0.0901961 alpha:0.729412];
|
||||
expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]);
|
||||
}
|
||||
|
||||
- (void)test08UIImageTransformFilter {
|
||||
// Invert color filter
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"];
|
||||
UIImage *filteredImage = [self.testImage sd_filteredImageWithFilter:filter];
|
||||
expect(CGSizeEqualToSize(filteredImage.size, self.testImage.size)).beTruthy();
|
||||
// Check left color, should be inverted
|
||||
UIColor *leftColor = [filteredImage sd_colorAtPoint:CGPointMake(80, 150)];
|
||||
// Hard-code from the output
|
||||
UIColor *expectedColor = [UIColor colorWithRed:0.85098 green:0.992157 blue:0.992157 alpha:1];
|
||||
expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]);
|
||||
}
|
||||
|
||||
#pragma mark - SDWebImageTransformer
|
||||
|
||||
- (void)test09ImagePipelineTransformer {
|
||||
CGSize size = CGSizeMake(100, 100);
|
||||
SDImageScaleMode scaleMode = SDImageScaleModeAspectFill;
|
||||
CGFloat angle = M_PI_4;
|
||||
BOOL fitSize = NO;
|
||||
CGFloat radius = 50;
|
||||
#if SD_UIKIT
|
||||
SDRectCorner corners = UIRectCornerAllCorners;
|
||||
#else
|
||||
SDRectCorner corners = SDRectCornerAllCorners;
|
||||
#endif
|
||||
CGFloat borderWidth = 1;
|
||||
UIColor *borderCoder = [UIColor blackColor];
|
||||
SDWebImageResizingTransformer *transformer1 = [SDWebImageResizingTransformer transformerWithSize:size scaleMode:scaleMode];
|
||||
SDWebImageRotationTransformer *transformer2 = [SDWebImageRotationTransformer transformerWithAngle:angle fitSize:fitSize];
|
||||
SDWebImageRoundCornerTransformer *transformer3 = [SDWebImageRoundCornerTransformer transformerWithRadius:radius corners:corners borderWidth:borderWidth borderColor:borderCoder];
|
||||
SDWebImagePipelineTransformer *pipelineTransformer = [SDWebImagePipelineTransformer transformerWithTransformers:@[transformer1, transformer2, transformer3]];
|
||||
|
||||
UIImage *transformedImage = [pipelineTransformer transformedImageWithImage:self.testImage forKey:@"Test"];
|
||||
expect(CGSizeEqualToSize(transformedImage.size, size)).beTruthy();
|
||||
}
|
||||
|
||||
#pragma mark - Helper
|
||||
|
||||
- (UIImage *)testImage {
|
||||
if (!_testImage) {
|
||||
_testImage = [[UIImage alloc] initWithContentsOfFile:[self testPNGPath]];
|
||||
}
|
||||
return _testImage;
|
||||
}
|
||||
|
||||
- (NSString *)testPNGPath {
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
return [testBundle pathForResource:@"TestImage" ofType:@"png"];
|
||||
}
|
||||
|
||||
@end
|
|
@ -37,6 +37,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
|
|||
#import <SDWebImage/SDWebImageDownloader.h>
|
||||
#import <SDWebImage/SDWebImageTransition.h>
|
||||
#import <SDWebImage/SDWebImageIndicator.h>
|
||||
#import <SDWebImage/SDWebImageTransformer.h>
|
||||
#import <SDWebImage/UIImage+Transform.h>
|
||||
|
||||
#if SD_MAC || SD_UIKIT
|
||||
#import <SDWebImage/MKAnnotationView+WebCache.h>
|
||||
|
|
Loading…
Reference in New Issue