swfから画像を抽出するコマンドラインアプリケーション
Revision | c69b7c88b8e7998bbc28dad36325baeeacde6b30 (tree) |
---|---|
Zeit | 2016-09-16 00:27:31 |
Autor | masakih <masakih@user...> |
Commiter | masakih |
BitsLossless2に対応した
@@ -33,6 +33,24 @@ typedef struct _HMSWFBitsJPEG3 { | ||
33 | 33 | } HMSWFBitsJPEG3; |
34 | 34 | #define HMSWFJPEG3HeaderSize 6 |
35 | 35 | |
36 | +typedef struct _HMSWFBitLossless2ColorTable { | |
37 | + UInt8 colorTableSize; | |
38 | + unsigned char data; | |
39 | +} HMSWFBitLossless2ColorTable; | |
40 | + | |
41 | +typedef struct _HMSWFBitsLossless2 { | |
42 | + UInt16 charctorID; | |
43 | + UInt8 bitmapFormat; | |
44 | + UInt16 width; | |
45 | + UInt16 height; | |
46 | + union { | |
47 | + HMSWFBitLossless2ColorTable colorTable; | |
48 | + unsigned char data; | |
49 | + } data; | |
50 | +} HMSWFBitsLossless2; | |
51 | +#define HMSWFLossless2HeaderSize 7 | |
52 | +#define HMSWFLossless2ColorTableHeaderSize 8 | |
53 | + | |
36 | 54 | #pragma pack() |
37 | 55 | |
38 | 56 |
@@ -10,17 +10,22 @@ | ||
10 | 10 | #include "SWFStructure.h" |
11 | 11 | #import "HMZlibData.h" |
12 | 12 | |
13 | + | |
14 | + | |
13 | 15 | static NSString *sCurrentDir = nil; |
14 | 16 | static NSString *sOriginalName = nil; |
15 | 17 | |
16 | -void printLog(const char *fmt, ...) { | |
17 | 18 | #if 0 |
19 | +#define printLog(...) printLogF( __VA_ARGS__) | |
20 | +void printLogF(const char *fmt, ...) { | |
18 | 21 | va_list ap; |
19 | 22 | va_start(ap, fmt); |
20 | 23 | vfprintf(stderr, fmt, ap); |
21 | 24 | va_end(ap); |
22 | -#endif | |
23 | 25 | } |
26 | +#else | |
27 | +#define printLog(...) | |
28 | +#endif | |
24 | 29 | |
25 | 30 | void printHex(const unsigned char *p) { |
26 | 31 | for(int i=0;i<1;i++) { |
@@ -48,7 +53,7 @@ void storeImage(const unsigned char *p, UInt32 length, int tagCount) { | ||
48 | 53 | [pic writeToURL:url atomically:YES]; |
49 | 54 | } |
50 | 55 | |
51 | -void storeDefineBitsJPEG3(const unsigned char *p, UInt32 length, int tagCount) { | |
56 | +void storeBitsJPEG3(const unsigned char *p, UInt32 length, int tagCount) { | |
52 | 57 | printLog("#### TYPE IS PICTURE ####\n\n"); |
53 | 58 | if(length < HMSWFJPEG3HeaderSize) return; |
54 | 59 |
@@ -127,6 +132,122 @@ void storeDefineBitsJPEG3(const unsigned char *p, UInt32 length, int tagCount) { | ||
127 | 132 | [imageData writeToURL:url atomically:YES]; |
128 | 133 | } |
129 | 134 | |
135 | +void storeBitLossless2ColorTable(const unsigned char *p, UInt32 length, int tagCount) { | |
136 | + const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)p; | |
137 | + | |
138 | + UInt8 mapSize = data->data.colorTable.colorTableSize + 1; | |
139 | + printLog("color table size -> %d\n", mapSize); | |
140 | + printLog("zipped image data size -> %d\n", length - HMSWFLossless2ColorTableHeaderSize); | |
141 | + | |
142 | + NSData *zipedContentData = [NSData dataWithBytes:&data->data.colorTable.data length:length - HMSWFLossless2ColorTableHeaderSize]; | |
143 | + NSData *contentData = [zipedContentData inflate]; | |
144 | + printLog("unzipped image data size -> %d\n", contentData.length); | |
145 | + | |
146 | + const UInt32 *mapP = (UInt32 *)contentData.bytes; | |
147 | + const UInt8 *colorIndexP = (UInt8 *)(mapP + mapSize); | |
148 | + | |
149 | +#if 0 | |
150 | + printLog("MAP TABLE\n"); | |
151 | + for(int i = 0; i < mapSize; i++) { | |
152 | + printLog("0x%04x ", mapP[i]); | |
153 | + } | |
154 | + printLog("\n\n"); | |
155 | +#endif | |
156 | + | |
157 | + // rowサイズは4bytesアライメント | |
158 | + UInt8 skipBytes = data->width % 4; | |
159 | + | |
160 | + // ARBGカラーマップからARBGビットマップを作成 | |
161 | + UInt32 *imageDataP = calloc(8 * 4, data->width * data->height); | |
162 | + if(!imageDataP) { | |
163 | + fprintf(stderr, "Can not allocate enough memory.\n"); | |
164 | + return; | |
165 | + } | |
166 | + | |
167 | + UInt32 *imageDataPixel = imageDataP; | |
168 | + for(UInt16 h = 0; h < data->height; h++) { | |
169 | + for(UInt16 w = 0; w < data->width; w++) { | |
170 | + printLog("%d ", *colorIndexP); | |
171 | + *imageDataPixel++ = mapP[*colorIndexP++]; | |
172 | + } | |
173 | + colorIndexP += skipBytes; | |
174 | + printLog("\n"); | |
175 | + } | |
176 | + | |
177 | + // ARGBビットマップからNSBitmapImageRepを作成 | |
178 | + NSData *imageData = [NSData dataWithBytes:imageDataP length:8 * 4 * data->width * data->height]; | |
179 | + unsigned char *pp = (unsigned char *)imageData.bytes; | |
180 | + NSBitmapImageRep *imageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp | |
181 | + pixelsWide:data->width | |
182 | + pixelsHigh:data->height | |
183 | + bitsPerSample:8 | |
184 | + samplesPerPixel:4 | |
185 | + hasAlpha:YES | |
186 | + isPlanar:NO | |
187 | + colorSpaceName:NSCalibratedRGBColorSpace | |
188 | + bytesPerRow:data->width * 4 | |
189 | + bitsPerPixel:0]; | |
190 | + // PNGで保存 | |
191 | + NSData *tiffData = imageRef.TIFFRepresentation; | |
192 | + if(!tiffData) { | |
193 | + fprintf(stderr, "Can not create tiff image.\n"); | |
194 | + return; | |
195 | + } | |
196 | + | |
197 | + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:tiffData]; | |
198 | + NSData *pndData = [rep representationUsingType:NSPNGFileType | |
199 | + properties:@{}]; | |
200 | + NSString *path = [NSString stringWithFormat:@"%@-%d.png", sOriginalName, tagCount]; | |
201 | + path = [sCurrentDir stringByAppendingPathComponent:path]; | |
202 | + NSURL *url = [NSURL fileURLWithPath:path]; | |
203 | + [pndData writeToURL:url atomically:YES]; | |
204 | +} | |
205 | +void storeBitsLossless2(const unsigned char *p, UInt32 length, int tagCount) { | |
206 | + printLog("#### TYPE IS PICTURE ####\n\n"); | |
207 | + if(length < HMSWFLossless2HeaderSize) { | |
208 | + fprintf(stderr, "length is too short.\n"); | |
209 | + return; | |
210 | + } | |
211 | + | |
212 | + const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)p; | |
213 | + | |
214 | + if(data->bitmapFormat == 3) { | |
215 | + storeBitLossless2ColorTable(p, length, tagCount); | |
216 | + return; | |
217 | + } | |
218 | + | |
219 | + length -= HMSWFLossless2HeaderSize; | |
220 | + | |
221 | + p = &data->data.data; | |
222 | + NSData *zipedImageData = [NSData dataWithBytes:p length:length]; | |
223 | + NSData *imageData = [zipedImageData inflate]; | |
224 | + unsigned char *pp = (unsigned char *)imageData.bytes; | |
225 | + NSBitmapImageRep *imageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp | |
226 | + pixelsWide:data->width | |
227 | + pixelsHigh:data->height | |
228 | + bitsPerSample:8 * 4 | |
229 | + samplesPerPixel:4 | |
230 | + hasAlpha:YES | |
231 | + isPlanar:NO | |
232 | + colorSpaceName:NSCalibratedRGBColorSpace | |
233 | + bytesPerRow:data->width * 4 | |
234 | + bitsPerPixel:0]; | |
235 | + // PNGで保存 | |
236 | + NSData *tiffData = imageRef.TIFFRepresentation; | |
237 | + if(!tiffData) { | |
238 | + fprintf(stderr, "Can not create tiff image.\n"); | |
239 | + return; | |
240 | + } | |
241 | + | |
242 | + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:tiffData]; | |
243 | + NSData *pndData = [rep representationUsingType:NSPNGFileType | |
244 | + properties:@{}]; | |
245 | + NSString *path = [NSString stringWithFormat:@"%@-%d.png", sOriginalName, tagCount]; | |
246 | + path = [sCurrentDir stringByAppendingPathComponent:path]; | |
247 | + NSURL *url = [NSURL fileURLWithPath:path]; | |
248 | + [pndData writeToURL:url atomically:YES]; | |
249 | +} | |
250 | + | |
130 | 251 | int main(int argc, const char * argv[]) { |
131 | 252 | @autoreleasepool { |
132 | 253 | NSProcessInfo *pInfo = [NSProcessInfo processInfo]; |
@@ -178,6 +299,7 @@ int main(int argc, const char * argv[]) { | ||
178 | 299 | printLog("size -> %u (%x)\n", size, size); |
179 | 300 | int offset = size * 4; |
180 | 301 | offset += 5; // 上位5bit分 |
302 | + // bit -> byte | |
181 | 303 | int div = offset / 8; |
182 | 304 | int mod = offset % 8; |
183 | 305 | offset = div + (mod == 0 ? 0 : 1); // アライメント |
@@ -185,15 +307,11 @@ int main(int argc, const char * argv[]) { | ||
185 | 307 | p += offset; |
186 | 308 | |
187 | 309 | // fps: 8.8 fixed number. |
188 | - UInt8 fpsE = *(UInt8 *)p; | |
189 | - p += 1; | |
190 | - UInt8 fps = *(UInt8 *)p; | |
191 | - p += 1; | |
192 | - printLog("fps -> %u.%u\n", fps, fpsE); | |
310 | + printLog("fps -> %u.%u\n", *(UInt8 *)(p + 1), *(UInt8 *)p); | |
311 | + p += 2; | |
193 | 312 | |
194 | 313 | // frame count |
195 | - UInt16 frameCount = *(UInt16 *)p; | |
196 | - printLog("frame count -> %u\n", frameCount); | |
314 | + printLog("frame count -> %u\n", *(UInt16 *)p); | |
197 | 315 | p += 2; |
198 | 316 | |
199 | 317 | // タグの処理開始 |
@@ -224,13 +342,17 @@ int main(int argc, const char * argv[]) { | ||
224 | 342 | break; |
225 | 343 | case 35: |
226 | 344 | @autoreleasepool { |
227 | - storeDefineBitsJPEG3(p, length, tagCount); | |
345 | + storeBitsJPEG3(p, length, tagCount); | |
346 | + } | |
347 | + break; | |
348 | + case 36: | |
349 | + @autoreleasepool { | |
350 | + storeBitsLossless2(p, length, tagCount); | |
228 | 351 | } |
229 | 352 | break; |
230 | 353 | case 8: |
231 | 354 | case 21: |
232 | 355 | case 20: |
233 | - case 36: | |
234 | 356 | case 90: |
235 | 357 | @autoreleasepool { |
236 | 358 | storeImage(p, length, tagCount); |