mirror of
https://github.com/androidx/media.git
synced 2025-05-11 09:39:52 +08:00
add SSA/ASS specific files from branch
This commit is contained in:
parent
163a3a7bb8
commit
246a0dc86e
@ -0,0 +1,43 @@
|
||||
package com.google.android.exoplayer2.text.ssa;
|
||||
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
|
||||
/**
|
||||
* Created by cablej01 on 02/01/2017.
|
||||
*/
|
||||
|
||||
public class SSACue extends Cue {
|
||||
private Style style = null;
|
||||
private int layer;
|
||||
private String effect;
|
||||
private String richText = null;
|
||||
|
||||
public SSACue(String text) {
|
||||
this(text, null, 0, null);
|
||||
}
|
||||
|
||||
public SSACue(String text, Style style, int layer, String effect) {
|
||||
super(text.replaceAll("\\{[^{]*\\}", ""));
|
||||
this.richText = text;
|
||||
this.layer = layer;
|
||||
this.effect = effect;
|
||||
this.style = style;
|
||||
// TODO map SSA fields to superclass fields
|
||||
}
|
||||
|
||||
public Style getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
public int getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public String getEffect() {
|
||||
return effect;
|
||||
}
|
||||
|
||||
public String getRichText() {
|
||||
return richText;
|
||||
}
|
||||
}
|
@ -0,0 +1,260 @@
|
||||
package com.google.android.exoplayer2.text.ssa;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.text.Layout;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.SimpleSubtitleDecoder;
|
||||
import com.google.android.exoplayer2.util.LongArray;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static android.R.attr.breadCrumbShortTitle;
|
||||
import static android.R.attr.data;
|
||||
import static android.R.attr.format;
|
||||
import static android.R.attr.key;
|
||||
import static android.R.attr.lines;
|
||||
import static android.R.attr.subtitle;
|
||||
import static android.R.attr.text;
|
||||
import static android.R.attr.textAlignment;
|
||||
import static android.R.attr.track;
|
||||
import static android.icu.lang.UCharacter.GraphemeClusterBreak.L;
|
||||
import static android.webkit.ConsoleMessage.MessageLevel.LOG;
|
||||
import static com.google.android.exoplayer2.text.Cue.DIMEN_UNSET;
|
||||
import static com.google.android.exoplayer2.text.Cue.TYPE_UNSET;
|
||||
|
||||
/**
|
||||
* Created by cablej01 on 26/12/2016.
|
||||
*/
|
||||
|
||||
/* Notes from ojw28
|
||||
|
||||
Subtitles are really complicated because they can be packaged in different units of granularity
|
||||
and with different ways of conveying timing information. Roughly speaking, an input buffer
|
||||
received by a subtitle decoder consists of a timestamp (timeUs) and the subtitle data to be
|
||||
decoded (data). There are four cases that can occur:
|
||||
|
||||
1. data contains all of the cues for the media and also their presentation timestamps.
|
||||
timeUs is the time of the start of the media. The subtitle decoder receives a single input buffer.
|
||||
|
||||
2. data contains a single cue to be displayed at timeUs. There are no timestamps encoded in data.
|
||||
The subtitle decoder receives many input buffers.
|
||||
|
||||
3. data contains cues covering a region of time (e.g. 5 seconds) along with their presentation
|
||||
timestamps relative to the start of the region. timeUs is the time of the start of the region.
|
||||
The subtitle decoder receives many input buffers.
|
||||
|
||||
4. As above, but the timestamps embedded in data are relative to the start of the media rather
|
||||
than the start of the region. This case is tricky and best avoided.
|
||||
|
||||
For a side-loaded SSA file you'd have case (1).
|
||||
|
||||
For SSA embedded in MKV, it looks like they way it's embedded means you'd have case (2)
|
||||
if you were to just pass the sample data through without changing it.
|
||||
Note that timeUs is being set to blockTimeUs already.
|
||||
Each region happens to be the duration of a single cue.
|
||||
|
||||
In the extractor, It's much easier to handle if you change the sample data so that you get case (3).
|
||||
This basically means the embedded time should be 0 rather than blockTimeUs.
|
||||
|
||||
If you look at the SubRip case in the MKV extractor you'll see that it does exactly this.
|
||||
The SubRip case also defers writing so that the end time can be set properly.
|
||||
|
||||
In the decoder you should create a new Subtitle instance for each decode call, rather than appending to an existing instance.
|
||||
|
||||
For the SSA embedded in MKV case you should end up with each call to decode producing a new Subtitle with a single cue at time 0.
|
||||
The reason this works is that the event timing in a Subtitle is relative to timeUs of the buffer,
|
||||
which is being set to blockTimeUs. When the decoder receives a new input buffer with a larger timeUs
|
||||
than the previous one, the value passed to getCues will go down.
|
||||
*/
|
||||
|
||||
|
||||
public class SSADecoder extends SimpleSubtitleDecoder {
|
||||
private static final String TAG = "SSADecoder";
|
||||
private static String defaultDialogueFormat = "Start, End, , Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
|
||||
private static String defaultStyleFormat = "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding";
|
||||
private String[] dialogueFormat;
|
||||
private String[] styleFormat;
|
||||
private Map<String,Style> styles = new HashMap<>();
|
||||
|
||||
public SSADecoder() {
|
||||
super("SSADecoder");
|
||||
dialogueFormat = parseKeys(defaultDialogueFormat);
|
||||
styleFormat = parseKeys(defaultStyleFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes data into a {@link SSASubtitle}.
|
||||
*
|
||||
* @param bytes An array holding the data to be decoded, starting at position 0.
|
||||
* @param length The size of the data to be decoded.
|
||||
* @return The decoded {@link SSASubtitle}.
|
||||
*/
|
||||
@Override
|
||||
protected SSASubtitle decode(byte[] bytes, int length) {
|
||||
SSASubtitle subtitle = new SSASubtitle();
|
||||
ParsableByteArray data = new ParsableByteArray(bytes, length);
|
||||
String currentLine;
|
||||
while ((currentLine = data.readLine()) != null) {
|
||||
if (currentLine.matches("^Dialogue:.*$")) {
|
||||
String p[] = currentLine.split(":",2);
|
||||
Map<String,String> ev = parseLine(dialogueFormat, p[1].trim());
|
||||
subtitle.addEvent(ev, styles);
|
||||
}
|
||||
}
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
public void decodeFile(byte[] bytes, int length) {
|
||||
SSASubtitle subtitle = new SSASubtitle();
|
||||
ParsableByteArray data = new ParsableByteArray(bytes, length);
|
||||
decodeHeader(data);
|
||||
String currentLine;
|
||||
while ((currentLine = data.readLine()) != null) {
|
||||
while(true) {
|
||||
currentLine = data.readLine();
|
||||
if(currentLine==null)
|
||||
break;
|
||||
Log.i(TAG, currentLine);
|
||||
if(!currentLine.contains(":"))
|
||||
break;
|
||||
String p[] = currentLine.split(":",2);
|
||||
if(p[0].equals("Format")) {
|
||||
dialogueFormat = parseKeys(p[1]);
|
||||
}
|
||||
else if(p[0].equals("Dialogue")) {
|
||||
Map<String,String> ev = parseLine(dialogueFormat, p[1].trim());
|
||||
subtitle.addEvent(ev, styles);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void decodeHeader(byte[] bytes, int length) {
|
||||
ParsableByteArray data = new ParsableByteArray(bytes, length);
|
||||
decodeHeader(data);
|
||||
}
|
||||
|
||||
private void decodeHeader(ParsableByteArray data) {
|
||||
String currentLine;
|
||||
while ((currentLine = data.readLine()) != null) {
|
||||
if (currentLine.length() == 0) {
|
||||
// Skip blank lines.
|
||||
continue;
|
||||
}
|
||||
Log.i(TAG, currentLine);
|
||||
|
||||
if (currentLine.equals("[Script Info]")) {
|
||||
// TODO
|
||||
continue;
|
||||
} else if (currentLine.equals("[V4+ Styles]")) {
|
||||
parseStyles(styles, data);
|
||||
continue;
|
||||
} else if (currentLine.equals("[V4 Styles]")) {
|
||||
parseStyles(styles, data);
|
||||
continue;
|
||||
} else if (currentLine.equals("[Events]")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseStyles(Map<String, Style> styles, ParsableByteArray data) {
|
||||
while(true) {
|
||||
String line = data.readLine();
|
||||
if(line==null)
|
||||
break;
|
||||
Log.i(TAG, line);
|
||||
if(!line.contains(":"))
|
||||
break;
|
||||
String p[] = line.split(":",2);
|
||||
if(p[0].equals("Format")) {
|
||||
styleFormat = parseKeys(p[1]);
|
||||
}
|
||||
else if(p[0].equals("Style")) {
|
||||
Style s = new Style(parseLine(styleFormat, p[1]));
|
||||
styles.put(s.getName(), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String[] parseKeys(String format) {
|
||||
String keys[] = format.split(", *");
|
||||
String r[] = new String[keys.length];
|
||||
for(int i=0; i<r.length; i++) {
|
||||
r[i] = keys[i].trim().toLowerCase();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public static Map<String,String> parseLine(String[] keys, String event) {
|
||||
Map<String,String> result = new HashMap<>();
|
||||
String fields[] = event.split(", *", keys.length);
|
||||
for(int i=0; i<keys.length; i++) {
|
||||
String k = keys[i];
|
||||
String v = fields[i].trim();
|
||||
result.put(k, v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void writeMangledHeader(StringBuffer s, byte[] data){
|
||||
// header contains the original format but the Matroska encoder changes this.
|
||||
// we won't need anything after the [Events] line
|
||||
try {
|
||||
String header = new String(data, "UTF-8").split("\\[Events]")[0];
|
||||
s.append(header);
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
// we know this can't happen
|
||||
}
|
||||
s.append("[Events]\n");
|
||||
s.append(defaultDialogueFormat);
|
||||
s.append("\n");
|
||||
}
|
||||
|
||||
public static void buildDialogue(StringBuffer s, String data, long durationUs) {
|
||||
s.append("Dialogue: ");
|
||||
s.append(SSADecoder.formatTimeCode(0)); // blockTimeUs
|
||||
s.append(",");
|
||||
long endUs = durationUs; // + blockTimeUs
|
||||
if (endUs == C.TIME_UNSET) {
|
||||
endUs = 2000000; // 2 second default duration
|
||||
}
|
||||
s.append(SSADecoder.formatTimeCode(endUs));
|
||||
s.append(",");
|
||||
s.append(data);
|
||||
s.append("\n");
|
||||
}
|
||||
|
||||
public static String formatTimeCode(long tc_us) {
|
||||
long seconds = tc_us / 1000000;
|
||||
long us = tc_us - 1000000*seconds;
|
||||
long minutes = seconds / 60;
|
||||
seconds -= 60 * minutes;
|
||||
long hours = minutes / 60;
|
||||
minutes -= 60*hours;
|
||||
double sec = seconds + ((float)us)/1000000.0;
|
||||
return String.format("%01d:%02d:%06.3f", hours, minutes, sec);
|
||||
}
|
||||
|
||||
public static long parseTimecode(String time) {
|
||||
String p[] = time.split(":");
|
||||
long hours = Long.parseLong(p[0]);
|
||||
long minutes = Long.parseLong(p[1]);
|
||||
float seconds = Float.parseFloat(p[2]);
|
||||
float us = 1000000*seconds;
|
||||
long lus = ((long)us);
|
||||
return lus + 1000000 * (60 * (minutes + 60 * hours));
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.google.android.exoplayer2.text.ssa;
|
||||
|
||||
import android.text.Layout;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.Subtitle;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.LongArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static android.R.attr.start;
|
||||
|
||||
/**
|
||||
* Created by cablej01 on 26/12/2016.
|
||||
*/
|
||||
|
||||
public class SSASubtitle implements Subtitle {
|
||||
|
||||
private List<Cue> cues = new ArrayList<>();
|
||||
private List<Long> cueTimesUs = new ArrayList<>();
|
||||
|
||||
|
||||
public SSASubtitle() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void add(int pos, Cue cue, long cueTimeUs) {
|
||||
cues.add(pos, cue);
|
||||
cueTimesUs.add(pos, cueTimeUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextEventTimeIndex(long timeUs) {
|
||||
int index = Util.binarySearchCeil(cueTimesUs, timeUs, false, false);
|
||||
return index < cueTimesUs.size() ? index : C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEventTimeCount() {
|
||||
return cueTimesUs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEventTime(int index) {
|
||||
Assertions.checkArgument(index >= 0);
|
||||
Assertions.checkArgument(index < cueTimesUs.size());
|
||||
return cueTimesUs.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cue> getCues(long timeUs) {
|
||||
Log.i("getCues", String.format("%d %s", timeUs, SSADecoder.formatTimeCode(timeUs)));
|
||||
int index = Util.binarySearchFloor(cueTimesUs, timeUs, true, false);
|
||||
if (index == -1 || cues.get(index) == null) {
|
||||
// timeUs is earlier than the start of the first cue, or we have an empty cue.
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Collections.singletonList(cues.get(index));
|
||||
}
|
||||
}
|
||||
|
||||
protected void addEvent(Map<String,String> ev, Map<String,Style> styles) {
|
||||
// int readOrder = Integer.parseInt(ev.get("readorder")); ? not needed
|
||||
int marginL = Integer.parseInt(ev.get("marginl"));
|
||||
int marginR = Integer.parseInt(ev.get("marginr"));
|
||||
int marginV = Integer.parseInt(ev.get("marginv"));
|
||||
String styleName = ev.get("style");
|
||||
Style style = styles.get(styleName);
|
||||
if(marginL!=0 || marginR!=0 || marginV !=0) {
|
||||
style = new Style(style);
|
||||
}
|
||||
if(marginL!=0) {
|
||||
style.setMarginL(marginL);
|
||||
}
|
||||
if(marginR!=0) {
|
||||
style.setMarginR(marginR);
|
||||
}
|
||||
if(marginV!=0) {
|
||||
style.setMarginV(marginV);
|
||||
}
|
||||
int layer = Integer.parseInt(ev.get("layer"));
|
||||
String effect = ev.get("effect");
|
||||
String text = ev.get("text").replaceAll("\\\\N", "\n");
|
||||
String simpleText = text.replaceAll("\\{[^{]*\\}", "");
|
||||
Cue cue = new SSACue(text, style, layer, effect);
|
||||
long start = SSADecoder.parseTimecode(ev.get("start"));
|
||||
cueTimesUs.add(start);
|
||||
cues.add(cue);
|
||||
// add null cue to remove this cue after it's duration
|
||||
long end = SSADecoder.parseTimecode(ev.get("end"));
|
||||
cueTimesUs.add(end);
|
||||
cues.add(null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,283 @@
|
||||
package com.google.android.exoplayer2.text.ssa;
|
||||
|
||||
import android.graphics.Outline;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static android.os.Build.VERSION_CODES.M;
|
||||
|
||||
/**
|
||||
* Created by cablej01 on 27/12/2016.
|
||||
*/
|
||||
|
||||
public class Style {
|
||||
private String name;
|
||||
private String fontName;
|
||||
private int fontSize;
|
||||
private int primaryColour, secondaryColour, outlineColour, backColour;
|
||||
private boolean bold, italic, underline, strikeOut;
|
||||
private int scaleX, scaleY, spacing, angle;
|
||||
private int borderStyle;
|
||||
private int outline, shadow, alignment, marginL, marginR, marginV;
|
||||
private int alphaLevel=0;
|
||||
private int encoding;
|
||||
|
||||
public Style() {
|
||||
|
||||
}
|
||||
|
||||
public Style(Map<String,String> init) {
|
||||
name = init.get("name");
|
||||
fontName = init.get("fontname");
|
||||
fontSize = Integer.parseInt(init.get("fontsize"));
|
||||
primaryColour = parseColour(init.get("primarycolour"));
|
||||
secondaryColour = parseColour(init.get("secondarycolour"));
|
||||
outlineColour = parseColour(init.get("outlinecolour"));
|
||||
backColour = parseColour(init.get("backcolour"));
|
||||
bold = init.get("bold").equals("0")?false:true;
|
||||
italic = init.get("italic").equals("0")?false:true;
|
||||
underline = init.get("underline").equals("0")?false:true;
|
||||
strikeOut = init.get("strikeout").equals("0")?false:true;
|
||||
scaleX = Integer.parseInt(init.get("scalex"));
|
||||
scaleY = Integer.parseInt(init.get("scaley"));
|
||||
spacing = Integer.parseInt(init.get("spacing"));
|
||||
angle = Integer.parseInt(init.get("angle"));
|
||||
borderStyle = Integer.parseInt(init.get("borderstyle"));
|
||||
outline = Integer.parseInt(init.get("outline"));
|
||||
shadow = Integer.parseInt(init.get("shadow"));
|
||||
alignment = Integer.parseInt(init.get("alignment"));
|
||||
marginL = Integer.parseInt(init.get("marginl"));
|
||||
marginR = Integer.parseInt(init.get("marginr"));
|
||||
marginV = Integer.parseInt(init.get("marginv"));
|
||||
if(init.containsKey("alphalevel"))
|
||||
alphaLevel= Integer.parseInt(init.get("alphalevel"));
|
||||
encoding = Integer.parseInt(init.get("encoding"));
|
||||
}
|
||||
|
||||
public Style(Style aStyle) {
|
||||
name = aStyle.name;
|
||||
fontName = aStyle.fontName;
|
||||
fontSize = aStyle.fontSize;
|
||||
primaryColour = aStyle.primaryColour;
|
||||
secondaryColour = aStyle.secondaryColour;
|
||||
outlineColour = aStyle.outlineColour;
|
||||
backColour = aStyle.backColour;
|
||||
bold = aStyle.bold;
|
||||
italic = aStyle.italic;
|
||||
underline = aStyle.underline;
|
||||
strikeOut = aStyle.strikeOut;
|
||||
scaleX = aStyle.scaleX;
|
||||
scaleY = aStyle.scaleY;
|
||||
spacing = aStyle.spacing;
|
||||
angle = aStyle.angle;
|
||||
borderStyle = aStyle.borderStyle;
|
||||
outline = aStyle.outline;
|
||||
shadow = aStyle.shadow;
|
||||
alignment = aStyle.alignment;
|
||||
marginL = aStyle.marginL;
|
||||
marginR = aStyle.marginR;
|
||||
marginV = aStyle.marginV;
|
||||
alphaLevel= aStyle.alphaLevel;
|
||||
encoding = aStyle.encoding;
|
||||
}
|
||||
|
||||
public static int parseColour(String val) {
|
||||
return Integer.parseInt(val.substring(2), 16);
|
||||
}
|
||||
|
||||
public static String formatColour(int val) {
|
||||
return String.format("&H%06X", val);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getFontName() {
|
||||
return fontName;
|
||||
}
|
||||
|
||||
public void setFontName(String fontName) {
|
||||
this.fontName = fontName;
|
||||
}
|
||||
|
||||
public int getFontSize() {
|
||||
return fontSize;
|
||||
}
|
||||
|
||||
public void setFontSize(int fontSize) {
|
||||
this.fontSize = fontSize;
|
||||
}
|
||||
|
||||
public int getPrimaryColour() {
|
||||
return primaryColour;
|
||||
}
|
||||
|
||||
public void setPrimaryColour(int primaryColour) {
|
||||
this.primaryColour = primaryColour;
|
||||
}
|
||||
|
||||
public int getSecondaryColour() {
|
||||
return secondaryColour;
|
||||
}
|
||||
|
||||
public void setSecondaryColour(int secondaryColour) {
|
||||
this.secondaryColour = secondaryColour;
|
||||
}
|
||||
|
||||
public int getOutlineColour() {
|
||||
return outlineColour;
|
||||
}
|
||||
|
||||
public void setOutlineColour(int outlineColour) {
|
||||
this.outlineColour = outlineColour;
|
||||
}
|
||||
|
||||
public int getBackColour() {
|
||||
return backColour;
|
||||
}
|
||||
|
||||
public void setBackColour(int backColour) {
|
||||
this.backColour = backColour;
|
||||
}
|
||||
|
||||
public boolean isBold() {
|
||||
return bold;
|
||||
}
|
||||
|
||||
public void setBold(boolean bold) {
|
||||
this.bold = bold;
|
||||
}
|
||||
|
||||
public boolean isItalic() {
|
||||
return italic;
|
||||
}
|
||||
|
||||
public void setItalic(boolean italic) {
|
||||
this.italic = italic;
|
||||
}
|
||||
|
||||
public boolean isUnderline() {
|
||||
return underline;
|
||||
}
|
||||
|
||||
public void setUnderline(boolean underline) {
|
||||
this.underline = underline;
|
||||
}
|
||||
|
||||
public boolean isStrikeOut() {
|
||||
return strikeOut;
|
||||
}
|
||||
|
||||
public void setStrikeOut(boolean strikeOut) {
|
||||
this.strikeOut = strikeOut;
|
||||
}
|
||||
|
||||
public int getScaleX() {
|
||||
return scaleX;
|
||||
}
|
||||
|
||||
public void setScaleX(int scaleX) {
|
||||
this.scaleX = scaleX;
|
||||
}
|
||||
|
||||
public int getScaleY() {
|
||||
return scaleY;
|
||||
}
|
||||
|
||||
public void setScaleY(int scaleY) {
|
||||
this.scaleY = scaleY;
|
||||
}
|
||||
|
||||
public int getSpacing() {
|
||||
return spacing;
|
||||
}
|
||||
|
||||
public void setSpacing(int spacing) {
|
||||
this.spacing = spacing;
|
||||
}
|
||||
|
||||
public int getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
public void setAngle(int angle) {
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
public int getBorderStyle() {
|
||||
return borderStyle;
|
||||
}
|
||||
|
||||
public void setBorderStyle(int borderStyle) {
|
||||
this.borderStyle = borderStyle;
|
||||
}
|
||||
|
||||
public int getOutline() {
|
||||
return outline;
|
||||
}
|
||||
|
||||
public void setOutline(int outline) {
|
||||
this.outline = outline;
|
||||
}
|
||||
|
||||
public int getShadow() {
|
||||
return shadow;
|
||||
}
|
||||
|
||||
public void setShadow(int shadow) {
|
||||
this.shadow = shadow;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
return alignment;
|
||||
}
|
||||
|
||||
public void setAlignment(int alignment) {
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
public int getMarginL() {
|
||||
return marginL;
|
||||
}
|
||||
|
||||
public void setMarginL(int marginL) {
|
||||
this.marginL = marginL;
|
||||
}
|
||||
|
||||
public int getMarginR() {
|
||||
return marginR;
|
||||
}
|
||||
|
||||
public void setMarginR(int marginR) {
|
||||
this.marginR = marginR;
|
||||
}
|
||||
|
||||
public int getMarginV() {
|
||||
return marginV;
|
||||
}
|
||||
|
||||
public void setMarginV(int marginV) {
|
||||
this.marginV = marginV;
|
||||
}
|
||||
|
||||
public int getAlphaLevel() {
|
||||
return alphaLevel;
|
||||
}
|
||||
|
||||
public void setAlphaLevel(int alphaLevel) {
|
||||
this.alphaLevel = alphaLevel;
|
||||
}
|
||||
|
||||
public int getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public void setEncoding(int encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user