13 |
14 | #ifdef SD_WEBP
15 | #import "UIImage+WebP.h"
16 | #endif
17 |
18 | @implementation UIImage (MultiFormat)
19 |
20 | + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data {
21 | if (!data) {
22 | return nil;
23 | }
24 |
25 | UIImage *image;
26 | SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data];
27 | if (imageFormat == SDImageFormatGIF) {
28 | image = [UIImage sd_animatedGIFWithData:data];
29 | }
30 | #ifdef SD_WEBP
31 | else if (imageFormat == SDImageFormatWebP)
32 | {
33 | image = [UIImage sd_imageWithWebPData:data];
34 | }
35 | #endif
36 | else {
37 | image = [[UIImage alloc] initWithData:data];
38 | #if SD_UIKIT || SD_WATCH
39 | UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data];
40 | if (orientation != UIImageOrientationUp) {
41 | image = [UIImage imageWithCGImage:image.CGImage
42 | scale:image.scale
43 | orientation:orientation];
44 | }
45 | #endif
46 | }
47 |
48 |
49 | return image;
50 | }
51 |
52 | #if SD_UIKIT || SD_WATCH
53 | +(UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData {
54 | UIImageOrientation result = UIImageOrientationUp;
55 | CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
56 | if (imageSource) {
57 | CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
58 | if (properties) {
59 | CFTypeRef val;
60 | int exifOrientation;
61 | val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
62 | if (val) {
63 | CFNumberGetValue(val, kCFNumberIntType, &exifOrientation);
64 | result = [self sd_exifOrientationToiOSOrientation:exifOrientation];
65 | } // else - if it's not set it remains at up
66 | CFRelease((CFTypeRef) properties);
67 | } else {
68 | //NSLog(@"NO PROPERTIES, FAIL");
69 | }
70 | CFRelease(imageSource);
71 | }
72 | return result;
73 | }
74 |
75 | #pragma mark EXIF orientation tag converter
76 | // Convert an EXIF image orientation to an iOS one.
77 | // reference see here: http://sylvana.net/jpegcrop/exif_orientation.html
78 | + (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation {
79 | UIImageOrientation orientation = UIImageOrientationUp;
80 | switch (exifOrientation) {
81 | case 1:
82 | orientation = UIImageOrientationUp;
83 | break;
84 |
85 | case 3:
86 | orientation = UIImageOrientationDown;
87 | break;
88 |
89 | case 8:
90 | orientation = UIImageOrientationLeft;
91 | break;
92 |
93 | case 6:
94 | orientation = UIImageOrientationRight;
95 | break;
96 |
97 | case 2:
98 | orientation = UIImageOrientationUpMirrored;
99 | break;
100 |
101 | case 4:
102 | orientation = UIImageOrientationDownMirrored;
103 | break;
104 |
105 | case 5:
106 | orientation = UIImageOrientationLeftMirrored;
107 | break;
108 |
109 | case 7:
110 | orientation = UIImageOrientationRightMirrored;
111 | break;
112 | default:
113 | break;
114 | }
115 | return orientation;
116 | }
117 | #endif
118 |
119 | - (nullable NSData *)sd_imageData {
120 | return [self sd_imageDataAsFormat:SDImageFormatUndefined];
121 | }
122 |
123 | - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat {
124 | NSData *imageData = nil;
125 | if (self) {
126 | #if SD_UIKIT || SD_WATCH
127 | int alphaInfo = CGImageGetAlphaInfo(self.CGImage);
128 | BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
129 | alphaInfo == kCGImageAlphaNoneSkipFirst ||
130 | alphaInfo == kCGImageAlphaNoneSkipLast);
131 |
132 | BOOL usePNG = hasAlpha;
133 |
134 | // the imageFormat param has priority here. But if the format is undefined, we relly on the alpha channel
135 | if (imageFormat != SDImageFormatUndefined) {
136 | usePNG = (imageFormat == SDImageFormatPNG);
137 | }
138 |
139 | if (usePNG) {
140 | imageData = UIImagePNGRepresentation(self);
141 | } else {
142 | imageData = UIImageJPEGRepresentation(self, (CGFloat)1.0);
143 | }
144 | #else
145 | NSBitmapImageFileType imageFileType = NSJPEGFileType;
146 | if (imageFormat == SDImageFormatGIF) {
147 | imageFileType = NSGIFFileType;
148 | } else if (imageFormat == SDImageFormatPNG) {
149 | imageFileType = NSPNGFileType;
150 | }
151 |
152 | imageData = [NSBitmapImageRep representationOfImageRepsInArray:self.representations
153 | usingType:imageFileType
154 | properties:@{}];
155 | #endif
156 | }
157 | return imageData;
158 | }
159 |
160 |
161 | @end
162 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Demo -
7 | Installation -
8 | Documents -
9 | Contribution -
10 | 中文文档
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | # LNTheme
22 | Dynamic theme switching framework that supports local multi-theme configuration or network multi-theme configuration.
23 |
24 | ## Demo
25 | Use Netease cloud music API
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
178 |
179 | Copyright (c) 2016 vvusu
180 |
181 |
--------------------------------------------------------------------------------
/LNThemeDemo/Libraries/SDWebImage/UIImage+WebP.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #ifdef SD_WEBP
10 |
11 | #import "UIImage+WebP.h"
12 | #import "webp/decode.h"
13 | #import "webp/mux_types.h"
14 | #import "webp/demux.h"
15 | #import "NSImage+WebCache.h"
16 |
17 | // Callback for CGDataProviderRelease
18 | static void FreeImageData(void *info, const void *data, size_t size) {
19 | free((void *)data);
20 | }
21 |
22 | @implementation UIImage (WebP)
23 |
24 | + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data {
25 | if (!data) {
26 | return nil;
27 | }
28 |
29 | WebPData webpData;
30 | WebPDataInit(&webpData);
31 | webpData.bytes = data.bytes;
32 | webpData.size = data.length;
33 | WebPDemuxer *demuxer = WebPDemux(&webpData);
34 | if (!demuxer) {
35 | return nil;
36 | }
37 |
38 | uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
39 | if (!(flags & ANIMATION_FLAG)) {
40 | // for static single webp image
41 | UIImage *staticImage = [self sd_rawWepImageWithData:webpData];
42 | WebPDemuxDelete(demuxer);
43 | return staticImage;
44 | }
45 |
46 | WebPIterator iter;
47 | if (!WebPDemuxGetFrame(demuxer, 1, &iter)) {
48 | WebPDemuxReleaseIterator(&iter);
49 | WebPDemuxDelete(demuxer);
50 | return nil;
51 | }
52 |
53 | NSMutableArray *images = [NSMutableArray array];
54 | NSTimeInterval duration = 0;
55 |
56 | do {
57 | UIImage *image;
58 | if (iter.blend_method == WEBP_MUX_BLEND) {
59 | image = [self sd_blendWebpImageWithOriginImage:[images lastObject] iterator:iter];
60 | } else {
61 | image = [self sd_rawWepImageWithData:iter.fragment];
62 | }
63 |
64 | if (!image) {
65 | continue;
66 | }
67 |
68 | [images addObject:image];
69 | duration += iter.duration / 1000.0f;
70 |
71 | } while (WebPDemuxNextFrame(&iter));
72 |
73 | WebPDemuxReleaseIterator(&iter);
74 | WebPDemuxDelete(demuxer);
75 |
76 | UIImage *finalImage = nil;
77 | #if SD_UIKIT || SD_WATCH
78 | finalImage = [UIImage animatedImageWithImages:images duration:duration];
79 | #elif SD_MAC
80 | if ([images count] > 0) {
81 | finalImage = images[0];
82 | }
83 | #endif
84 | return finalImage;
85 | }
86 |
87 |
88 | + (nullable UIImage *)sd_blendWebpImageWithOriginImage:(nullable UIImage *)originImage iterator:(WebPIterator)iter {
89 | if (!originImage) {
90 | return nil;
91 | }
92 |
93 | CGSize size = originImage.size;
94 | CGFloat tmpX = iter.x_offset;
95 | CGFloat tmpY = size.height - iter.height - iter.y_offset;
96 | CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height);
97 |
98 | UIImage *image = [self sd_rawWepImageWithData:iter.fragment];
99 | if (!image) {
100 | return nil;
101 | }
102 |
103 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
104 | uint32_t bitmapInfo = iter.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0;
105 | CGContextRef blendCanvas = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpaceRef, bitmapInfo);
106 | CGContextDrawImage(blendCanvas, CGRectMake(0, 0, size.width, size.height), originImage.CGImage);
107 | CGContextDrawImage(blendCanvas, imageRect, image.CGImage);
108 | CGImageRef newImageRef = CGBitmapContextCreateImage(blendCanvas);
109 |
110 | #if SD_UIKIT || SD_WATCH
111 | image = [UIImage imageWithCGImage:newImageRef];
112 | #elif SD_MAC
113 | image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize];
114 | #endif
115 |
116 | CGImageRelease(newImageRef);
117 | CGContextRelease(blendCanvas);
118 | CGColorSpaceRelease(colorSpaceRef);
119 |
120 | return image;
121 | }
122 |
123 | + (nullable UIImage *)sd_rawWepImageWithData:(WebPData)webpData {
124 | WebPDecoderConfig config;
125 | if (!WebPInitDecoderConfig(&config)) {
126 | return nil;
127 | }
128 |
129 | if (WebPGetFeatures(webpData.bytes, webpData.size, &config.input) != VP8_STATUS_OK) {
130 | return nil;
131 | }
132 |
133 | config.output.colorspace = config.input.has_alpha ? MODE_rgbA : MODE_RGB;
134 | config.options.use_threads = 1;
135 |
136 | // Decode the WebP image data into a RGBA value array.
137 | if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) {
138 | return nil;
139 | }
140 |
141 | int width = config.input.width;
142 | int height = config.input.height;
143 | if (config.options.use_scaling) {
144 | width = config.options.scaled_width;
145 | height = config.options.scaled_height;
146 | }
147 |
148 | // Construct a UIImage from the decoded RGBA value array.
149 | CGDataProviderRef provider =
150 | CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData);
151 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
152 | CGBitmapInfo bitmapInfo = config.input.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0;
153 | size_t components = config.input.has_alpha ? 4 : 3;
154 | CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
155 | CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
156 |
157 | CGColorSpaceRelease(colorSpaceRef);
158 | CGDataProviderRelease(provider);
159 |
160 | #if SD_UIKIT || SD_WATCH
161 | UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
162 | #else
163 | UIImage *image = [[UIImage alloc] initWithCGImage:imageRef size:NSZeroSize];
164 | #endif
165 | CGImageRelease(imageRef);
166 |
167 | return image;
168 | }
169 |
170 | @end
171 |
172 | #endif
173 |
--------------------------------------------------------------------------------