swfから画像を抽出するコマンドラインアプリケーション
Revision | c22ebeb481b9fc2c31fc951fd9c58b5294b1966f (tree) |
---|---|
Time | 2017-03-05 18:21:37 |
Author | masakih <masakih@user...> |
Commiter | masakih |
マルチスレッド化した
@@ -12,10 +12,24 @@ | ||
12 | 12 | |
13 | 13 | #include <getopt.h> |
14 | 14 | |
15 | -static NSString *sOutputDir = nil; | |
16 | -static NSString *sOriginalName = nil; | |
17 | 15 | |
18 | -static NSArray *sCharactorIds = nil; | |
16 | +@interface Information: NSObject | |
17 | +@property (copy) NSString *originalName; | |
18 | +@property (copy) NSString *outputDir; | |
19 | +@property (copy) NSString *filename; | |
20 | +@property (copy) NSArray *charctorIds; | |
21 | +@end | |
22 | + | |
23 | +@implementation Information | |
24 | +- (bool)skipCharactorID:(UInt16) chractorid { | |
25 | + if(self.charctorIds.count == 0) return false; | |
26 | + | |
27 | + for(NSString *charID in self.charctorIds) { | |
28 | + if(charID.integerValue == chractorid) return false; | |
29 | + } | |
30 | + return true; | |
31 | +} | |
32 | +@end | |
19 | 33 | |
20 | 34 | #if 0 |
21 | 35 | #define printLog(...) printLogF( __VA_ARGS__) |
@@ -38,7 +52,6 @@ void printHex(const unsigned char *p) { | ||
38 | 52 | } |
39 | 53 | } |
40 | 54 | |
41 | - | |
42 | 55 | enum { |
43 | 56 | tagBits = 6, |
44 | 57 | tagJPEGTables = 8, // not supported |
@@ -81,23 +94,14 @@ static void version() | ||
81 | 94 | exit(EXIT_SUCCESS); |
82 | 95 | } |
83 | 96 | |
84 | -bool skipCharactorID(UInt16 chractorid) { | |
85 | - if(sCharactorIds.count == 0) return false; | |
86 | - | |
87 | - for(NSString *charID in sCharactorIds) { | |
88 | - if(charID.integerValue == chractorid) return false; | |
89 | - } | |
90 | - return true; | |
91 | -} | |
92 | - | |
93 | -void saveDataWithExtension(id data, NSString *extention, UInt16 charactorID) { | |
94 | - NSString *path = [NSString stringWithFormat:@"%@-%d.%@", sOriginalName, charactorID, extention]; | |
95 | - path = [sOutputDir stringByAppendingPathComponent:path]; | |
97 | +void saveDataWithExtension(Information *info, id data, NSString *extention, UInt16 charactorID) { | |
98 | + NSString *path = [NSString stringWithFormat:@"%@-%d.%@", info.originalName, charactorID, extention]; | |
99 | + path = [info.outputDir stringByAppendingPathComponent:path]; | |
96 | 100 | NSURL *url = [NSURL fileURLWithPath:path]; |
97 | 101 | [data writeToURL:url atomically:YES]; |
98 | 102 | } |
99 | 103 | |
100 | -void saveImageAsPNG(id image, UInt16 charactorID) { | |
104 | +void saveImageAsPNG(Information *info, id image, UInt16 charactorID) { | |
101 | 105 | NSData *tiffData = [image TIFFRepresentation]; |
102 | 106 | if(!tiffData) { |
103 | 107 | fprintf(stderr, "Can not create TIFF representation.\n"); |
@@ -107,14 +111,14 @@ void saveImageAsPNG(id image, UInt16 charactorID) { | ||
107 | 111 | NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:tiffData]; |
108 | 112 | NSData *imageData = [rep representationUsingType:NSPNGFileType |
109 | 113 | properties:@{}]; |
110 | - saveDataWithExtension(imageData, @"png", charactorID); | |
114 | + saveDataWithExtension(info, imageData, @"png", charactorID); | |
111 | 115 | } |
112 | 116 | |
113 | -void storeImage(const unsigned char *p, UInt32 length, UInt16 charactorID) { | |
117 | +void storeImage(Information *info, const unsigned char *p, UInt32 length, UInt16 charactorID) { | |
114 | 118 | printLog("#### TYPE IS PICTURE ####\n\n"); |
115 | 119 | |
116 | 120 | printLog("CaractorID is %d\n", charactorID); |
117 | - if(skipCharactorID(charactorID)) return; | |
121 | + if([info skipCharactorID:charactorID]) return; | |
118 | 122 | |
119 | 123 | if(length == 0) return; |
120 | 124 |
@@ -125,10 +129,10 @@ void storeImage(const unsigned char *p, UInt32 length, UInt16 charactorID) { | ||
125 | 129 | return; |
126 | 130 | } |
127 | 131 | |
128 | - saveDataWithExtension(pic, @"jpg", charactorID); | |
132 | + saveDataWithExtension(info, pic, @"jpg", charactorID); | |
129 | 133 | } |
130 | 134 | |
131 | -void storeBitsJPEG3(const unsigned char *p, UInt32 length) { | |
135 | +void storeBitsJPEG3(Information *info, const unsigned char *p, UInt32 length) { | |
132 | 136 | printLog("#### TYPE IS PICTURE ####\n\n"); |
133 | 137 | if(length < HMSWFJPEG3HeaderSize) return; |
134 | 138 |
@@ -136,14 +140,14 @@ void storeBitsJPEG3(const unsigned char *p, UInt32 length) { | ||
136 | 140 | |
137 | 141 | UInt16 charactorID = bitsJPEG3->charctorID; |
138 | 142 | printLog("CaractorID is %d\n", charactorID); |
139 | - if(skipCharactorID(charactorID)) return; | |
143 | + if([info skipCharactorID:charactorID]) return; | |
140 | 144 | |
141 | 145 | UInt32 contentLength = length - HMSWFJPEG3HeaderSize; |
142 | 146 | UInt32 imageSize = bitsJPEG3->imageSize; |
143 | 147 | p = &bitsJPEG3->imageData; |
144 | 148 | |
145 | 149 | if(imageSize == contentLength) { |
146 | - storeImage(p, contentLength, charactorID); | |
150 | + storeImage(info, p, contentLength, charactorID); | |
147 | 151 | return; |
148 | 152 | } |
149 | 153 |
@@ -178,32 +182,33 @@ void storeBitsJPEG3(const unsigned char *p, UInt32 length) { | ||
178 | 182 | } |
179 | 183 | |
180 | 184 | // 透過画像の作成 |
181 | - NSImage *image = [[NSImage alloc] initWithSize:size]; | |
182 | - [image lockFocus]; | |
183 | - { | |
184 | - NSRect rect = NSMakeRect(0, 0, size.width, size.height); | |
185 | - | |
186 | - CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; | |
187 | - CGContextSaveGState(context); | |
188 | - CGContextClipToMask(context, NSRectToCGRect(rect), alphaImageRef.CGImage); | |
189 | - [pict drawAtPoint:NSZeroPoint | |
190 | - fromRect:rect | |
191 | - operation:NSCompositeCopy | |
192 | - fraction:1.0]; | |
193 | - | |
194 | - CGContextRestoreGState(context); | |
195 | - } | |
196 | - [image unlockFocus]; | |
197 | - | |
198 | - saveImageAsPNG(image, charactorID); | |
185 | + NSImage *image = [NSImage imageWithSize:size | |
186 | + flipped:NO | |
187 | + drawingHandler: | |
188 | + ^BOOL(NSRect dstRect) { | |
189 | + NSRect rect = NSMakeRect(0, 0, size.width, size.height); | |
190 | + | |
191 | + CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; | |
192 | + CGContextSaveGState(context); | |
193 | + CGContextClipToMask(context, NSRectToCGRect(rect), alphaImageRef.CGImage); | |
194 | + [pict drawAtPoint:NSZeroPoint | |
195 | + fromRect:rect | |
196 | + operation:NSCompositeCopy | |
197 | + fraction:1.0]; | |
198 | + CGContextRestoreGState(context); | |
199 | + | |
200 | + return YES; | |
201 | + }]; | |
202 | + | |
203 | + saveImageAsPNG(info, image, charactorID); | |
199 | 204 | } |
200 | 205 | |
201 | -void storeBitLossless2ColorTable(const unsigned char *p, UInt32 length) { | |
206 | +void storeBitLossless2ColorTable(Information *info, const unsigned char *p, UInt32 length) { | |
202 | 207 | const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)p; |
203 | 208 | |
204 | 209 | UInt16 charactorID = data->charctorID; |
205 | 210 | printLog("CaractorID is %d\n", charactorID); |
206 | - if(skipCharactorID(charactorID)) return; | |
211 | + if([info skipCharactorID:charactorID]) return; | |
207 | 212 | |
208 | 213 | UInt8 mapSize = data->data.colorTable.colorTableSize + 1; |
209 | 214 | printLog("color table size -> %d\n", mapSize); |
@@ -265,9 +270,9 @@ void storeBitLossless2ColorTable(const unsigned char *p, UInt32 length) { | ||
265 | 270 | return; |
266 | 271 | } |
267 | 272 | |
268 | - saveImageAsPNG(imageRef, charactorID); | |
273 | + saveImageAsPNG(info, imageRef, charactorID); | |
269 | 274 | } |
270 | -void storeBitsLossless2(const unsigned char *p, UInt32 length) { | |
275 | +void storeBitsLossless2(Information *info, const unsigned char *p, UInt32 length) { | |
271 | 276 | printLog("#### TYPE IS PICTURE ####\n\n"); |
272 | 277 | if(length < HMSWFLossless2HeaderSize) { |
273 | 278 | fprintf(stderr, "length is too short.\n"); |
@@ -278,10 +283,10 @@ void storeBitsLossless2(const unsigned char *p, UInt32 length) { | ||
278 | 283 | |
279 | 284 | UInt16 charactorID = data->charctorID; |
280 | 285 | printLog("CaractorID is %d\n", charactorID); |
281 | - if(skipCharactorID(charactorID)) return; | |
286 | + if([info skipCharactorID:charactorID]) return; | |
282 | 287 | |
283 | 288 | if(data->bitmapFormat == 3) { |
284 | - storeBitLossless2ColorTable(p, length); | |
289 | + storeBitLossless2ColorTable(info, p, length); | |
285 | 290 | return; |
286 | 291 | } |
287 | 292 |
@@ -301,12 +306,11 @@ void storeBitsLossless2(const unsigned char *p, UInt32 length) { | ||
301 | 306 | colorSpaceName:NSCalibratedRGBColorSpace |
302 | 307 | bytesPerRow:data->width * 4 |
303 | 308 | bitsPerPixel:0]; |
304 | - saveImageAsPNG(imageRef, charactorID); | |
309 | + saveImageAsPNG(info, imageRef, charactorID); | |
305 | 310 | } |
306 | 311 | |
307 | -void extractImagesFromSWFFile(const char *filename) { | |
308 | - | |
309 | - NSString *filePath = [NSString stringWithFormat:@"%s", filename]; | |
312 | +void extractImagesFromSWFFile(Information *info) { | |
313 | + NSString *filePath = info.filename; | |
310 | 314 | if(![filePath hasPrefix:@"/"]) { |
311 | 315 | NSFileManager *fm = [NSFileManager defaultManager]; |
312 | 316 | filePath = [fm.currentDirectoryPath stringByAppendingPathComponent:filePath]; |
@@ -315,12 +319,12 @@ void extractImagesFromSWFFile(const char *filename) { | ||
315 | 319 | NSURL *url = [NSURL fileURLWithPath:filePath]; |
316 | 320 | NSData *data = [NSData dataWithContentsOfURL:url]; |
317 | 321 | if(!data) { |
318 | - fprintf(stderr, "Can not open %s.\n", filename); | |
322 | + fprintf(stderr, "Can not open %s.\n", info.filename.UTF8String); | |
319 | 323 | return; |
320 | 324 | } |
321 | 325 | |
322 | - sOriginalName = [filePath lastPathComponent]; | |
323 | - sOriginalName = [sOriginalName stringByDeletingPathExtension]; | |
326 | + info.originalName = [filePath lastPathComponent]; | |
327 | + info.originalName = [info.originalName stringByDeletingPathExtension]; | |
324 | 328 | |
325 | 329 | printHex(data.bytes); |
326 | 330 |
@@ -333,11 +337,11 @@ void extractImagesFromSWFFile(const char *filename) { | ||
333 | 337 | printHex(data.bytes); |
334 | 338 | |
335 | 339 | if(header->type[0] != 'F' && header->type[0] != 'C') { |
336 | - fprintf(stderr, "File %s is not SWF.\n", filename); | |
340 | + fprintf(stderr, "File %s is not SWF.\n", info.filename.UTF8String); | |
337 | 341 | return; |
338 | 342 | } |
339 | 343 | if(header->type[1] != 'W' || header->type[2] != 'S') { |
340 | - fprintf(stderr, "File %s is not SWF.\n", filename); | |
344 | + fprintf(stderr, "File %s is not SWF.\n", info.filename.UTF8String); | |
341 | 345 | return; |
342 | 346 | } |
343 | 347 |
@@ -393,17 +397,17 @@ void extractImagesFromSWFFile(const char *filename) { | ||
393 | 397 | switch(tag) { |
394 | 398 | case tagBits: |
395 | 399 | @autoreleasepool { |
396 | - storeImage(p + 2, length - 2, *(UInt16 *)p); | |
400 | + storeImage(info, p + 2, length - 2, *(UInt16 *)p); | |
397 | 401 | } |
398 | 402 | break; |
399 | 403 | case tagBitsJPEG3: |
400 | 404 | @autoreleasepool { |
401 | - storeBitsJPEG3(p, length); | |
405 | + storeBitsJPEG3(info, p, length); | |
402 | 406 | } |
403 | 407 | break; |
404 | 408 | case tagBitsLossless2: |
405 | 409 | @autoreleasepool { |
406 | - storeBitsLossless2(p, length); | |
410 | + storeBitsLossless2(info, p, length); | |
407 | 411 | } |
408 | 412 | break; |
409 | 413 | case tagBitsJPEG2: |
@@ -428,8 +432,11 @@ void extractImagesFromSWFFile(const char *filename) { | ||
428 | 432 | } |
429 | 433 | |
430 | 434 | int main(int argc, char * const *argv) { |
435 | + | |
436 | + NSString *outputDir = nil; | |
437 | + NSArray *charactorIds = nil; | |
438 | + | |
431 | 439 | @autoreleasepool { |
432 | - | |
433 | 440 | // 引数の処理 |
434 | 441 | int opt; |
435 | 442 | char *oFilename = NULL; |
@@ -471,34 +478,42 @@ int main(int argc, char * const *argv) { | ||
471 | 478 | } |
472 | 479 | |
473 | 480 | if(oFilename) { |
474 | - sOutputDir = [NSString stringWithFormat:@"%s", oFilename]; | |
481 | + outputDir = [NSString stringWithFormat:@"%s", oFilename]; | |
475 | 482 | NSFileManager *fm = [NSFileManager defaultManager]; |
476 | 483 | BOOL isDir = NO; |
477 | - if(![fm fileExistsAtPath:sOutputDir isDirectory:&isDir] || !isDir) { | |
478 | - fprintf(stderr, "Output directory:%s is not found or not directory.", sOutputDir.fileSystemRepresentation); | |
484 | + if(![fm fileExistsAtPath:outputDir isDirectory:&isDir] || !isDir) { | |
485 | + fprintf(stderr, "Output directory:%s is not found or not directory.", outputDir.fileSystemRepresentation); | |
479 | 486 | exit(EXIT_FAILURE); |
480 | 487 | } |
481 | 488 | } else { |
482 | 489 | NSFileManager *fm = [NSFileManager defaultManager]; |
483 | - sOutputDir = fm.currentDirectoryPath; | |
490 | + outputDir = fm.currentDirectoryPath; | |
484 | 491 | } |
485 | 492 | |
486 | 493 | if(charactorid) { |
487 | 494 | NSString *charactoridsString = [NSString stringWithFormat:@"%s", charactorid]; |
488 | 495 | NSArray *ids = [charactoridsString componentsSeparatedByString:@","]; |
489 | 496 | if(ids.count != 0) { |
490 | - sCharactorIds = ids; | |
491 | - | |
497 | + charactorIds = ids; | |
492 | 498 | |
493 | 499 | printLog("CaractorIDs is %s\n", [NSString stringWithFormat:@"%@", ids].fileSystemRepresentation); |
494 | 500 | } |
495 | 501 | } |
496 | - | |
502 | + | |
503 | + dispatch_group_t group = dispatch_group_create(); | |
504 | + dispatch_queue_t queue = dispatch_queue_create("Create image", DISPATCH_QUEUE_CONCURRENT); | |
497 | 505 | for(int filePos = optind; filePos < argc; filePos++) { |
498 | 506 | const char *filename = argv[filePos]; |
507 | + Information *info = [Information new]; | |
508 | + info.outputDir = outputDir; | |
509 | + info.charctorIds = charactorIds; | |
510 | + info.filename = [NSString stringWithFormat:@"%s", filename]; | |
499 | 511 | |
500 | - extractImagesFromSWFFile(filename); | |
512 | + dispatch_group_async(group, queue, ^{ | |
513 | + extractImagesFromSWFFile(info); | |
514 | + }); | |
501 | 515 | } |
516 | + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); | |
502 | 517 | } |
503 | 518 | return 0; |
504 | 519 | } |