root/trunk/Subtitles/SubContext.m

Revision 919, 8.2 kB (checked in by astrange, 1 month ago)

SSA: Support vertical text (fonts with @ in the name).

Line 
1 //
2 //  SubContext.m
3 //  SSARender2
4 //
5 //  Created by Alexander Strange on 7/28/07.
6 //  Copyright 2007 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "SubContext.h"
10 #import "SubParsing.h"
11
12 @implementation SubStyle
13
14 SubRGBAColor ParseSSAColor(unsigned rgb)
15 {
16         unsigned char r, g, b, a;
17        
18         a = (rgb >> 24) & 0xff;
19         b = (rgb >> 16) & 0xff;
20         g = (rgb >> 8) & 0xff;
21         r = rgb & 0xff;
22        
23         a = 255-a;
24        
25         return (SubRGBAColor){r/255.,g/255.,b/255.,a/255.};
26 }
27
28 static SubRGBAColor ParseSSAColorString(NSString *c)
29 {
30         const char *c_ = [c UTF8String];
31         unsigned int rgb;
32        
33         if (c_[0] == '&') {
34                 rgb = strtoul(&c_[2],NULL,16);
35         } else {
36                 rgb = strtol(c_,NULL,0);
37         }
38        
39         return ParseSSAColor(rgb);
40 }
41
42 UInt8 SSA2ASSAlignment(UInt8 a)
43 {
44     int h = 1, v = 0;
45         if (a >= 9 && a <= 11) {v = kSubAlignmentMiddle; h = a-8;}
46         if (a >= 5 && a <= 7)  {v = kSubAlignmentTop;    h = a-4;}
47         if (a >= 1 && a <= 3)  {v = kSubAlignmentBottom; h = a;}
48         return v * 3 + h;
49 }
50
51 void ParseASSAlignment(UInt8 a, UInt8 *alignH, UInt8 *alignV)
52 {
53         switch (a) {
54                 default: case 1 ... 3: *alignV = kSubAlignmentBottom; break;
55                 case 4 ... 6: *alignV = kSubAlignmentMiddle; break;
56                 case 7 ... 9: *alignV = kSubAlignmentTop; break;
57         }
58        
59         switch (a) {
60                 case 1: case 4: case 7: *alignH = kSubAlignmentLeft; break;
61                 default: case 2: case 5: case 8: *alignH = kSubAlignmentCenter; break;
62                 case 3: case 6: case 9: *alignH = kSubAlignmentRight; break;
63         }
64 }
65
66 BOOL ParseFontVerticality(NSString **fontname)
67 {
68         if ([*fontname characterAtIndex:0] == '@') {
69                 *fontname = [*fontname substringFromIndex:1];
70                 return YES;
71         }
72         return NO;
73 }
74
75 +(SubStyle*)defaultStyleWithDelegate:(SubRenderer*)delegate
76 {
77         SubStyle *sty = [[[SubStyle alloc] init] autorelease];
78        
79         sty->name = @"*Default";
80         sty->fontname = @"Helvetica";
81         sty->platformSizeScale = 1;
82         sty->size = 32 * sqrt([delegate aspectRatio] / (4./3.));
83         sty->primaryColor = (SubRGBAColor){1,1,1,1};
84         sty->outlineColor = (SubRGBAColor){0,0,0,1};
85         sty->shadowColor = (SubRGBAColor){0,0,0,1};
86         sty->scaleX = sty->scaleY = 100;
87         sty->tracking = sty->angle = 0;
88         sty->outlineRadius = 1.5;
89         sty->shadowDist = 2;
90         sty->marginL = sty->marginR = sty->marginV = 20;
91         sty->bold = YES;
92         sty->italic = sty->underline = sty->strikeout = NO;
93         sty->alignH = kSubAlignmentCenter;
94         sty->alignV = kSubAlignmentBottom;
95         sty->borderStyle = kSubBorderStyleNormal;
96         sty->ex = [delegate completedStyleParsing:sty];
97         sty->delegate = delegate;
98         return sty;
99 }
100
101 -(SubStyle*)initWithDictionary:(NSDictionary *)s scriptVersion:(UInt8)version delegate:(SubRenderer*)delegate_
102 {
103         if (self = [super init]) {
104                 NSString *tmp;
105                 delegate = delegate_;
106                 NSString *sv;
107                                
108 #define sv(fn, n) fn = [[s objectForKey: @""#n] retain]
109 #define fv(fn, n) sv = [s objectForKey:@""#n]; fn = sv ? [sv floatValue] : 0.;
110 #define iv(fn, n) fn = [[s objectForKey:@""#n] intValue]
111 #define bv(fn, n) fn = [[s objectForKey:@""#n] intValue] != 0
112 #define cv(fn, n) tmp = [s objectForKey:@""#n]; if (tmp) fn = ParseSSAColorString(tmp);
113                
114                 sv(name, Name);
115                 sv(fontname, Fontname);
116                 fv(size, Fontsize);
117                 cv(primaryColor, PrimaryColour);
118                 cv(secondaryColor, SecondaryColour);
119                 tmp = [s objectForKey:@"BackColour"];
120                 if (tmp) outlineColor = shadowColor = ParseSSAColorString(tmp);
121                 cv(outlineColor, OutlineColour);
122                 cv(shadowColor, ShadowColour);
123                 bv(bold, Bold);
124                 bv(italic, Italic);
125                 bv(underline, Underline);
126                 bv(strikeout, Strikeout);
127                 fv(scaleX, ScaleX);
128                 fv(scaleY, ScaleY);
129                 fv(tracking, Spacing);
130                 fv(angle, Angle);
131                 fv(outlineRadius, Outline);
132                 fv(shadowDist, Shadow);
133                 iv(marginL, MarginL);
134                 iv(marginR, MarginR);
135                 iv(marginV, MarginV);
136                 iv(borderStyle, BorderStyle);
137                
138                 if (!scaleX) scaleX = 100;
139                 if (!scaleY) scaleY = 100;
140
141                 UInt8 align = [[s objectForKey:@"Alignment"] intValue];
142                 if (version == kSubTypeSSA) align = SSA2ASSAlignment(align);
143                
144                 ParseASSAlignment(align, &alignH, &alignV);
145                
146                 platformSizeScale = 0;
147                 ex = [delegate completedStyleParsing:self];
148         }
149        
150         return self;
151 }
152
153 static NSString *yes(int i) {return i ? @"yes" : @"no";}
154
155 static NSString *ColorString(SubRGBAColor *c)
156 {
157         return [NSString stringWithFormat:@"{R: %d G: %d B: %d A: %d}", (int)(c->red * 255),
158                                          (int)(c->green * 255), (int)(c->blue * 255), (int)(c->alpha * 255)];
159 }
160
161 -(NSString *)description
162 {
163         static const NSString *alignHStr[] = {@"left", @"center", @"right"};
164         static const NSString *alignVStr[] = {@"bottom", @"middle", @"top"};
165         static const NSString *bstyle[] = {@"normal", @"box"};
166        
167         return [NSString stringWithFormat:@""
168                                          "SubStyle named \"%@\"\n"
169                                          "-Font: %f pt %@\n"
170                                          "-Primary color: %@\n"
171                                          "-Secondary color: %@\n"
172                                          "-Outline: %f px %@\n"
173                                          "-Shadow: %f px %@\n"
174                                          "-Margin: %d px left, %d px right, %d px vertical\n"
175                                          "-Bold: %@ Italic: %@ Underline: %@ Strikeout: %@\n"
176                                          "-Alignment: %@ %@\n"
177                                          "-Border style: %@\n"
178                                          "-Per-font scale: %f\n",
179                                          name, size, fontname, ColorString(&primaryColor),
180                                          ColorString(&secondaryColor), outlineRadius, ColorString(&outlineColor),
181                                          shadowDist, ColorString(&shadowColor), marginL, marginR, marginV,
182                                          yes(bold), yes(italic), yes(underline), yes(strikeout), alignHStr[alignH],
183                                          alignVStr[alignV], bstyle[borderStyle], platformSizeScale];
184 }
185
186 -(void)dealloc
187 {
188         [name release];
189         [fontname release];
190         [delegate releaseStyleExtra:ex];
191         [super dealloc];
192 }
193
194 -(void)finalize
195 {
196         [delegate releaseStyleExtra:ex];
197         [super finalize];
198 }
199 @end
200
201 @implementation SubContext
202
203 BOOL IsScriptASS(NSDictionary *headers)
204 {       
205         return [[[headers objectForKey:@"ScriptType"] lowercaseString] isEqualToString:@"v4.00+"];
206 }
207
208 -(void)readHeaders
209 {
210         scriptType = IsScriptASS(headers) ? kSubTypeASS : kSubTypeSSA;
211         collisions = [[headers objectForKey:@"Collisions"] isEqualToString:@"Reverse"] ? kSubCollisionsReverse : kSubCollisionsNormal;
212         wrapStyle = [[headers objectForKey:@"WrapStyle"] intValue];
213        
214         NSString *resXS = [headers objectForKey:@"PlayResX"], *resYS = [headers objectForKey:@"PlayResY"];
215        
216         if (resXS) resX = [resXS floatValue];
217         if (resYS) resY = [resYS floatValue];
218        
219         // obscure res rules copied from VSFilter
220         if ((!resXS && !resYS) || (!resX && !resY)) {
221                 resX = 384; resY = 288;
222         } else if (!resYS) {
223                 resY = (resX == 1280) ? 1024 : (resX / (4./3.));
224         } else if (!resXS) {
225                 resX = (resY == 1024) ? 1280 : (resY * (4./3.));
226         }
227 }
228
229 -(SubContext*)initWithHeaders:(NSDictionary *)headers_ styles:(NSArray *)styles_ extraData:(NSString *)ed delegate:(SubRenderer*)delegate
230 {
231         if (self = [super init]) {
232                 headertext = [ed retain];
233                 headers = [headers_ retain];
234                 [self readHeaders];
235                
236                 [delegate completedHeaderParsing:self];
237                
238                 styles = nil;
239                 if (styles_) {
240                         int i, nstyles = [styles_ count];
241                         NSMutableDictionary *sdict = [[NSMutableDictionary alloc] initWithCapacity:nstyles];
242                        
243                         for (i=0; i < nstyles; i++) {
244                                 NSDictionary *style = [styles_ objectAtIndex:i];
245                                 [sdict setObject:[[[SubStyle alloc] initWithDictionary:style scriptVersion:scriptType delegate:delegate] autorelease]
246                                                                                                 forKey:[style objectForKey:@"Name"]];
247                         }
248                        
249                         styles = sdict;
250                 }
251                
252                 defaultStyle = [styles objectForKey:@"Default"];
253                 if (!defaultStyle) defaultStyle = [SubStyle defaultStyleWithDelegate:delegate];
254                 [defaultStyle retain];
255                
256         }
257        
258         return self;
259 }
260
261 -(SubContext*)initWithNonSSAType:(UInt8)type delegate:(SubRenderer*)delegate
262 {
263         if (self = [super init]) {
264                 resX = 640;
265                 resY = 480;
266                 scriptType = type;
267                 collisions = kSubCollisionsNormal;
268                 wrapStyle = kSubLineWrapBottomWider;
269                 styles = headers = nil;
270                 headertext = nil;
271                 [delegate completedHeaderParsing:self];
272
273                 defaultStyle = [[SubStyle defaultStyleWithDelegate:delegate] retain];           
274         }
275        
276         return self;
277 }
278
279 -(void)dealloc
280 {
281         [styles release];
282         [defaultStyle release];
283         [headers release];
284         [headertext release];
285         [super dealloc];
286 }
287
288 -(SubStyle*)styleForName:(NSString *)name
289 {
290         SubStyle *sty = [styles objectForKey:name];
291         return sty ? sty : defaultStyle;
292 }
293 @end
294
295 @implementation SubRenderer
296 -(void*)completedStyleParsing:(SubStyle*)s {return nil;}
297 -(void)completedHeaderParsing:(SubContext*)sc {}
298 -(void*)spanExtraFromRenderDiv:(SubRenderDiv*)div {return nil;}
299 -(void*)cloneSpanExtra:(SubRenderSpan*)span {return span->ex;}
300 -(void)spanChangedTag:(SSATagType)tag span:(SubRenderSpan*)span div:(SubRenderDiv*)div param:(void*)p {}
301 -(void)releaseStyleExtra:(void*)ex {}
302 -(void)releaseSpanExtra:(void*)ex {}
303 -(float)aspectRatio {return 4./3.;}
304 @end
Note: See TracBrowser for help on using the browser.