masakih

KanColleGraphicDivider

  • R/O
  • HTTP
  • SSH
  • HTTPS

コミット

よく使われているワード(クリックで追加)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

swfから画像を抽出するコマンドラインアプリケーション


コミットメタ情報

リビジョン567e844c19e6f45dbcfab79a5cd5e895e77bb79a (tree)
日時2018-05-21 23:04:29
作者Hori,Masaki <nandekka@popp...>
コミッターGitHub

ログメッセージ

Object Oriented

変更サマリ

差分

--- a/KanColleGraphicDivider.xcodeproj/project.pbxproj
+++ b/KanColleGraphicDivider.xcodeproj/project.pbxproj
@@ -9,6 +9,15 @@
99 /* Begin PBXBuildFile section */
1010 F44C14BB1D84F07300ADE497 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F44C14BA1D84F07300ADE497 /* main.m */; };
1111 F44C14C41D85083E00ADE497 /* HMZlibData.m in Sources */ = {isa = PBXBuildFile; fileRef = F44C14C31D85083E00ADE497 /* HMZlibData.m */; };
12+ F490569020B050D400CF637D /* BitsLossless2Decoder.m in Sources */ = {isa = PBXBuildFile; fileRef = F490568F20B050D400CF637D /* BitsLossless2Decoder.m */; };
13+ F490569320B0512C00CF637D /* Information.m in Sources */ = {isa = PBXBuildFile; fileRef = F490569220B0512C00CF637D /* Information.m */; };
14+ F490569620B0568F00CF637D /* ImageStorer.m in Sources */ = {isa = PBXBuildFile; fileRef = F490569520B0568F00CF637D /* ImageStorer.m */; };
15+ F490569A20B059B800CF637D /* BitLossless2ColorTableDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = F490569920B059B800CF637D /* BitLossless2ColorTableDecoder.m */; };
16+ F490569D20B05B9400CF637D /* BitsJPEG3Decoder.m in Sources */ = {isa = PBXBuildFile; fileRef = F490569C20B05B9400CF637D /* BitsJPEG3Decoder.m */; };
17+ F49056A320B0789B00CF637D /* SwfContent.m in Sources */ = {isa = PBXBuildFile; fileRef = F49056A220B0789B00CF637D /* SwfContent.m */; };
18+ F49056A620B078DB00CF637D /* SwfData.m in Sources */ = {isa = PBXBuildFile; fileRef = F49056A520B078DB00CF637D /* SwfData.m */; };
19+ F49056A920B0794400CF637D /* SwfHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = F49056A820B0794400CF637D /* SwfHeader.m */; };
20+ F49056B020B16A6D00CF637D /* BitsDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = F49056AF20B16A6D00CF637D /* BitsDecoder.m */; };
1221 /* End PBXBuildFile section */
1322
1423 /* Begin PBXCopyFilesBuildPhase section */
@@ -29,6 +38,26 @@
2938 F44C14C11D84F27500ADE497 /* SWFStructure.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SWFStructure.h; sourceTree = "<group>"; };
3039 F44C14C21D85083E00ADE497 /* HMZlibData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HMZlibData.h; sourceTree = "<group>"; };
3140 F44C14C31D85083E00ADE497 /* HMZlibData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HMZlibData.m; sourceTree = "<group>"; };
41+ F490568D20B04F5300CF637D /* ImageDecoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageDecoder.h; sourceTree = "<group>"; };
42+ F490568E20B050D400CF637D /* BitsLossless2Decoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitsLossless2Decoder.h; sourceTree = "<group>"; };
43+ F490568F20B050D400CF637D /* BitsLossless2Decoder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BitsLossless2Decoder.m; sourceTree = "<group>"; };
44+ F490569120B0512C00CF637D /* Information.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Information.h; sourceTree = "<group>"; };
45+ F490569220B0512C00CF637D /* Information.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Information.m; sourceTree = "<group>"; };
46+ F490569420B0568F00CF637D /* ImageStorer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageStorer.h; sourceTree = "<group>"; };
47+ F490569520B0568F00CF637D /* ImageStorer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImageStorer.m; sourceTree = "<group>"; };
48+ F490569720B0584600CF637D /* KanColleGraphicDivider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KanColleGraphicDivider.h; sourceTree = "<group>"; };
49+ F490569820B059B800CF637D /* BitLossless2ColorTableDecoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitLossless2ColorTableDecoder.h; sourceTree = "<group>"; };
50+ F490569920B059B800CF637D /* BitLossless2ColorTableDecoder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BitLossless2ColorTableDecoder.m; sourceTree = "<group>"; };
51+ F490569B20B05B9400CF637D /* BitsJPEG3Decoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitsJPEG3Decoder.h; sourceTree = "<group>"; };
52+ F490569C20B05B9400CF637D /* BitsJPEG3Decoder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BitsJPEG3Decoder.m; sourceTree = "<group>"; };
53+ F49056A120B0789B00CF637D /* SwfContent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwfContent.h; sourceTree = "<group>"; };
54+ F49056A220B0789B00CF637D /* SwfContent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SwfContent.m; sourceTree = "<group>"; };
55+ F49056A420B078DB00CF637D /* SwfData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwfData.h; sourceTree = "<group>"; };
56+ F49056A520B078DB00CF637D /* SwfData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SwfData.m; sourceTree = "<group>"; };
57+ F49056A720B0794400CF637D /* SwfHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwfHeader.h; sourceTree = "<group>"; };
58+ F49056A820B0794400CF637D /* SwfHeader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SwfHeader.m; sourceTree = "<group>"; };
59+ F49056AE20B16A6C00CF637D /* BitsDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitsDecoder.h; sourceTree = "<group>"; };
60+ F49056AF20B16A6D00CF637D /* BitsDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BitsDecoder.m; sourceTree = "<group>"; };
3261 /* End PBXFileReference section */
3362
3463 /* Begin PBXFrameworksBuildPhase section */
@@ -61,7 +90,27 @@
6190 F44C14B91D84F07300ADE497 /* KanColleGraphicDivider */ = {
6291 isa = PBXGroup;
6392 children = (
93+ F490569720B0584600CF637D /* KanColleGraphicDivider.h */,
6494 F44C14BA1D84F07300ADE497 /* main.m */,
95+ F49056A420B078DB00CF637D /* SwfData.h */,
96+ F49056A520B078DB00CF637D /* SwfData.m */,
97+ F49056A720B0794400CF637D /* SwfHeader.h */,
98+ F49056A820B0794400CF637D /* SwfHeader.m */,
99+ F49056A120B0789B00CF637D /* SwfContent.h */,
100+ F49056A220B0789B00CF637D /* SwfContent.m */,
101+ F490569120B0512C00CF637D /* Information.h */,
102+ F490569220B0512C00CF637D /* Information.m */,
103+ F490569420B0568F00CF637D /* ImageStorer.h */,
104+ F490569520B0568F00CF637D /* ImageStorer.m */,
105+ F490568D20B04F5300CF637D /* ImageDecoder.h */,
106+ F49056AE20B16A6C00CF637D /* BitsDecoder.h */,
107+ F49056AF20B16A6D00CF637D /* BitsDecoder.m */,
108+ F490568E20B050D400CF637D /* BitsLossless2Decoder.h */,
109+ F490568F20B050D400CF637D /* BitsLossless2Decoder.m */,
110+ F490569820B059B800CF637D /* BitLossless2ColorTableDecoder.h */,
111+ F490569920B059B800CF637D /* BitLossless2ColorTableDecoder.m */,
112+ F490569B20B05B9400CF637D /* BitsJPEG3Decoder.h */,
113+ F490569C20B05B9400CF637D /* BitsJPEG3Decoder.m */,
65114 F44C14C11D84F27500ADE497 /* SWFStructure.h */,
66115 F44C14C21D85083E00ADE497 /* HMZlibData.h */,
67116 F44C14C31D85083E00ADE497 /* HMZlibData.m */,
@@ -125,8 +174,17 @@
125174 isa = PBXSourcesBuildPhase;
126175 buildActionMask = 2147483647;
127176 files = (
177+ F490569620B0568F00CF637D /* ImageStorer.m in Sources */,
178+ F490569020B050D400CF637D /* BitsLossless2Decoder.m in Sources */,
179+ F49056A320B0789B00CF637D /* SwfContent.m in Sources */,
180+ F49056B020B16A6D00CF637D /* BitsDecoder.m in Sources */,
181+ F490569A20B059B800CF637D /* BitLossless2ColorTableDecoder.m in Sources */,
128182 F44C14BB1D84F07300ADE497 /* main.m in Sources */,
183+ F49056A920B0794400CF637D /* SwfHeader.m in Sources */,
184+ F490569D20B05B9400CF637D /* BitsJPEG3Decoder.m in Sources */,
185+ F490569320B0512C00CF637D /* Information.m in Sources */,
129186 F44C14C41D85083E00ADE497 /* HMZlibData.m in Sources */,
187+ F49056A620B078DB00CF637D /* SwfData.m in Sources */,
130188 );
131189 runOnlyForDeploymentPostprocessing = 0;
132190 };
@@ -249,6 +307,7 @@
249307 F44C14C01D84F07300ADE497 /* Release */,
250308 );
251309 defaultConfigurationIsVisible = 0;
310+ defaultConfigurationName = Release;
252311 };
253312 /* End XCConfigurationList section */
254313 };
--- /dev/null
+++ b/KanColleGraphicDivider.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>IDEDidComputeMac32BitWarning</key>
6+ <true/>
7+</dict>
8+</plist>
--- /dev/null
+++ b/KanColleGraphicDivider/BitLossless2ColorTableDecoder.h
@@ -0,0 +1,15 @@
1+//
2+// BitLossless2ColorTableDecoder.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+#import "ImageDecoder.h"
12+
13+@interface BitLossless2ColorTableDecoder : NSObject <ImageDecoder>
14+
15+@end
--- /dev/null
+++ b/KanColleGraphicDivider/BitLossless2ColorTableDecoder.m
@@ -0,0 +1,114 @@
1+//
2+// BitLossless2ColorTableDecoder.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "BitLossless2ColorTableDecoder.h"
10+
11+#include "KanColleGraphicDivider.h"
12+#import "ImageStorer.h"
13+
14+#import "HMZlibData.h"
15+
16+@interface BitLossless2ColorTableDecoder()
17+
18+@property NSData *data;
19+
20+@property (readonly) NSUInteger length;
21+
22+@end
23+
24+@implementation BitLossless2ColorTableDecoder
25+
26++ (instancetype)decoderWithData:(NSData *)data {
27+
28+ return [[self alloc] initWithData:data];
29+}
30+
31+- (instancetype)initWithData:(NSData *)data {
32+
33+ self = [super init];
34+
35+ if( self ) {
36+
37+ self.data = data;
38+ }
39+
40+ return self;
41+}
42+
43+- (NSUInteger)length {
44+
45+ return self.data.length;
46+}
47+
48+- (void)decodeUsingInformationn:(Information *)information {
49+
50+ saveDataWithExtension(information, self.decodedData, self.extension, self.charactorID);
51+}
52+
53+- (UInt32) charactorID {
54+
55+ const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)self.data.bytes;
56+
57+ return data->charctorID;
58+}
59+
60+- (NSData *)decodedData {
61+
62+ const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)self.data.bytes;
63+
64+ UInt8 mapSize = data->data.colorTable.colorTableSize + 1;
65+
66+ NSData *zipedContentData = [NSData dataWithBytes:&data->data.colorTable.data length:self.length - HMSWFLossless2ColorTableHeaderSize];
67+ NSData *contentData = [zipedContentData inflate];
68+
69+ const UInt32 *mapP = (UInt32 *)contentData.bytes;
70+ const UInt8 *colorIndexP = (UInt8 *)(mapP + mapSize);
71+
72+ // rowサイズは4bytesアライメント
73+ UInt8 skipBytes = data->width % 4;
74+
75+ // ARGBカラーマップからARGBビットマップを作成
76+ UInt32 *imageDataP = calloc(4, data->width * data->height);
77+ if(!imageDataP) {
78+ fprintf(stderr, "Can not allocate enough memory.\n");
79+ return nil;
80+ }
81+
82+ UInt32 *imageDataPixel = imageDataP;
83+ for(UInt16 h = 0; h < data->height; h++) {
84+ for(UInt16 w = 0; w < data->width; w++) {
85+ *imageDataPixel++ = mapP[*colorIndexP++];
86+ }
87+ colorIndexP += skipBytes;
88+ }
89+
90+ // ARGBビットマップからNSBitmapImageRepを作成
91+ NSData *imageData = [NSData dataWithBytes:imageDataP length:4 * data->width * data->height];
92+ unsigned char *pp = (unsigned char *)imageData.bytes;
93+ NSBitmapImageRep *imageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp
94+ pixelsWide:data->width
95+ pixelsHigh:data->height
96+ bitsPerSample:8
97+ samplesPerPixel:4
98+ hasAlpha:YES
99+ isPlanar:NO
100+ colorSpaceName:NSCalibratedRGBColorSpace
101+ bytesPerRow:data->width * 4
102+ bitsPerPixel:0];
103+ free(imageDataP);
104+ imageDataP = NULL;
105+
106+ return convertImagaData(imageRef);
107+}
108+
109+- (NSString *)extension {
110+
111+ return @"png";
112+}
113+
114+@end
--- /dev/null
+++ b/KanColleGraphicDivider/BitsDecoder.h
@@ -0,0 +1,15 @@
1+//
2+// BitsDecoder.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+#import "ImageDecoder.h"
12+
13+@interface BitsDecoder : NSObject <ImageDecoder>
14+
15+@end
--- /dev/null
+++ b/KanColleGraphicDivider/BitsDecoder.m
@@ -0,0 +1,74 @@
1+//
2+// BitsDecoder.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "BitsDecoder.h"
10+
11+#import "ImageStorer.h"
12+
13+@interface BitsDecoder()
14+
15+@property NSData *data;
16+
17+@property (readonly) NSUInteger length;
18+
19+@end
20+
21+@implementation BitsDecoder
22+
23++ (instancetype)decoderWithData:(NSData *)data {
24+
25+ return [[self alloc] initWithData:data];
26+}
27+
28+- (instancetype)initWithData:(NSData *)data {
29+
30+ self = [super init];
31+
32+ if( self ) {
33+
34+ self.data = data;
35+ }
36+
37+ return self;
38+}
39+
40+- (NSUInteger)length {
41+
42+ return self.data.length;
43+}
44+
45+- (void)decodeUsingInformationn:(Information *)information {
46+
47+ saveDataWithExtension(information, self.decodedData, self.extension, self.charactorID);
48+}
49+
50+- (UInt32) charactorID {
51+
52+ return *(UInt16 *)self.data.bytes;
53+}
54+
55+- (NSData *)decodedData {
56+
57+ NSData *contentData = [self.data subdataWithRange:NSMakeRange(2, self.length - 2)];
58+ if(contentData.length == 0) return nil;
59+
60+ NSImage *pict = [[NSImage alloc] initWithData:contentData];
61+ if(!pict) {
62+ fprintf(stderr, "Can not create image from data.\n");
63+ return nil;
64+ }
65+
66+ return contentData;
67+}
68+
69+- (NSString *)extension {
70+
71+ return @"jpg";
72+}
73+
74+@end
--- /dev/null
+++ b/KanColleGraphicDivider/BitsJPEG3Decoder.h
@@ -0,0 +1,15 @@
1+//
2+// BitsJPEG3Decoder.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+#import "ImageDecoder.h"
12+
13+@interface BitsJPEG3Decoder : NSObject <ImageDecoder>
14+
15+@end
--- /dev/null
+++ b/KanColleGraphicDivider/BitsJPEG3Decoder.m
@@ -0,0 +1,136 @@
1+//
2+// BitsJPEG3Decoder.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "BitsJPEG3Decoder.h"
10+
11+#include "KanColleGraphicDivider.h"
12+#import "ImageStorer.h"
13+
14+#import "BitsDecoder.h"
15+
16+#import "HMZlibData.h"
17+
18+@interface BitsJPEG3Decoder()
19+
20+@property NSData *data;
21+
22+@property (readonly) NSUInteger length;
23+
24+@end
25+
26+@implementation BitsJPEG3Decoder
27+
28++ (instancetype)decoderWithData:(NSData *)data {
29+
30+ return [[self alloc] initWithData:data];
31+}
32+
33+- (instancetype)initWithData:(NSData *)data {
34+
35+ self = [super init];
36+
37+ if( self ) {
38+
39+ self.data = data;
40+ }
41+
42+ return self;
43+}
44+
45+- (NSUInteger)length {
46+
47+ return self.data.length;
48+}
49+
50+- (void)decodeUsingInformationn:(Information *)information {
51+
52+ saveDataWithExtension(information, self.decodedData, self.extension, self.charactorID);
53+}
54+
55+- (UInt32) charactorID {
56+
57+ const HMSWFBitsJPEG3 *data = (HMSWFBitsJPEG3 *)self.data.bytes;
58+
59+ return data->charctorID;
60+}
61+
62+- (NSData *)decodedData {
63+
64+ const unsigned char *p = self.data.bytes;
65+
66+ if(self.length < HMSWFJPEG3HeaderSize) return nil;
67+
68+ const HMSWFBitsJPEG3 *bitsJPEG3 = (HMSWFBitsJPEG3 *)p;
69+
70+ NSUInteger contentLength = self.length - HMSWFJPEG3HeaderSize;
71+ NSUInteger imageSize = bitsJPEG3->imageSize;
72+ p = &bitsJPEG3->imageData;
73+
74+ if(imageSize == contentLength) {
75+
76+ return [[BitsDecoder decoderWithData:self.data] object];
77+ }
78+
79+ // JPEGを取出し
80+ NSData *pic = [NSData dataWithBytes:p length:imageSize];
81+ NSImage *pict = [[NSImage alloc] initWithData:pic];
82+ if(!pict) {
83+ fprintf(stderr, "Can not create image from data.\n");
84+ return nil;
85+ }
86+
87+ NSSize size = pict.size;
88+
89+ // アルファチャンネルの取出し
90+ NSData *alpha = [NSData dataWithBytes:p + imageSize length:contentLength - imageSize];
91+ alpha = [alpha inflate];
92+
93+ unsigned char *pp = (unsigned char *)alpha.bytes;
94+ NSBitmapImageRep *alphaImageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp
95+ pixelsWide:size.width
96+ pixelsHigh:size.height
97+ bitsPerSample:8
98+ samplesPerPixel:1
99+ hasAlpha:NO
100+ isPlanar:NO
101+ colorSpaceName:NSDeviceWhiteColorSpace
102+ bytesPerRow:size.width
103+ bitsPerPixel:0];
104+ if(!alphaImageRef) {
105+ fprintf(stderr, "Can not create alpha image from data.\n");
106+ return nil;
107+ }
108+
109+ // 透過画像の作成
110+ NSImage *image = [NSImage imageWithSize:size
111+ flipped:NO
112+ drawingHandler:
113+ ^BOOL(NSRect dstRect) {
114+ NSRect rect = NSMakeRect(0, 0, size.width, size.height);
115+
116+ CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
117+ CGContextSaveGState(context);
118+ CGContextClipToMask(context, NSRectToCGRect(rect), alphaImageRef.CGImage);
119+ [pict drawAtPoint:NSZeroPoint
120+ fromRect:rect
121+ operation:NSCompositeCopy
122+ fraction:1.0];
123+ CGContextRestoreGState(context);
124+
125+ return YES;
126+ }];
127+
128+ return convertImagaData(image);
129+}
130+
131+- (NSString *)extension {
132+
133+ return @"png";
134+}
135+
136+@end
--- /dev/null
+++ b/KanColleGraphicDivider/BitsLossless2Decoder.h
@@ -0,0 +1,15 @@
1+//
2+// BitsLossless2Decoder.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+#import "ImageDecoder.h"
12+
13+@interface BitsLossless2Decoder : NSObject <ImageDecoder>
14+
15+@end
--- /dev/null
+++ b/KanColleGraphicDivider/BitsLossless2Decoder.m
@@ -0,0 +1,97 @@
1+//
2+// BitsLossless2Decoder.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "BitsLossless2Decoder.h"
10+
11+#include "KanColleGraphicDivider.h"
12+#import "ImageStorer.h"
13+
14+#import "HMZlibData.h"
15+
16+#import "BitLossless2ColorTableDecoder.h"
17+
18+@interface BitsLossless2Decoder()
19+
20+@property NSData *data;
21+
22+@property (readonly) NSUInteger length;
23+
24+@end
25+
26+@implementation BitsLossless2Decoder
27+
28++ (instancetype)decoderWithData:(NSData *)data {
29+
30+ return [[self alloc] initWithData:data];
31+}
32+
33+- (instancetype)initWithData:(NSData *)data {
34+
35+ self = [super init];
36+
37+ if( self ) {
38+
39+ self.data = data;
40+ }
41+
42+ return self;
43+}
44+
45+- (NSUInteger)length {
46+
47+ return self.data.length;
48+}
49+
50+- (void)decodeUsingInformationn:(Information *)information {
51+
52+ saveDataWithExtension(information, self.decodedData, self.extension, self.charactorID);
53+}
54+
55+- (UInt32) charactorID {
56+
57+ const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)self.data.bytes;
58+
59+ return data->charctorID;
60+}
61+
62+- (NSData *)decodedData {
63+
64+ const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)self.data.bytes;
65+
66+ if(data->bitmapFormat == 3) {
67+
68+ id decoder = [BitLossless2ColorTableDecoder decoderWithData:self.data];
69+ return [decoder decodedData];
70+ }
71+
72+ NSUInteger cLength = self.length - HMSWFLossless2HeaderSize;
73+
74+ const unsigned char *p = &data->data.data;
75+ NSData *zipedImageData = [NSData dataWithBytes:p length:cLength];
76+ NSData *imageData = [zipedImageData inflate];
77+ unsigned char *pp = (unsigned char *)imageData.bytes;
78+ NSBitmapImageRep *imageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp
79+ pixelsWide:data->width
80+ pixelsHigh:data->height
81+ bitsPerSample:8 * 4
82+ samplesPerPixel:4
83+ hasAlpha:YES
84+ isPlanar:NO
85+ colorSpaceName:NSCalibratedRGBColorSpace
86+ bytesPerRow:data->width * 4
87+ bitsPerPixel:0];
88+
89+ return convertImagaData(imageRef);
90+}
91+
92+- (NSString *)extension {
93+
94+ return @"png";
95+}
96+
97+@end
--- /dev/null
+++ b/KanColleGraphicDivider/ImageDecoder.h
@@ -0,0 +1,21 @@
1+//
2+// ImageDecoder.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+
11+@protocol ImageDecoder <NSObject>
12+
13++ (id)decoderWithData:(NSData *)data;
14+
15+@property (readonly) UInt32 charactorID;
16+
17+@property (nullable, readonly) NSData *decodedData;
18+
19+@property (readonly) NSString *extension;
20+
21+@end
--- /dev/null
+++ b/KanColleGraphicDivider/ImageStorer.h
@@ -0,0 +1,14 @@
1+//
2+// ImageStorer.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+#import "Information.h"
11+
12+void saveDataWithExtension(Information *info, id data, NSString *extention, UInt16 charactorID);
13+
14+NSData *convertImagaData(id data);
--- /dev/null
+++ b/KanColleGraphicDivider/ImageStorer.m
@@ -0,0 +1,31 @@
1+//
2+// ImageStorer.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#include "KanColleGraphicDivider.h"
10+#import "ImageStorer.h"
11+
12+void saveDataWithExtension(Information *info, NSData *data, NSString *extention, UInt16 charactorID) {
13+
14+ NSString *path = [NSString stringWithFormat:@"%@-%d.%@", info.originalName, charactorID, extention];
15+ path = [info.outputDir stringByAppendingPathComponent:path];
16+ NSURL *url = [NSURL fileURLWithPath:path];
17+ [data writeToURL:url atomically:YES];
18+}
19+
20+NSData *convertImagaData(NSImage *image) {
21+
22+ NSData *tiffData = [image TIFFRepresentation];
23+ if(!tiffData) {
24+ fprintf(stderr, "Can not create TIFF representation.\n");
25+ return nil;
26+ }
27+
28+ NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:tiffData];
29+ return [rep representationUsingType:NSPNGFileType
30+ properties:@{}];
31+}
--- /dev/null
+++ b/KanColleGraphicDivider/Information.h
@@ -0,0 +1,19 @@
1+//
2+// Information.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+
11+@interface Information: NSObject
12+@property (copy) NSString *originalName;
13+@property (copy) NSString *outputDir;
14+@property (copy) NSString *filename;
15+@property (copy) NSArray *charctorIds;
16+
17+- (bool)skipCharactorID:(UInt16) chractorid;
18+
19+@end
--- /dev/null
+++ b/KanColleGraphicDivider/Information.m
@@ -0,0 +1,20 @@
1+//
2+// Information.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "Information.h"
10+
11+@implementation Information
12+- (bool)skipCharactorID:(UInt16) chractorid {
13+ if(self.charctorIds.count == 0) return false;
14+
15+ for(NSString *charID in self.charctorIds) {
16+ if(charID.integerValue == chractorid) return false;
17+ }
18+ return true;
19+}
20+@end
--- /dev/null
+++ b/KanColleGraphicDivider/KanColleGraphicDivider.h
@@ -0,0 +1,21 @@
1+//
2+// KanColleGraphicDivider.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/19.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#ifndef KanColleGraphicDivider_h
10+#define KanColleGraphicDivider_h
11+
12+#include "SWFStructure.h"
13+
14+#if 0
15+#define printLog(...) printLogF( __VA_ARGS__)
16+void printLogF(const char *fmt, ...);
17+#else
18+#define printLog(...)
19+#endif
20+
21+#endif /* KanColleGraphicDivider_h */
--- a/KanColleGraphicDivider/SWFStructure.h
+++ b/KanColleGraphicDivider/SWFStructure.h
@@ -9,6 +9,7 @@
99 #ifndef SWFStructure_h
1010 #define SWFStructure_h
1111
12+#import <MacTypes.h>
1213
1314 #pragma pack(1)
1415
--- /dev/null
+++ b/KanColleGraphicDivider/SwfContent.h
@@ -0,0 +1,23 @@
1+//
2+// SwfContent.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+
11+@interface SwfContent : NSObject
12+
13++ (nullable instancetype)contentWithData:(NSData *)data;
14+
15+@property NSRange nextRange;
16+
17+@property (nullable, readonly) SwfContent *next;
18+
19+@property (readonly) UInt32 charactorID;
20+@property (nullable, readonly) NSData *content;
21+@property (readonly) NSString *extension;
22+
23+@end
--- /dev/null
+++ b/KanColleGraphicDivider/SwfContent.m
@@ -0,0 +1,157 @@
1+//
2+// SwfContent.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "SwfContent.h"
10+
11+#import "BitsDecoder.h"
12+#import "BitsLossless2Decoder.h"
13+#import "BitsJPEG3Decoder.h"
14+
15+#include "SWFStructure.h"
16+
17+typedef enum : NSUInteger {
18+ tagBits = 6,
19+ tagJPEGTables = 8, // not supported
20+ tagBitsJPEG2 = 21, // not supported
21+ tagBitsJPEG3 = 35,
22+ tagBitsLossless = 20, // not supported
23+ tagBitsLossless2 = 36,
24+ tagBitsJPEG4 = 90, // not supported
25+} TagType;
26+
27+@interface SwfContent()
28+
29+@property (nonnull) NSData *data;
30+
31+//@property NSRange nextRange;
32+
33+@property TagType tagType;
34+@property (nullable) NSData *contentData;
35+@property (nullable, readwrite) id<ImageDecoder> decoder;
36+
37+@end
38+
39+@implementation SwfContent
40+
41++ (nullable instancetype)contentWithData:(NSData *)data {
42+
43+ return [[self alloc] initWithData:data];
44+
45+}
46+
47+- (nullable instancetype)initWithData:(NSData *)data {
48+
49+ self = [super init];
50+
51+ if( !data ) {
52+
53+ NSLog(@"SwfContent: Data is nil");
54+
55+ return nil;
56+ }
57+
58+ if( self ) {
59+
60+ self.data = data;
61+ self.nextRange = NSMakeRange(NSNotFound, 0);
62+
63+ if( ![self parse] ) {
64+
65+ NSLog(@"SwfContent: Parse Error");
66+
67+ return nil;
68+ }
69+ }
70+
71+ return self;
72+}
73+
74+- (SwfContent *)next {
75+
76+ if( self.nextRange.location == NSNotFound ) {
77+
78+ return nil;
79+ }
80+
81+ if( self.data.length < NSMaxRange(self.nextRange) ) {
82+
83+ NSLog(@"Next size is Overflow");
84+ exit(-10);
85+ }
86+
87+ return [SwfContent contentWithData:[self.data subdataWithRange:self.nextRange]];
88+}
89+
90+- (UInt32)charactorID {
91+
92+ return self.decoder.charactorID;
93+}
94+
95+- (NSData *)content {
96+
97+ return self.decoder.decodedData;
98+}
99+
100+- (NSString *)extension {
101+
102+ return self.decoder.extension;
103+}
104+
105+- (BOOL)parse {
106+
107+ HMSWFTag *tagP = (HMSWFTag *)self.data.bytes;
108+ NSUInteger tagLength = 2;
109+ self.tagType = tagP->tagAndLength >> 6;
110+ UInt32 contentLength = tagP->tagAndLength & 0x3F;
111+ if(contentLength == 0x3F) {
112+ contentLength = tagP->extraLength;
113+ tagLength += 4;
114+ }
115+
116+ if( self.tagType == 0 ) {
117+
118+ return YES;
119+ }
120+
121+ if( self.data.length < (tagLength + contentLength) ) {
122+
123+ NSLog(@"Content size is Overflow");
124+ exit(-10);
125+ }
126+ self.contentData = [self.data subdataWithRange:NSMakeRange(tagLength, contentLength)];
127+
128+ NSUInteger nextPos = tagLength + contentLength;
129+ NSUInteger length = self.data.length - nextPos;
130+ self.nextRange = NSMakeRange(nextPos, length);
131+
132+ switch (self.tagType) {
133+
134+ case tagBits:
135+
136+ self.decoder = [BitsDecoder decoderWithData:self.contentData];
137+ break;
138+
139+ case tagBitsJPEG3:
140+
141+ self.decoder = [BitsJPEG3Decoder decoderWithData:self.contentData];
142+ break;
143+
144+ case tagBitsLossless2:
145+
146+ self.decoder = [BitsLossless2Decoder decoderWithData:self.contentData];
147+ break;
148+
149+ default:
150+
151+ break;
152+ }
153+
154+ return YES;
155+}
156+
157+@end
--- /dev/null
+++ b/KanColleGraphicDivider/SwfData.h
@@ -0,0 +1,21 @@
1+//
2+// SwfData.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+
11+#import "SwfHeader.h"
12+#import "SwfContent.h"
13+
14+@interface SwfData : NSObject
15+
16++ (instancetype)dataWithData:(NSData *)data;
17+
18+@property (nullable, readonly) SwfHeader *header;
19+@property (nullable, readonly) SwfContent *firstContent;
20+
21+@end
--- /dev/null
+++ b/KanColleGraphicDivider/SwfData.m
@@ -0,0 +1,37 @@
1+//
2+// SwfData.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "SwfData.h"
10+
11+@interface SwfData()
12+
13+@property (nullable, readwrite) SwfHeader *header;
14+@property (nullable, readwrite) SwfContent *firstContent;
15+
16+@end
17+
18+@implementation SwfData
19+
20++ (instancetype)dataWithData:(NSData *)data {
21+
22+ return [[self alloc] initWithData:data];
23+}
24+
25+- (instancetype)initWithData:(NSData *)data {
26+
27+ self = [super init];
28+ if( self ) {
29+
30+ self.header = [SwfHeader headerWithData:data];
31+ self.firstContent = [SwfContent contentWithData:self.header.next];
32+ }
33+
34+ return self;
35+}
36+
37+@end
--- /dev/null
+++ b/KanColleGraphicDivider/SwfHeader.h
@@ -0,0 +1,17 @@
1+//
2+// SwfHeader.h
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+
11+@interface SwfHeader : NSObject
12+
13++ (nullable instancetype)headerWithData:(NSData *)data;
14+
15+@property (nullable, readonly) NSData *next;
16+
17+@end
--- /dev/null
+++ b/KanColleGraphicDivider/SwfHeader.m
@@ -0,0 +1,146 @@
1+//
2+// SwfHeader.m
3+// KanColleGraphicDivider
4+//
5+// Created by Hori,Masaki on 2018/05/20.
6+// Copyright © 2018年 Hori,Masaki. All rights reserved.
7+//
8+
9+#import "SwfHeader.h"
10+
11+#import "HMZlibData.h"
12+
13+typedef enum : NSUInteger {
14+
15+ normalSWFType,
16+ zlibCompressedSWFType,
17+ LZMACompressedSWFType,
18+
19+ unknownSWFType,
20+
21+} SwfType;
22+
23+
24+@interface SwfHeader()
25+
26+@property (nonnull) NSData *data;
27+
28+@property (nullable, readwrite) NSData *next;
29+
30+@end
31+
32+@implementation SwfHeader
33+
34++ (nullable instancetype)headerWithData:(NSData *)data {
35+
36+ return [[self alloc] initWithData:data];
37+}
38+
39+- (nullable instancetype)initWithData:(NSData *)data {
40+
41+ self = [super init];
42+
43+ if( !data ) {
44+
45+ NSLog(@"SwfHeader: Data is nil.");
46+
47+ return nil;
48+ }
49+
50+ if( self ) {
51+
52+ self.data = data;
53+
54+ if( ![self parse] ) {
55+
56+ NSLog(@"SwfHeader: Parse error");
57+
58+ return nil;
59+ }
60+ }
61+
62+ return self;
63+}
64+
65+- (BOOL)parse {
66+
67+ SwfType type = typeOf(self.data);
68+
69+ switch (type) {
70+
71+ case normalSWFType:
72+ {
73+ NSData *subdata = [self.data subdataWithRange:NSMakeRange(8, self.data.length - 8)];
74+ self.data = subdata;
75+ }
76+ break;
77+
78+ case zlibCompressedSWFType:
79+ {
80+ NSData *subdata = [self.data subdataWithRange:NSMakeRange(8, self.data.length - 8)];
81+ self.data = [subdata inflate];
82+ }
83+ break;
84+
85+ case LZMACompressedSWFType:
86+ {
87+ NSData *subdata = [self.data subdataWithRange:NSMakeRange(8, self.data.length - 8)];
88+ self.data = [subdata inflate];
89+ }
90+ break;
91+
92+ default:
93+
94+ NSLog(@"Signature is Unknown.");
95+
96+ return NO;
97+ }
98+
99+ // RECT: 上位5bitsが各要素のサイズを表す 要素は4つ
100+ UInt8 size = *(UInt8 *)self.data.bytes;
101+ size >>= 3;
102+ int offset = size * 4;
103+ offset += 5; // 上位5bit分
104+ // bit -> byte
105+ int div = offset / 8;
106+ int mod = offset % 8;
107+ offset = div + (mod == 0 ? 0 : 1); // アライメント
108+
109+ // fps: 8.8 fixed number.
110+ // 2 bytes.
111+
112+ // frame count
113+ // 2 bytes.
114+
115+ NSUInteger contentLoc = offset + 2 + 2;
116+ NSUInteger contentLength = self.data.length - contentLoc;
117+
118+ NSRange contentRange = NSMakeRange(contentLoc, contentLength);
119+
120+ self.next = [self.data subdataWithRange:contentRange];
121+
122+ return YES;
123+}
124+
125+SwfType typeOf(NSData *data) {
126+
127+ NSString *signature = [[NSString alloc] initWithBytesNoCopy:(void *)data.bytes
128+ length:3
129+ encoding:NSUTF8StringEncoding
130+ freeWhenDone:NO];
131+ if( [signature isEqualToString:@"FWS"] ) {
132+
133+ return normalSWFType;
134+ }
135+ if( [signature isEqualToString:@"CWS"] ) {
136+
137+ return zlibCompressedSWFType;
138+ }
139+ if( [signature isEqualToString:@"ZWS"] ) {
140+
141+ return LZMACompressedSWFType;
142+ }
143+
144+ return kUnknownType;
145+}
146+@end
--- a/KanColleGraphicDivider/main.m
+++ b/KanColleGraphicDivider/main.m
@@ -7,41 +7,22 @@
77 //
88
99 #import <Cocoa/Cocoa.h>
10-#include "SWFStructure.h"
11-#import "HMZlibData.h"
1210
1311 #include <getopt.h>
1412
13+#include "KanColleGraphicDivider.h"
1514
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
15+#import "Information.h"
16+#import "ImageStorer.h"
2217
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
18+#import "SwfData.h"
3319
34-#if 0
35-#define printLog(...) printLogF( __VA_ARGS__)
3620 void printLogF(const char *fmt, ...) {
3721 va_list ap;
3822 va_start(ap, fmt);
3923 vfprintf(stderr, fmt, ap);
4024 va_end(ap);
4125 }
42-#else
43-#define printLog(...)
44-#endif
4526
4627 void printHex(const unsigned char *p) {
4728 for(int i=0;i<1;i++) {
@@ -52,17 +33,6 @@ void printHex(const unsigned char *p) {
5233 }
5334 }
5435
55-enum {
56- tagBits = 6,
57- tagJPEGTables = 8, // not supported
58- tagBitsJPEG2 = 21, // not supported
59- tagBitsJPEG3 = 35,
60- tagBitsLossless = 20, // not supported
61- tagBitsLossless2 = 36,
62- tagBitsJPEG4 = 90, // not supported
63-
64-};
65-
6636 const char *toolName;
6737 const char *versionString = "1.0";
6838
@@ -94,221 +64,6 @@ static void version()
9464 exit(EXIT_SUCCESS);
9565 }
9666
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];
100- NSURL *url = [NSURL fileURLWithPath:path];
101- [data writeToURL:url atomically:YES];
102-}
103-
104-void saveImageAsPNG(Information *info, id image, UInt16 charactorID) {
105- NSData *tiffData = [image TIFFRepresentation];
106- if(!tiffData) {
107- fprintf(stderr, "Can not create TIFF representation.\n");
108- return;
109- }
110-
111- NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:tiffData];
112- NSData *imageData = [rep representationUsingType:NSPNGFileType
113- properties:@{}];
114- saveDataWithExtension(info, imageData, @"png", charactorID);
115-}
116-
117-void storeImage(Information *info, const unsigned char *p, UInt32 length, UInt16 charactorID) {
118- printLog("#### TYPE IS PICTURE ####\n\n");
119-
120- printLog("CaractorID is %d\n", charactorID);
121- if([info skipCharactorID:charactorID]) return;
122-
123- if(length == 0) return;
124-
125- NSData *pic = [NSData dataWithBytes:p length:length];
126- NSImage *pict = [[NSImage alloc] initWithData:pic];
127- if(!pict) {
128- fprintf(stderr, "Can not create image from data.\n");
129- return;
130- }
131-
132- saveDataWithExtension(info, pic, @"jpg", charactorID);
133-}
134-
135-void storeBitsJPEG3(Information *info, const unsigned char *p, UInt32 length) {
136- printLog("#### TYPE IS PICTURE ####\n\n");
137- if(length < HMSWFJPEG3HeaderSize) return;
138-
139- const HMSWFBitsJPEG3 *bitsJPEG3 = (HMSWFBitsJPEG3 *)p;
140-
141- UInt16 charactorID = bitsJPEG3->charctorID;
142- printLog("CaractorID is %d\n", charactorID);
143- if([info skipCharactorID:charactorID]) return;
144-
145- UInt32 contentLength = length - HMSWFJPEG3HeaderSize;
146- UInt32 imageSize = bitsJPEG3->imageSize;
147- p = &bitsJPEG3->imageData;
148-
149- if(imageSize == contentLength) {
150- storeImage(info, p, contentLength, charactorID);
151- return;
152- }
153-
154- // JPEGを取出し
155- NSData *pic = [NSData dataWithBytes:p length:imageSize];
156- NSImage *pict = [[NSImage alloc] initWithData:pic];
157- if(!pict) {
158- fprintf(stderr, "Can not create image from data.\n");
159- return;
160- }
161-
162- NSSize size = pict.size;
163-
164- // アルファチャンネルの取出し
165- NSData *alpha = [NSData dataWithBytes:p + imageSize length:contentLength - imageSize];
166- alpha = [alpha inflate];
167-
168- unsigned char *pp = (unsigned char *)alpha.bytes;
169- NSBitmapImageRep *alphaImageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp
170- pixelsWide:size.width
171- pixelsHigh:size.height
172- bitsPerSample:8
173- samplesPerPixel:1
174- hasAlpha:NO
175- isPlanar:NO
176- colorSpaceName:NSDeviceWhiteColorSpace
177- bytesPerRow:size.width
178- bitsPerPixel:0];
179- if(!alphaImageRef) {
180- fprintf(stderr, "Can not create alpha image from data.\n");
181- return;
182- }
183-
184- // 透過画像の作成
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);
204-}
205-
206-void storeBitLossless2ColorTable(Information *info, const unsigned char *p, UInt32 length) {
207- const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)p;
208-
209- UInt16 charactorID = data->charctorID;
210- printLog("CaractorID is %d\n", charactorID);
211- if([info skipCharactorID:charactorID]) return;
212-
213- UInt8 mapSize = data->data.colorTable.colorTableSize + 1;
214- printLog("color table size -> %d\n", mapSize);
215- printLog("zipped image data size -> %d\n", length - HMSWFLossless2ColorTableHeaderSize);
216-
217- NSData *zipedContentData = [NSData dataWithBytes:&data->data.colorTable.data length:length - HMSWFLossless2ColorTableHeaderSize];
218- NSData *contentData = [zipedContentData inflate];
219- printLog("unzipped image data size -> %d\n", contentData.length);
220-
221- const UInt32 *mapP = (UInt32 *)contentData.bytes;
222- const UInt8 *colorIndexP = (UInt8 *)(mapP + mapSize);
223-
224-#if 0
225- printLog("MAP TABLE\n");
226- for(int i = 0; i < mapSize; i++) {
227- printLog("0x%04x ", mapP[i]);
228- }
229- printLog("\n\n");
230-#endif
231-
232- // rowサイズは4bytesアライメント
233- UInt8 skipBytes = data->width % 4;
234-
235- // ARBGカラーマップからARBGビットマップを作成
236- UInt32 *imageDataP = calloc(4, data->width * data->height);
237- if(!imageDataP) {
238- fprintf(stderr, "Can not allocate enough memory.\n");
239- return;
240- }
241-
242- UInt32 *imageDataPixel = imageDataP;
243- for(UInt16 h = 0; h < data->height; h++) {
244- for(UInt16 w = 0; w < data->width; w++) {
245- printLog("%d ", *colorIndexP);
246- *imageDataPixel++ = mapP[*colorIndexP++];
247- }
248- colorIndexP += skipBytes;
249- printLog("\n");
250- }
251-
252- // ARGBビットマップからNSBitmapImageRepを作成
253- NSData *imageData = [NSData dataWithBytes:imageDataP length:4 * data->width * data->height];
254- unsigned char *pp = (unsigned char *)imageData.bytes;
255- NSBitmapImageRep *imageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp
256- pixelsWide:data->width
257- pixelsHigh:data->height
258- bitsPerSample:8
259- samplesPerPixel:4
260- hasAlpha:YES
261- isPlanar:NO
262- colorSpaceName:NSCalibratedRGBColorSpace
263- bytesPerRow:data->width * 4
264- bitsPerPixel:0];
265- free(imageDataP);
266- imageDataP = NULL;
267-
268- if(!imageRef) {
269- fprintf(stderr, "Can not create ImageRef from maked bitmap.");
270- return;
271- }
272-
273- saveImageAsPNG(info, imageRef, charactorID);
274-}
275-void storeBitsLossless2(Information *info, const unsigned char *p, UInt32 length) {
276- printLog("#### TYPE IS PICTURE ####\n\n");
277- if(length < HMSWFLossless2HeaderSize) {
278- fprintf(stderr, "length is too short.\n");
279- return;
280- }
281-
282- const HMSWFBitsLossless2 *data = (HMSWFBitsLossless2 *)p;
283-
284- UInt16 charactorID = data->charctorID;
285- printLog("CaractorID is %d\n", charactorID);
286- if([info skipCharactorID:charactorID]) return;
287-
288- if(data->bitmapFormat == 3) {
289- storeBitLossless2ColorTable(info, p, length);
290- return;
291- }
292-
293- length -= HMSWFLossless2HeaderSize;
294-
295- p = &data->data.data;
296- NSData *zipedImageData = [NSData dataWithBytes:p length:length];
297- NSData *imageData = [zipedImageData inflate];
298- unsigned char *pp = (unsigned char *)imageData.bytes;
299- NSBitmapImageRep *imageRef = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pp
300- pixelsWide:data->width
301- pixelsHigh:data->height
302- bitsPerSample:8 * 4
303- samplesPerPixel:4
304- hasAlpha:YES
305- isPlanar:NO
306- colorSpaceName:NSCalibratedRGBColorSpace
307- bytesPerRow:data->width * 4
308- bitsPerPixel:0];
309- saveImageAsPNG(info, imageRef, charactorID);
310-}
311-
31267 void extractImagesFromSWFFile(Information *info) {
31368 NSString *filePath = info.filename;
31469 if(![filePath hasPrefix:@"/"]) {
@@ -326,109 +81,27 @@ void extractImagesFromSWFFile(Information *info) {
32681 info.originalName = [filePath lastPathComponent];
32782 info.originalName = [info.originalName stringByDeletingPathExtension];
32883
329- printHex(data.bytes);
330-
331- // ヘッダの処理開始
332- const HMSWFHeader *header = data.bytes;
333- printLog("type\t%c%c%c\n", header->type[0], header->type[1], header->type[2]);
334- printLog("version\t%d\n", header->version);
335- printLog("file size\t0x%x (%d)\n", header->f.f, header->f.f);
336- data = [data subdataWithRange:NSMakeRange(8, data.length - 8)];
337- printHex(data.bytes);
338-
339- if(header->type[0] != 'F' && header->type[0] != 'C') {
340- fprintf(stderr, "File %s is not SWF.\n", info.filename.UTF8String);
341- return;
342- }
343- if(header->type[1] != 'W' || header->type[2] != 'S') {
344- fprintf(stderr, "File %s is not SWF.\n", info.filename.UTF8String);
345- return;
346- }
347-
348- // シグニチャがCの時はコンテントはzlibで圧縮されている
349- if(header->type[0] == 'C') {
350- data = [data inflate];
351- printHex(data.bytes);
352- }
353-
354- const unsigned char *p = data.bytes;
355-
356- // RECT: 上位5bitsが各要素のサイズを表す 要素は4つ
357- UInt8 size = *(UInt8 *)p;
358- size >>= 3;
359- printLog("size -> %u (%x)\n", size, size);
360- int offset = size * 4;
361- offset += 5; // 上位5bit分
362- // bit -> byte
363- int div = offset / 8;
364- int mod = offset % 8;
365- offset = div + (mod == 0 ? 0 : 1); // アライメント
366- printLog("offset -> %d\n", offset);
367- p += offset;
368-
369- // fps: 8.8 fixed number.
370- printLog("fps -> %u.%u\n", *(UInt8 *)(p + 1), *(UInt8 *)p);
371- p += 2;
84+ SwfData *swf = [SwfData dataWithData:data];
85+ SwfContent *content = swf.firstContent;
37286
373- // frame count
374- printLog("frame count -> %u\n", *(UInt16 *)p);
375- p += 2;
376-
377- // タグの処理開始
378- int tagCount = 0;
379- while(1) {
380- printHex(p);
381-
382- HMSWFTag *tagP = (HMSWFTag *)p;
383- p += 2;
384- printLog("tag and length -> 0x%04x\n", tagP->tagAndLength);
385- UInt32 tag = tagP->tagAndLength >> 6;
386- UInt32 length = tagP->tagAndLength & 0x3F;
387- if(length == 0x3F) {
388- length = tagP->extraLength;
389- p += 4;
390- }
391- printLog("tag -> %u\nlength -> %u\n", tag, length);
87+ while( content ) {
39288
393- // tag == 0 終了タグ
394- if(tag == 0) break;
89+ SwfContent *aContent = content;
90+ content = aContent.next;
39591
396- // 画像の時の処理
397- switch(tag) {
398- case tagBits:
399- @autoreleasepool {
400- storeImage(info, p + 2, length - 2, *(UInt16 *)p);
401- }
402- break;
403- case tagBitsJPEG3:
404- @autoreleasepool {
405- storeBitsJPEG3(info, p, length);
406- }
407- break;
408- case tagBitsLossless2:
409- @autoreleasepool {
410- storeBitsLossless2(info, p, length);
411- }
412- break;
413- case tagBitsJPEG2:
414- case tagBitsLossless:
415- case tagBitsJPEG4:
416- case tagJPEGTables:
417- if(length > 0) {
418- fprintf(stderr, "Not supported type. (tag=%d)\n", tag);
419- }
420- break;
92+ NSData *data = aContent.content;
93+ if( !data ) {
94+
95+ continue;
42196 }
42297
423- p += length;
424- tagCount++;
425-
426- if(tagCount > 200) {
427- return;
98+ if( [info skipCharactorID:aContent.charactorID] ) {
99+
100+ continue;
428101 }
102+
103+ saveDataWithExtension(info, data, aContent.extension, aContent.charactorID);
429104 }
430-
431- printLog("tag Count -> %d\n", tagCount);
432105 }
433106
434107 int main(int argc, char * const *argv) {
@@ -446,11 +119,11 @@ int main(int argc, char * const *argv) {
446119
447120 #define SHORTOPTS "ho:vc:"
448121 static struct option longopts[] = {
449- {"output", required_argument, NULL, 'o'},
450- {"charactorid", required_argument, NULL, 'c'},
451- {"version", no_argument, NULL, 'v'},
452- {"help", no_argument, NULL, 'h'},
453- {NULL, 0, NULL, 0}
122+ {"output", required_argument, NULL, 'o'},
123+ {"charactorid", required_argument, NULL, 'c'},
124+ {"version", no_argument, NULL, 'v'},
125+ {"help", no_argument, NULL, 'h'},
126+ {NULL, 0, NULL, 0}
454127 };
455128
456129 while((opt = getopt_long(argc, argv, SHORTOPTS, longopts, NULL)) != -1) {