📄 subpicture.java
字号:
/*
* @(#)SUBPICTURE.java - creates SUP file to use as DVD subtitles
*
* Copyright (c) 2003-2005 by dvb.matt, All Rights Reserved.
*
* This file is part of X, a free Java based demux utility.
* X is intended for educational purposes only, as a non-commercial test project.
* It may not be used otherwise. Most parts are only experimental.
*
*
* This program is free software; you can redistribute it free of charge
* and/or modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* thanx to Samuel Hocevar for his very helpful annotations of DVD subtitle RLE stuff
* http://www.via.ecp.fr/~sam/doc/dvd/
*/
package net.sourceforge.dvb.projectx.subtitle;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.image.BufferedImage;
import java.awt.geom.Rectangle2D;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.sourceforge.dvb.projectx.common.Resource;
import net.sourceforge.dvb.projectx.common.X;
public class SubPicture extends JFrame
{
public Picture picture;
String title = Resource.getString("subpicture.title");
public SubPicture()
{
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
close();
}
});
picture = new Picture();
picture.run(); //DM18052004 081.7 int02 add
getContentPane().add("Center", picture);
setTitle(title);
setSize(new Dimension(726,601)); //DM24012004 081.6 int11 changed, //DM20042004 081.7 int02 changed
setLocation(100,100);
setResizable(false); //DM17042004 081.7 int02 add
//setVisible(false);
}
public void newTitle(String newtitle)
{
setTitle(title+" "+newtitle);
}
public void close()
{
dispose(); //DM18052004 081.7 int02 changed
}
public class Picture extends JPanel implements Runnable
{
public java.text.DateFormat sms = new java.text.SimpleDateFormat("HH:mm:ss.SSS");
public Thread thread;
private int w=720, h=576, x=20, nibble=0, val=0, default_alpha=10; //DM24012004 081.6 int11 changed, //DM20042004 081.7 int02 changed
private int modified_alpha = 0;
private BufferedImage bimg;
private Graphics2D big;
private Font font, font_alt, font_std; //DM30122003 081.6 int10 add, //DM01032004 081.6 int18 add
private FontRenderContext frc;
//DM26052004 081.7 int03 changed
private final int default_teletext_colors[] = {
//bg = 0 = black
0xFF606060, //Y 40%
0xFFEB6060, //red lighter
0xFF10EB10, //green
0xFFEBEB10, //yellow
0xFF5050EB, //blue lighter
0xFFEB60EB, //magenta lighter
0xFF10EBEB, //cyan
0xFFEBEBEB, //Y 100%
//bg = 1 = red
0xFF606060, //Y black
0xFFE06060, //red
0xFF60E060, //green
0xFFE0E060, //yellow
0xFF6060E0, //blue
0xFFE060E0, //magenta
0xFF60E0E0, //cyan
0xFFE0E0E0, //white-gray
//bg = 2 = green
0xFF707070, //Y black
0xFFD07070, //red
0xFF70D070, //green
0xFFD0D070, //yellow
0xFF7070D0, //blue
0xFFD070D0, //magenta
0xFF70D0D0, //cyan
0xFFD0D0D0, //white-gray
//bg = 3 = yellow
0xFF808080, //Y black
0xFFC08080, //red
0xFF80C080, //green
0xFFC0C080, //yellow
0xFF8080C0, //blue
0xFFC080C0, //magenta
0xFF80C0C0, //cyan
0xFFC0C0C0, //white-gray
//bg = 4 = blue
0xFF909090, //Y black
0xFFC09090, //red
0xFF90C090, //green
0xFFC0C090, //yellow
0xFF9090C0, //blue
0xFFC090C0, //magenta
0xFF90C0C0, //cyan
0xFFB0B0B0, //white-gray
//bg = 5 = magenta
0xFFA0A0A0, //Y black
0xFFB0A0A0, //red
0xFFA0B0A0, //green
0xFFB0B0A0, //yellow
0xFFA0A0B0, //blue
0xFFB0A0B0, //magenta
0xFFA0B0B0, //cyan
0xFFA0A0A0, //white-gray
//bg = 6 = cyan
0xFFB0B0B0, //Y black
0xFFC0A0A0, //red
0xFFA0D0A0, //green
0xFFC0D0A0, //yellow
0xFFA0A0D0, //blue
0xFFD0A0D0, //magenta
0xFFA0D0D0, //cyan
0xFF909090, //white-gray
//bg = 7 = white
0xFFD0D0D0, //Y black
0xFFE09090, //red
0xFF90E090, //green
0xFFE0E090, //yellow
0xFF9090E0, //blue
0xFFE090E0, //magenta
0xFF90E0E0, //cyan
0xFF808080, //white-gray
0, // backgr black, user_transparency
0x80 // backgr blue, sign for full transparency
};
private final int default_sup_colors[] = {
0xFF101010, //black
0xFFA0A0A0, //Y 50%
0xFFEBEBEB, //Y 100%
0xFF606060, //Y 25%
0xFFEB1010, //red
0xFF10EB10, //green
0xFFEBEB10, //yellow
0xFF1010EB, //blue
0xFFEB10EB, //magenta
0xFF10EBEB, //cyan
0xFFEB8080, //red lighter
0xFF80EB80, //green lighter
0xFFEBEB80, //yellow lighter
0xFF8080EB, //blue lighter
0xFFEB80EB, //magante lighter
0xFF80EBEB, //cyan lighter
0 // full transparency black bg
};
private Object[] str = new Object[0];
private byte[] RLEheader = { 0x53,0x50,0,0,0,0,0,0,0,0,0,0,0,0 }; // startcode + later reverse 5PTS, DTS=0
private byte[] sections = {
0, 0, // next contr sequ.
3, 0x32, 0x10, // color palette linkage
4, (byte)0xFF, (byte)0xFA, // color alpha channel linkage F=opaque
5, 0, 0, 0, 0, 0, 0, // coordinates Xa,Ya,Xe,Ye
6, 0, 0, 0, 0, // bytepos start top_field, start bottom_field
1, // start displ. //0 means force display
(byte)0xFF, // end of sequ.
1, 0x50, // time for next sequ,
0, 0, //next contr sequ.
2, // stop displ.
(byte)0xFF // end of sequ: timedur in pts/1100, size s.a. , add 0xFF if size is not WORD aligned
};
private ByteArrayOutputStream out = new ByteArrayOutputStream();
private byte newline[] = { 0,0 };
private int Rect[] = new int[4];
private int pos[] = new int[4];
private int option[] = new int[10]; //DM26052004 081.7 int03 changed
//DM26052004 081.7 int03 changed
private int standard_values[] = { 26, 10, 32, 80, 560, 720, 576, -1, 4 };
private ArrayList user_color_table = new ArrayList();
private Bitmap bitmap;
private boolean read_from_Image = false;
private int isforced_status = 0;
private boolean global_error = false;
private int line_offset = 28;
public DVBSubpicture dvb = new DVBSubpicture(); //DM24042004 081.7 int02 new
public Picture()
{
bimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
big = bimg.createGraphics();
set("Tahoma", ("" + "26;10;32;80;560;720;576;-1;4"));
frc = big.getFontRenderContext();
// big.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
setBackground(Color.gray);
sms.setTimeZone(java.util.TimeZone.getTimeZone("GMT+0:00"));
}
public void paint(Graphics g)
{
if (big == null)
return;
g.drawImage(bimg, 0, 0, this);
}
/*** paint pic from ttx **/
public void showPicTTX(Object[] str)
{
this.str = str;
buildImgTTX();
repaint();
}
// set display time
//DM22032004 081.6 int18 changed
//DM26052004 081.7 int03 changed
public byte[] setTime(byte tmp[], long out_time)
{
long in_time = 0;
for (int a=0; a<4; a++) // in_pts
in_time |= (0xFF & tmp[a+2])<<(a*8);
//long difference = (long)Math.round((out_time - in_time) / 1100.0); // 900.0
long difference = 1L + ((out_time - in_time) / 1000);
int tp = (0xFF & tmp[12])<<8 | (0xFF & tmp[13]);
tmp[34+tp] = (byte)(0xFF & difference>>>8);
tmp[35+tp] = (byte)(0xFF & difference);
newTitle(" / " + Resource.getString("subpicture.in_time") + ": " + sms.format(new java.util.Date(in_time / 90)) + " " + Resource.getString("subpicture.duration") + ": " + sms.format(new java.util.Date((out_time - in_time) / 90)) );
return tmp;
}
/*** build Image from text **/
//DM30122003 081.6 int10 changed
//DM05052004 081.7 int02 changed
public void buildImgTTX()
{
int space = 6;
Rect[0] = option[3];
//Rect[3] = (2 * space) + (option[0] * str.length);
Rect[3] = (2 * space) + (line_offset * str.length);
Rect[1] = option[6] - option[2] - Rect[3];
Rect[2] = option[4];
pos[0] = Rect[0];
pos[1] = Rect[1];
pos[2] = Rect[0] + Rect[2] - 1;
pos[3] = Rect[1] + Rect[3] - 1;
//DM08032004 081.6 int18 add
paintVideoSize();
big.setColor(Color.white);
big.drawRect(Rect[0] - 1, Rect[1] - 1, Rect[2] + 1, Rect[3] + 1);
big.setFont(font_std);
big.drawString("x" + pos[0] + ", y" + pos[1] + " / " + (pos[2] - pos[0] + 1) + "*" + (pos[3] - pos[1] + 1), Rect[0] - 1, Rect[1] - 5);
int color_table[] = getColorTable(1);
big.setFont(font);
ArrayList list = new ArrayList();
boolean antialiasing;
/**
* pre-check, whether we have not more than 2 'speaker-colors'
*/
for (int a = 0; a < str.length; a++)
{
int[] chars = (int[])str[a];
for (int b = 0; b < chars.length; b++)
{
//source background color
int offset = (7 & chars[b]>>>4)<<3;
//source modified foreground color
int paint_color = color_table[offset + (7 & chars[b])];
String str = Integer.toString(paint_color);
String sign = new Character((char)(chars[b]>>>8)).toString();
//remember new color
if (list.indexOf(str) < 0 && !sign.equals(" "))
list.add(str);
}
}
/**
* define background; if less than 3 front-colors, use 'simple' antialiasing with full transparency
*/
if (list.size() < 3 && X.cBox[79].isSelected())
{
big.setColor(new Color(color_table[65])); // deep blue, full transp
modified_alpha = 0;
antialiasing = true;
}
else
{
big.setColor(new Color(color_table[64])); // black, half transp
modified_alpha = default_alpha;
antialiasing = false;
}
big.fillRect(Rect[0], Rect[1], Rect[2], Rect[3]); // background
Rectangle2D r;
// paint background of char
for (int a = 0; antialiasing && a < str.length; a++)
{
int[] chars = (int[])str[a];
String str = "";
big.setColor(new Color(color_table[64])); // black
/**
* concatenate string, no special colors required
*/
for (int i = 0; i < chars.length; i++)
str += new Character((char)(chars[i]>>>8)).toString();
x = option[3];
//int y = Rect[1] + (option[0] * (1 + a));
int y = Rect[1] + (line_offset * (1 + a));
int[] offs = { 2, 3, 3, 3, 3, 3, 2 };
for (int i = 0; i < offs.length; i++) // horiz. lines
{
int _x = x;
int _y = y - (offs.length / 2) + i;
for (int j = -offs[i]; j < offs[i] + 1; j++)
big.drawString(str, _x + j, _y);
}
}
// paint ascii char
for (int a=0; a < str.length; a++)
{
int[] chars = (int[])str[a];
x = option[3];
//DM26052004 081.7 int03 changed
for (int b=0; b < chars.length; b++)
{
//source background color
int offset = (7 & chars[b]>>>4)<<3;
//source foreground color
big.setColor(new Color(color_table[offset + (7 & chars[b])]));
//big.drawString("" + (char)(chars[b]>>>8), x, Rect[1] + (option[0] * (1 + a)));
big.drawString("" + (char)(chars[b]>>>8), x, Rect[1] + (line_offset * (1 + a)));
x += font.getStringBounds("" + (char)(chars[b]>>>8), frc).getWidth();
}
}
}
public void resetUserColorTable()
{
user_color_table.clear();
}
public Object[] getUserColorTableArray()
{
return user_color_table.toArray();
}
public ArrayList getUserColorTable()
{
return user_color_table;
}
public void updateUserColorTable(Bitmap new_bitmap)
{
bitmap = new_bitmap;
int pixel[] = bitmap.getPixel();
for (int a=0; a < pixel.length; a++)
{
String pixel_str = "" + pixel[a];
if (!user_color_table.contains(pixel_str))
user_color_table.add(pixel_str);
bitmap.getColorIndex(getUserColorTableIndex(pixel[a]));
}
}
private void updateUserColorTable(int pixel[])
{
for (int a=0; a < pixel.length; a++)
{
String pixel_str = "" + pixel[a];
if (user_color_table.contains(pixel_str))
continue;
else
user_color_table.add(pixel_str);
}
}
private int getUserColorTableIndex(int color_index)
{
int value;
if ((value = user_color_table.indexOf("" + color_index)) < 0)
return 0;
return value;
}
//DM26052004 081.7 int03 changed
public byte[] writeRLE(long start_time, int onscreen_time) throws IOException
{
read_from_Image = true; // use user defined alpha value for color index 0
bitmap = new Bitmap( Rect[0], Rect[1], Rect[2], Rect[3], bimg.getRGB(Rect[0], Rect[1], Rect[2], Rect[3], null, 0, Rect[2]), 2, 0, 1, 2, start_time, onscreen_time);
return buildRLE();
}
public byte[] writeRLE(Bitmap new_bitmap) throws IOException
{
bitmap = new_bitmap;
setArea();
return buildRLE();
}
private byte[] buildRLE()
{
byte picture_packet[] = null;
try
{
int pixels[] = bitmap.getPixel();
updateUserColorTable(pixels);
out.reset();
out.write(RLEheader); //start picture in .sup form
int bottom_field_start_pos = 0;
// read out interlaced RGB
for (int i=0, l=0, a=0, b=0, color_index=0; i < 2; i++)
{
// top_field first
for (l=0, color_index=0, a = i * bitmap.getWidth(); a < pixels.length; a += (2 * bitmap.getWidth()))
{
for (l=0, color_index=0, b=0; b < bitmap.getWidth(); b++, l++)
{
if (pixels[a + b] != color_index)
{
// write last RLE nibbles, while color change
updateRLE(l, color_index);
color_index = pixels[a + b];
l=0;
}
else if ( l > 254 )
{
// write last RLE nibbles, cannot incl. more than 255 pixels
updateRLE(l, color_index);
l=0;
}
// std: adds l-bit to active color
}
l -= 1;
while ( l > 255 ) // never used ?!
{
updateRLE(255, color_index);
l -= 255;
}
updateRLE(l, color_index); // write last RLE nibbles, line end
alignRLE();
out.write(newline); // new line CR, byte aligned
}
alignRLE();
if (bottom_field_start_pos == 0)
bottom_field_start_pos = out.size() - 10; // save startpos of bottom_field (size-14)
}
out.write(newline); //DM26052004 081.7 int03 add , not the best solution, but need the "0,0" here
int pack = out.size() - 12;
int control_block_pos = pack + 24;
int onscreen_time_pos = out.size() + 22;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -