/*
* @(#)SUBPICTURE.java - creates SUP file to use as DVD subtitles
*
* Copyright (c) 2003-2011 by dvb.matt, All Rights Reserved.
*
* This file is part of ProjectX, a free Java based demux utility.
* By the authors, ProjectX is intended for educational purposes only,
* as a non-commercial test project.
*
*
* This program is free software; you can redistribute it 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://sam.zoy.org/writings/dvd/subtitles/
*/
/*
* multicolor subtitling patch (UK Freeview) by Duncan (Shannock9) UK
* 2008-12
*/
package net.sourceforge.dvb.projectx.subtitle;
//
import java.awt.Image;
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.HashMap;
import java.util.Arrays;
import java.util.StringTokenizer;
import net.sourceforge.dvb.projectx.common.Resource;
import net.sourceforge.dvb.projectx.common.Keys;
import net.sourceforge.dvb.projectx.common.Common;
import net.sourceforge.dvb.projectx.parser.CommonParsing;
public class Subpicture extends Object {
private int w = Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_enableHDSub) ? 1920 : 720;
private int h = Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_enableHDSub) ? 1088 : 576;
private int x = 20;
private int default_alpha = 10;
private int modified_alpha = 0;
private BufferedImage bimg;
private Graphics2D big;
private Font font, font_std;
private FontRenderContext frc;
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 basic_teletext_colors[] = {
//bg & ft = 0..7
0xFF101010, //black 0
0xFFEB1010, //red 1
0xFF10EB10, //green 2
0xFFEBEB10, //yellow 3
0xFF1010EB, //blue 4
0xFFEB10EB, //magenta 5
0xFF10EBEB, //cyan 6
0xFFEBEBEB, //white 7
0xFF801010, //red2 8
0xFF108010, //green2 9
0xFF808010, //yellow2 A
0xFF101080, //blue2 B
0xFF801080, //magenta2C
0xFF108080, //cyan2 D
0xFF808080, //white2 E
0x80 // backgr blue, F 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 int[] alternative_sup_colors = new int[17];
private Object[] textrows = 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
/** control block defs, after picture
0, 0, // next contr sequ.
1, // start displ. //0 means force display
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
(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[11];
private int[] standard_values = { 26, 10, 32, 80, 560, 720, 576, -1, 4, 3, 1 };
private int isforced_status = 0;
private int ismulticolor_status = 0;
private int textrow_height = 28;
private ArrayList user_color_table = new ArrayList();
private ArrayList ccb_list = new ArrayList();
private Bitmap bitmap;
private boolean ReadFromImage = false;
private boolean GlobalError = false;
private int X_Offset = 0;
private int Y_Offset = 0;
private int DisplayMode = 0;
public DVBSubpicture dvb = new DVBSubpicture();
public ColorAreas s9CA = new ColorAreas(); //S9
/**
*
*/
public Subpicture()
{
bimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
big = bimg.createGraphics();
set("Tahoma", ("26;10;32;80;560;720;576;-1;4;2;1"));
frc = big.getFontRenderContext();
// big.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
/**
*
*/
public void repaint()
{
if (big == null)
return;
Common.getGuiInterface().repaintSubpicture();
}
/**
*
*/
public Image getImage()
{
return bimg;
}
/**
*
*/
public Image getScaledImage(int scaled_w, int scaled_h)
{
return bimg.getScaledInstance(scaled_w, scaled_h, Image.SCALE_FAST);
}
/**
* set display time
*/
public int setTime(long in_time, long out_time)
{
int difference = (int)(1L + ((out_time - in_time) / 1024));
Common.getGuiInterface().setSubpictureTitle(" / " + Resource.getString("subpicture.in_time") + ": " + Common.formatTime_1(in_time / 90) + " " + Resource.getString("subpicture.duration") + ": " + Common.formatTime_1((out_time - in_time) / 90) );
// if (debug)
// System.out.println("in " + in_time + "/out " + out_time + "/d1 " + (out_time - in_time) + "/90 " + ((out_time - in_time)/90) + "/d2 " + difference);
return difference;
}
/**
* paint any picture, for export it should only have 2bit depth
*/
public void paintPicture(byte[] array, int _width, int _height, int _scansize, int _x, int _y)
{
big.setColor(Color.gray);
big.fillRect(0, 0, w, h);
// bimg.setRGB(_x, _y, _width, _height, array, 0, _scansize);
repaint();
}
/**
* create pic from ttx
*/
public void createPictureFromTeletext(Object[] _textrows, Object obj)
{
textrows = _textrows;
paintPictureFromTeletext(obj);
repaint();
}
/**
* paint Image from ttx
*/
private void paintPictureFromTeletext(Object obj)
{
int space = 4; // space at top & bottom
big.setFont(font);
int font_height = (int)font.getMaxCharBounds(frc).getHeight();
//determine top and bottom string overhead
int textrow_shift = 2 + font_height - textrow_height;
//top left x of rectangle
Rect[0] = option[3];
//max width of rectangle for export
Rect[2] = option[4];
//max height of rectangle for export
Rect[3] = (2 * space) + (font_height * textrows.length);
//top left y of rectangle -> frame_height - bottom_offset - rectangle height
Rect[1] = option[6] - option[2] - Rect[3];
//all x,y of rectangle outside
pos[0] = Rect[0];
pos[1] = Rect[1];
pos[2] = Rect[0] + Rect[2] - 1;
pos[3] = Rect[1] + Rect[3] - 1;
paintVideoSize(obj);
paintPictureRectangle(Rect, pos);
big.setFont(font); // re-activate font
int color_table[] = getColorTable(1);
ArrayList colors_list = new ArrayList();
boolean antialiasing;
// pre-check, whether we have not more than supported 'speaker-colors'
for (int i = 0; i < textrows.length; i++)
{
int[] chars = (int[]) textrows[i];
for (int j = 0, bgcolor_index, paint_color; j < chars.length; j++)
{
//source background color
bgcolor_index = (7 & chars[j]>>>4)<<3;
//source modified foreground color
paint_color = color_table[bgcolor_index + (7 & chars[j])];
String nstr = Integer.toString(paint_color);
String sign = new Character((char)(chars[j]>>>8)).toString();
//remember new color
if (colors_list.indexOf(nstr) < 0 && !sign.equals(" "))
colors_list.add(nstr);
}
}
// define background; if less than supported number of front-colors,
// use 'simple' antialiasing with full transparency
// if (list.size() < 3 && Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_useTextOutline))
if (colors_list.size() < 15 && Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_useTextOutline))
{
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;
}
// paint entire background, either black or transparent color
big.fillRect(Rect[0], Rect[1], Rect[2], Rect[3]);
// paint outline background of char
for (int i = 0, y; antialiasing && i < textrows.length; i++)
{
int[] chars = (int[]) textrows[i];
String nstr = "";
big.setColor(new Color(color_table[64])); // black
// concatenate string, no special colors required
for (int j = 0; j < chars.length; j++)
nstr += new Character((char)(chars[j]>>>8)).toString();
x = option[3];
y = Rect[1] + space + (font_height * (1 + i));
int[] offs = new int[(option[9] * 2) + 1];
// overhead around a pixel: x pix WEST, 1 pix MID, x pix EAST
// pix > 4 not recommended, option[9] = outline_pixels
offs[0] = offs[offs.length - 1] = option[9] - 1;
Arrays.fill(offs, 1, offs.length - 1, option[9]);
for (int j = 0, _x, _y; j < offs.length; j++) // horiz. lines
{
_x = x;
_y = y - (offs.length / 2) + j;
for (int k = -offs[j]; k < offs[j] + 1; k++)
big.drawString(nstr, _x + k, _y - textrow_shift);
}
}
ccb_list.clear();
ChangeColorControlBlock ccb = new ChangeColorControlBlock(); //init as base
// paint all chars front colors
for (int i = 0, y; i < textrows.length; i++)
{
int[] chars = (int[]) textrows[i];
int ftcolor_index = -1;
int last_ftcolor_index = -1;
String str;
x = option[3];
y = Rect[1] + space + (font_height * (1 + i));
for (int j = 0, bgcolor_index; j < chars.length; j++)
{
//source background color
bgcolor_index = (7 & chars[j]>>>4)<<3;
ftcolor_index = color_table[bgcolor_index + (7 & chars[j])];
str = String.valueOf((char)(chars[j]>>>8));
//initiate new block def, exclude space chars
if (ftcolor_index != last_ftcolor_index)
{
ccb = new ChangeColorControlBlock();
ccb.bottom_line = y; //+5
ccb.top_line = ccb.bottom_line - font_height;//+3
ccb.left_column = x;
ccb.right_column = ccb.left_column + (int)font.getStringBounds(str, frc).getWidth();
ccb.color_index = ftcolor_index;
ccb.ftcolor = 7 & chars[j];
ccb.bgcolor = (7 & chars[j])>>4;
ccb.string = str;
ccb.row = i;
ccb_list.add(ccb);
}
else //move end of column to the right at same color of next char
{
ccb.right_column = x + (int)font.getStringBounds(str, frc).getWidth();
ccb.string += str;
}
last_ftcolor_index = ftcolor_index;
//source foreground color
big.setColor(new Color(ftcolor_index));
big.drawString(str, x, y - textrow_shift);
x += font.getStringBounds(str, frc).getWidth();
}
}
//remove empty strings area definitions
for (int i = 0; i < ccb_list.size(); )
{
ccb = (ChangeColorControlBlock) ccb_list.get(i);
if (ccb.string.trim().length() == 0)
ccb_list.remove(i);
else
i++;
}
}
class ChangeColorControlBlock {
public int top_line = 0;
public int bottom_line = 0;
public int left_column = 0;
public int right_column = 0;
public int color_index = 0;
public int ftcolor = 0;
public int bgcolor = 0;
public String string = "";
public int row = 0;
}
private int paintVideoSize(Object obj)
{
String[] str = (String[]) obj;
int video_horizontal = w;
int video_vertical = h;
// H
video_horizontal = str[0] == null ? video_horizontal : Integer.parseInt(str[0]);
// V
video_vertical = str[1] == null ? video_vertical : Integer.parseInt(str[1]);
//deep red background to verify picture rectangle with given video resolution
big.setColor(new Color(0xFF550000));
big.fillRect(0, 0, w, h);
//picture area which the subpicture must not exceed, have to adjust to the hor. middle of it
big.setColor(Color.gray);
big.fillRect(0, 0, video_horizontal, video_vertical);
return video_vertical;
}
private void paintPictureRectangle(int[] Rect, int[] pos)
{
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);
}
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 i = 0; i < pixel.length; i++)
{
String pixel_str = String.valueOf(pixel[i]);
if (!user_color_table.contains(pixel_str))
user_color_table.add(pixel_str);
bitmap.getColorIndex(getUserColorTableIndex(pixel[i]));
}
}
private void updateUserColorTable(int pixel[])
{
for (int i = 0; i < pixel.length; i++)
{
String pixel_str = String.valueOf(pixel[i]);
if (user_color_table.contains(pixel_str))
continue;
user_color_table.add(pixel_str);
}
}
private int getUserColorTableIndex(int color_index)
{
int value;
if ((value = user_color_table.indexOf(String.valueOf(color_index))) < 0)
return 0;
return value;
}
public byte[] writeRLE(long start_time, int onscreen_time) throws IOException
{
ReadFromImage = true; // use user defined alpha value for color index 0
//ceates bitmap from painted preview image
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 createRLEPicture();
}
public byte[] writeRLE(Bitmap new_bitmap) throws IOException
{
//takes given bitmap
bitmap = new_bitmap;
setArea();
return createRLEPicture();
}
private byte[] createRLEPicture()
{
byte picture_packet[] = null;
try {
if (ColorAreas.active) //multicolor DVB to SUP active //S9
resetUserColorTable(); //so retention counterproductive //S9
updateUserColorTable(bitmap.getPixel()); //base code re-ordered //S9
if (ColorAreas.active) //multicolor DVB to SUP active //S9
s9CA.analyse(bitmap, getUserColorTable()); //which can correct noisy pixels!! //S9
int pixels[] = bitmap.getPixel(); //base code re-ordered //S9
out.reset();
out.write(RLEheader); //start picture in .sup form
int bottom_field_start_pos = 0;
int pgc_color = 0; //holds bp12 for a run of pixels //S9
int[] nibble_value = new int[2];
// 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 (ColorAreas.active) //multicolor DVB to SUP active //S9
pgc_color = s9CA.bp12[a + b]; //bp12 was filled during analyse() //S9
else //pre-existing approach but fewer runs//S9
{
pgc_color = pixels[a + b];
// pgc_color = bitmap.getColorIndex(getUserColorTableIndex(color_index)); //S9
// pgc_color = bitmap.getColorIndex(pgc_color);
}
if (s9CA.active && s9CA.dbgline() == a / bitmap.getWidth()) //see every pixel on specific dbgline //S9dbg
{
int q = s9CA.getQuant(getUserColorTableIndex(pixels[a + b])); //quant as Integer //S9dbg
System.out.println("dbg line " + s9CA.d(3, a / bitmap.getWidth()) + "/x " + s9CA.d(3, b) //S9dbg
+ "/pixel " + s9CA.X(8, pixels[a + b]) + "/clr_ndx " + s9CA.X(2, color_index) //S9dbg
+ "/pgc_clr " + s9CA.X(2, pgc_color) + "/Q " + s9CA.X(8, q) + "/run " + s9CA.d(3, l));
} //S9dbg
if (pgc_color != color_index) //S9
{
// write last RLE nibbles, while color change
updateRLE(l, color_index, nibble_value);
color_index = pgc_color; //S9
l = 0;
}
else if ( l > 254 )
{
// write last RLE nibbles, cannot incl. more than 255 pixels
updateRLE(l, color_index, nibble_value);
l = 0;
}
// std: adds l-bit to active color
}
// when last pixel is length = 1 then it will be 0 and missing ?
// see CR
//l -= 1;
while ( l > 255 ) // never used ?!
{
updateRLE(255, color_index, nibble_value);
l -= 255;
}
updateRLE(l, color_index, nibble_value); // write last RLE nibbles, line end
alignRLE(nibble_value);
if (b < bitmap.getWidth()) //fix, add CR only when less pixel have been painted
out.write(newline); // new line CR, byte aligned
}
alignRLE(nibble_value);
if (bottom_field_start_pos == 0)
bottom_field_start_pos = out.size() - 10; // save startpos of bottom_field (size-14)
}
if (ColorAreas.active) //++multicolor DVB to SUP active++ //S9
{ //S9
//commands() must encapsulate command buffer design - do not patch command buffer from //S9
//here. All delay timing fields will be set by commands() from information in bitmap //S9
int command_start_pos = out.size() - 10; //offset in subpic >including 1st delay< //S9
out.write(s9CA.commands(command_start_pos, bottom_field_start_pos, bitmap));//cmd buffer //S9
if ((out.size() & 1) == 1)
out.write((byte)0xFF);
out.flush();
//Fixups to integrate command buffer into subpic are legitimate part of this method //S9
//Note "0xFF &" is redundant - the (byte) cast does that anyway. Mask only needed //S9
//for moving byte to int (implicitly or explicitly) to overcome any sign extension. //S9
picture_packet = out.toByteArray();
int size = picture_packet.length - 10;
picture_packet[10] = (byte)(0xFF & size>>>8);
picture_packet[11] = (byte)(0xFF & size);
picture_packet[12] = (byte)(0xFF & command_start_pos>>>8); //S9
picture_packet[13] = (byte)(0xFF & command_start_pos); //S9
for (int a = 0; a < 4; a++)
picture_packet[a + 2] = (byte)(0xFF & bitmap.getInTime()>>>(a * 8));
} //S9
else //++original code pre multicolor DVB++ //S9
{ //S9
//RLE picture data completed
int coded_picture_length = out.size() - 10; //minus 10 bytes RLE header in buffer
byte[][] section_value = new byte[11][];
//section_value[0] see later
section_value[1] = setStartDisplay(); //1, xx start, not forced
section_value[2] = setPGCsection(); //3, color + 4, alpha
section_value[3] = setScreenPosition(bitmap.getX(), bitmap.getY(), bitmap.getMaxX() - 1, bitmap.getMaxY() - 1); //5, xxx
section_value[4] = setFieldStartPosition(bottom_field_start_pos); //6, xxxx
section_value[5] = setChangeColorAlpha(section_value[2]); //7, xxxx , may be empty
section_value[6] = setEndOfSequence(); //EOS
section_value[7] = setDisplayTime(bitmap.getPlayTime()); // xx, delay time for next control sequence
//section_value[8] see later
section_value[9] = setStopDisplay(); //2
section_value[10] = setEndOfSequence(); //EOS
int control_block_pos = coded_picture_length + 4; //incl. 4byte for 2x length info
for (int s = 1; s < 7; s++)
control_block_pos += section_value[s].length;
section_value[0] = setControlBlockPosition(control_block_pos); //0+1, 24+25 (alt), 2mal verwenden
section_value[8] = section_value[0]; //repeat control_block_pos
//0, 0 = delaytime for 1st command
out.write(newline);
//write control_blocks
for (int s = 0; s < section_value.length; s++)
out.write(section_value[s]);
//align to word
if ((out.size() & 1) == 1)
out.write((byte)0xFF);
out.flush();
picture_packet = out.toByteArray();
int picture_packet_length = picture_packet.length - 10;
picture_packet[10] = (byte)(picture_packet_length>>>8);
picture_packet[11] = (byte) picture_packet_length;
picture_packet[12] = (byte)(coded_picture_length>>>8);
picture_packet[13] = (byte) coded_picture_length;
for (int a = 0; a < 4; a++) //set pts
picture_packet[a + 2] = (byte)(0xFF & bitmap.getInTime()>>>(a * 8));
} //++endif original code pre multicolor DVB++ //S9
if (s9CA.dbgSub(1))
s9CA.dumpHdrAndCmd(picture_packet); //so what was generated? //S9dbg
} catch (IOException e) {
Common.setExceptionMessage(e);
}
ReadFromImage = false;
ccb_list.clear();
if (picture_packet.length >= 0xFFFF)
Common.setMessage("!> error: subpicture exceeds 65k size limit");
return picture_packet;
}
// write last nibble, if it was not aligned
private void alignRLE(int[] nibble_value)
{
if (nibble_value[0] == 0)
return;
else
{
out.write((byte)nibble_value[1]);
nibble_value[1] = nibble_value[0] = 0;
}
}
// private void updateRLE(int l, int pgc_color) //S9
private void updateRLE(int l, int color_index, int[] nibble_value) //S9
{
if (l < 1)
return;
//pgc_color shall not exceed value 3! //S9
int pgc_color = getUserColorTableIndex(color_index);
//look-up of pgc_color refactored to caller <= it's the RESOLVED 2 bits we want runs of //S9
if (ColorAreas.active)
pgc_color = color_index;
else
pgc_color = bitmap.getColorIndex(pgc_color);
l = l<<2 | pgc_color; // combine bits + color_index
// new byte begin
if (nibble_value[0] == 0)
{
if (l > 0xFF) // 16
{
out.write((byte)(0xFF & l>>>8));
out.write((byte)(0xFF & l));
}
else if (l > 0x3F) // 12
{
out.write((byte)(0xFF & l>>>4));
nibble_value[1] = 0xF0 & l<<4;
nibble_value[0] = 4;
}
else if (l > 0xF) // 8
out.write((byte)(0xFF & l));
else // 4
{
nibble_value[1] = 0xF0 & l<<4;
nibble_value[0] = 4;
}
return;
}
// middle of byte
if (l > 0xFF) // 16
{
out.write((byte)(nibble_value[1] | (0xF & l>>>12)));
out.write((byte)(0xFF & l>>>4));
nibble_value[1] = 0xF0 & l<<4;
}
else if (l > 0x3F) // 12
{
out.write((byte)(nibble_value[1] | (0xF & l>>>8)));
out.write((byte)(0xFF & l));
nibble_value[1] = nibble_value[0] = 0;
}
else if (l > 0xF) // 8
{
out.write((byte)(nibble_value[1] | (0xF & l>>>4)));
nibble_value[1] = 0xF0 & l<<4;
}
else // 4
{
out.write((byte)(nibble_value[1] | (0xF & l)));
nibble_value[1] = nibble_value[0] = 0;
}
}
// control_block
private byte[] setControlBlockPosition(int control_block_pos)
{
return new byte[] { (byte)(control_block_pos>>>8), (byte)control_block_pos };
}
// color index 3,2 + 1,0
// alpha index 3,2 + 1,0
private byte[] setPGCsection()
{
int pgc_values = setPGClinks();
return new byte[] { 3, (byte)(pgc_values>>>8), (byte)pgc_values, 4, (byte)(pgc_values>>>24), (byte)(pgc_values>>>16) };
}
public int setPGClinks()
{
Object pgc_color_links[] = bitmap.getColorIndices();
Object pgc_alpha_links[] = getUserColorTableArray();
int pgc_colors = 0xFE10;
int pgc_alphas = 0xFFF9;
int pgc_color_value;
int pgc_alpha_value;
for (int i = 0; i < 4; i++)
{
if (i < pgc_color_links.length)
{
pgc_color_value = 0xF & Integer.parseInt(pgc_color_links[i].toString());
pgc_alpha_value = 0xF & Integer.parseInt(pgc_alpha_links[pgc_color_value].toString())>>>28;
pgc_colors = (pgc_colors & ~(0xF<<(i * 4))) | pgc_color_value<<(i * 4);
pgc_alphas = (pgc_alphas & ~(0xF<<(i * 4))) | pgc_alpha_value<<(i * 4);
}
}
if (ReadFromImage)
// pgc_alphas &= (0xFFF0 | default_alpha);
pgc_alphas &= (0xFFF0 | modified_alpha);
return (pgc_alphas<<16 | pgc_colors);
}
// set planned pic pos. on tvscreen
private byte[] setScreenPosition(int minX, int minY, int maxX, int maxY)
{
return new byte[] { 5, (byte)(minX>>>4), (byte)(minX<<4 | maxX>>>8), (byte)maxX, (byte)(minY>>>4), (byte)(minY<<4 | maxY>>>8), (byte)maxY };
}
// top_field
// bottom_field
private byte[] setFieldStartPosition(int bottom_field_start_pos)
{
return new byte[] { 6, 0, 4, (byte)(bottom_field_start_pos>>>8), (byte)bottom_field_start_pos };
}
private byte[] setChangeColorAlpha(byte[] PGCcontrol)
{
ChangeColorControlBlock ccb;
HashMap ccb_color = new HashMap();
//remove area definitions when less than 3 front colors (means no enhancement necessary => fallback)
for (int i = 0; i < ccb_list.size(); )
{
ccb = (ChangeColorControlBlock) ccb_list.get(i);
if (!ccb_color.containsKey(String.valueOf(ccb.color_index)))
ccb_color.put(String.valueOf(ccb.color_index), "0");
if (ccb_color.size() < 3)
ccb_list.remove(i);
else
i++;
}
// no change to apply
if (ccb_list.size() == 0)
return new byte[0];
byte[] control = { 7, 0, 0 }; //control, size word
byte[] row_header = { 0, 0, 0, 0 }; //0 + topline + count (max 15) + bottomline
byte[] data_block = { 0, 0, 0, 0, 0, 0 }; //left column 0000, color 3210, transp 3210
byte[] end_block = { 0x0F, (byte)0xFF, (byte)0xFF, (byte)0xFF };
ArrayList cnt_list = new ArrayList();
ByteArrayOutputStream block = new ByteArrayOutputStream();
try {
block.write(control);
int cnt = 0;
for (int i = 0, last_row = -1, ftcolor; i < ccb_list.size(); i++)
{
ccb = (ChangeColorControlBlock) ccb_list.get(i);
if (cnt > 0 && ccb.row != last_row)
{
cnt_list.add(new Integer(cnt));
cnt = 0;
}
if (cnt == 0)
{
row_header[0] = (byte)(ccb.top_line>>>8);
row_header[1] = (byte) ccb.top_line;
row_header[2] = (byte)(ccb.bottom_line>>>8);
row_header[3] = (byte) ccb.bottom_line;
block.write(row_header);
}
last_row = ccb.row;
ftcolor = getUserColorTableIndex(ccb.color_index); //must be < 15
if (cnt > 15) //max 15 parameters per row
continue;
data_block[0] = (byte)(ccb.left_column>>>8);
data_block[1] = (byte) ccb.left_column;
data_block[2] = (byte)(ftcolor | ftcolor<<4); //color 3,2
// data_block[2] = PGCcontrol[1]; //color 3,2
data_block[3] = PGCcontrol[2]; //color 1,0
data_block[4] = PGCcontrol[4]; //alpha 3,2 FF
data_block[5] = PGCcontrol[5]; //alpha 1,0 F0
block.write(data_block);
cnt++;
}
//last row numbers
if (cnt > 0)
cnt_list.add(new Integer(cnt));
block.write(end_block);
block.flush();
} catch (Exception e) {
Common.setExceptionMessage(e);
}
byte[] controlblock = block.toByteArray();
//add numbers in control field
for (int i = 0, j = 5; i < cnt_list.size(); i++)
{
int cnt = ((Integer) cnt_list.get(i)).intValue();
controlblock[j] = (byte)((cnt<<4) | (0xF & controlblock[j]));
j += 4 + (cnt * 6);
}
//set length
int length = controlblock.length - 1;
controlblock[1] = (byte)(length>>>8);
controlblock[2] = (byte)(length);
return controlblock;
}
private byte[] setDisplayTime(int display_time)
{
return new byte[] { (byte)(display_time>>>8), (byte)display_time }; //(display-) time to next control sequence
}
private byte[] setStartDisplay()
{
return new byte[] { 1 }; //start, not forced
}
private byte[] setStopDisplay()
{
return new byte[] { 2 }; //stop
}
private byte[] setEndOfSequence()
{
return new byte[] { (byte)0xFF }; //end of sequence
}
public int getMaximumLines()
{
return option[8];
}
public void set2()
{
option[2] = option[7];
}
/***
* set user packet ("Font pointsize; Backgr. Alpha value; Yoffset; Xoffset; Screenwidth");
*/
public int[] set(String nm, String values)
{
return set(nm, values, false);
}
/***
* set user packet ("Font pointsize; Backgr. Alpha value; Yoffset; Xoffset; Screenwidth");
*/
public int[] set(String nm, String values, boolean keepColourTable)
{
if (!keepColourTable)
resetUserColorTable();
System.arraycopy(standard_values, 0, option, 0, standard_values.length);
StringTokenizer st = new StringTokenizer(values, ";");
int a = 0;
while (st.hasMoreTokens() && a < option.length)
option[a++] = Integer.parseInt(st.nextToken());
textrow_height = option[0];
default_alpha = 0xF & option[1];
font = new Font(nm, option[10] == 0 ? Font.PLAIN : Font.BOLD, option[0]);
font_std = new Font("Tahoma", Font.PLAIN, 14); //DM01032004 081.6 int18 add
int[] ret_val = { option[2], option[7] };
return ret_val;
}
/**
* define alternative color_table
*/
public int[] getColorTable(int flag)
{
if (flag == 1)
return default_teletext_colors;
if (flag == 2)
return basic_teletext_colors;
if (alternative_sup_colors[0] == 0)
return default_sup_colors;
return alternative_sup_colors;
}
/**
*
*/
public void setColorTable(int[] values)
{
//define alternative color_table here
if (values == null)
Arrays.fill(alternative_sup_colors, 0);
else
System.arraycopy(values, 0, alternative_sup_colors, 0, values.length);
}
/**
*
*/
private void setArea()
{
Rect[0] = bitmap.getX();
Rect[1] = bitmap.getY();
Rect[2] = bitmap.getWidth();
Rect[3] = bitmap.getHeight();
pos[0] = bitmap.getX();
pos[1] = bitmap.getY();
pos[2] = bitmap.getMaxX();
pos[3] = bitmap.getMaxY();
}
/**
*
*/
public String getArea()
{
String area = "";
area += "x " + Rect[0];
area += " y " + Rect[1];
area += " w " + Rect[2];
area += " h " + Rect[3];
area += " x1 " + pos[0];
area += " y1 " + pos[1];
area += " x2 " + pos[2];
area += " y2 " + pos[3];
return area;
}
/**
*
*/
private void Set_Bits(byte buf[], int BPos[], int N, int Val)
{
int Pos = BPos[1]>>>3;
int BitOffs = BPos[1] & 7;
if (Pos >= buf.length || BitOffs + N >= (BPos[1] & ~7) + 32)
{
GlobalError = true;
}
else
{
int NoOfBytes = 1 + ((BitOffs + N - 1)>>>3);
int NoOfBits = NoOfBytes<<3;
int tmp_value = CommonParsing.getIntValue(buf, Pos, NoOfBytes, !CommonParsing.BYTEREORDERING);
int mask = (-1)>>>(32 - N);
int k = NoOfBits - N - BitOffs;
mask <<= k;
Val <<= k;
tmp_value &= ~mask;
tmp_value |= (Val & mask);
CommonParsing.setValue(buf, Pos, NoOfBytes, !CommonParsing.BYTEREORDERING, tmp_value);
}
BPos[1] += N;
BPos[0] = BPos[1]>>>3;
}
/**
*
*/
private int Get_Bits(byte buf[], int BPos[], int N)
{
int Pos, Val;
Pos = BPos[1]>>>3;
if (Pos >= buf.length)
{
GlobalError = true;
BPos[1] += N;
BPos[0] = BPos[1]>>>3;
return 0;
}
Val = (0xFF & buf[Pos++])<<24;
if (Pos < buf.length)
Val |= (0xFF & buf[Pos++])<<16;
if (Pos < buf.length)
Val |= (0xFF & buf[Pos++])<<8;
if (Pos < buf.length)
Val |= (0xFF & buf[Pos]);
Val <<= BPos[1] & 7;
Val >>>= 32-N;
BPos[1] += N;
BPos[0] = BPos[1]>>>3;
return Val;
}
/**
*
*/
private int Show_Bits(byte buf[], int BPos[], int N)
{
int Pos, Val;
Pos = BPos[1]>>>3;
if (Pos >= buf.length)
{
GlobalError = true;
return 0;
}
Val = (0xFF & buf[Pos++])<<24;
if (Pos < buf.length)
Val |= (0xFF & buf[Pos++])<<16;
if (Pos < buf.length)
Val |= (0xFF & buf[Pos++])<<8;
if (Pos < buf.length)
Val |= (0xFF & buf[Pos]);
Val <<= BPos[1] & 7;
Val >>>= 32 - N;
return Val;
}
/**
*
*/
private void Flush_Bits(int BPos[], int N)
{
BPos[1] += N;
BPos[0] = BPos[1]>>>3;
}
/**
*
*/
private void align_Bits(int BPos[])
{
if ((1 & BPos[1]>>>2) != 0)
Flush_Bits( BPos, 4);
}
/**
*
*/
public String isForced_Msg()
{
return isForced_Msg(0);
}
/**
*
*/
public String isForced_Msg(int val)
{
String str = null;
//change of status occured
if ((isforced_status & 1) == 0 || val == 1)
str = (isforced_status & 2) > 0 ? Resource.getString("subpicture.msg.forced.no") : Resource.getString("subpicture.msg.forced.yes");
isforced_status |= 1;
return str;
}
/**
*
*/
public void reset()
{
isforced_status = 0;
ismulticolor_status = 0;
set_XY_Offset(0, 0);
setDisplayMode(0);
}
/**
* modify X,Y Position
*/
public void set_XY_Offset(int x_value, int y_value)
{
X_Offset = x_value;
Y_Offset = y_value;
}
/**
* modify force display flag
*/
public void setDisplayMode(int value)
{
DisplayMode = value;
}
/**
*
*/
public int decode_picture(byte[] packet, int off, boolean decode, Object obj)
{
return decode_picture(packet, off, decode, obj, 0, false, true);
}
/**
*
*/
public int decode_picture(byte[] packet, int off, boolean decode, Object obj, Image previewImage, int previewflags)
{
return decode_picture(packet, off, decode, obj, 0, false, true, previewImage, previewflags);
}
/**
*
*/
public int decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible)
{
return decode_picture(packet, off, decode, obj, pts, save, visible, null, 0);
}
/**
*
*/
public int decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible, Image previewImage, int previewflags)
{
ReadFromImage = false;
GlobalError = false;
boolean simple_picture = false;
int picture_length = packet.length;
int[] BPos = { off, off<<3 }; //BytePos, BitPos
int[] position = new int[4];
int[] start_pos = new int[3];
int default_indices = 0;
ArrayList colcon = new ArrayList();
if (BPos[0] > picture_length)
return -4;
int packetlength = Get_Bits(packet, BPos, 16); // required pack length
if (Show_Bits(packet, BPos, 24) == 0xF) // DVB subpicture: 8bit padding 0x00 + 8bit subtitle_stream_id 0x00 + start of subtitle segment 0x0F
{
big.setFont(font_std);
byte[] data = new byte[picture_length + 4];
System.arraycopy(packet, 0, data, 0, picture_length);
int ret = dvb.decodeDVBSubpicture(data, BPos, big, bimg, pts, save, visible);
if (ret > -2)
repaint();
return ret;
}
if (BPos[0] + packetlength != picture_length + 2)
return -5;
start_pos[2] = Get_Bits(packet, BPos, 16) - 2;
Flush_Bits(BPos, start_pos[2]<<3); // jump to sections chunk
//fixed pos, so it must follow the 1st ctrl sequ,
//delay of 2nd ctrl sequ execution - usually stop displaying
int playtime_pos = Get_Bits(packet, BPos, 16);
if (playtime_pos == start_pos[2] + 2)
{
playtime_pos = packetlength;
simple_picture = true;
Common.setMessage(Resource.getString("subpicture.msg2"));
}
else
start_pos[2] += off + 2;
int[] color_table = getColorTable(0);
while (BPos[0] < off + playtime_pos) // read sections chunk
{
int cmd_switch = Show_Bits(packet, BPos, 8); // show at first, to enable editing
switch(cmd_switch)
{
case 0: // force display flag
isforced_status = (isforced_status & 5) != 5 ? 4 : 5;
if (DisplayMode == 2) //set normal
Set_Bits(packet, BPos, 8, 1);
else
Flush_Bits(BPos, 8);
break;
case 1: // start display flag, normal
isforced_status = (isforced_status & 3) != 3 ? 2 : 3;
if (DisplayMode == 1) //set forced
Set_Bits(packet, BPos, 8, 0);
else
Flush_Bits(BPos, 8);
break;
case 2: // stop display flag
Flush_Bits(BPos, 8);
break;
case 3: // 4 color links
Flush_Bits(BPos, 8);
default_indices |= 0xFFFF & Get_Bits(packet, BPos, 16);
break;
case 4: // alpha blending
Flush_Bits(BPos, 8);
default_indices |= (0xFFFF & Get_Bits(packet, BPos, 16))<<16;
break;
case 5: // x,y pos.
Flush_Bits(BPos, 8);
if (X_Offset != 0) //move X-pos
{
position[0] = Show_Bits(packet, BPos, 12) + X_Offset; //X-links
Set_Bits(packet, BPos, 12, position[0]); //X-links
position[1] = Show_Bits(packet, BPos, 12) + X_Offset; //X-rechts
Set_Bits(packet, BPos, 12, position[1]); //X-rechts
}
else
{
position[0] = Get_Bits(packet, BPos, 12); //X-links
position[1] = Get_Bits(packet, BPos, 12); //X-rechts
}
if (Y_Offset != 0) //move Y-pos
{
position[2] = Show_Bits(packet, BPos, 12) + Y_Offset; //Y-oben
Set_Bits(packet, BPos, 12, position[2]); //Y-oben
position[3] = Show_Bits(packet, BPos, 12) + Y_Offset; //Y-unten
Set_Bits(packet, BPos, 12, position[3]); //Y-unten
}
else
{
position[2] = Get_Bits(packet, BPos, 12); //X-links
position[3] = Get_Bits(packet, BPos, 12); //X-rechts
}
break;
case 6: // pos. of decode_start of a field
Flush_Bits(BPos, 8);
for (int b = 0; b < 2; b++)
start_pos[b] = Get_Bits(packet, BPos, 16);
break;
case 7: // extra alpha + color area definition
Flush_Bits(BPos, 8);
int blen = Get_Bits(packet, BPos, 16); // get length
if (ismulticolor_status == 0)
{
ismulticolor_status |= 1;
Common.setMessage("-> contains extra area definitions!");
}
int area_size = 0;
int endofcmd = BPos[0] + blen;
while (BPos[0] < endofcmd)
{
area_size = Show_Bits(packet, BPos, 32); // read 4 bytes linenumbers & def. index
if (area_size == 0x0FFFFFFF) //end marker
{
Flush_Bits(BPos, 32);
break;
}
if (Y_Offset != 0) //move Y-pos
{
area_size = (0xF000 & area_size) | ((0xFFF & area_size>>16) + Y_Offset)<<16 | ((0xFFF & area_size) + Y_Offset); //Y
Set_Bits(packet, BPos, 32, area_size);
}
else
Flush_Bits(BPos, 32);
for (int i = 0, j = 0xF & area_size>>12; i < j; i++) //parameter count
{
int[] area_defs = new int[5]; // 5 parameters
area_defs[0] = 0xFFF & area_size>>16; //from top line number
area_defs[1] = 0xFFF & area_size; //to bottom line number
if (X_Offset != 0) //move X-pos
{
area_defs[2] = Show_Bits(packet, BPos, 16) + X_Offset; // read 2 bytes column, start of def.
Set_Bits(packet, BPos, 16, area_defs[2]); //set new
}
else
area_defs[2] = Get_Bits(packet, BPos, 16); // read 2 bytes column, start of def.
area_defs[3] = Get_Bits(packet, BPos, 16); // read 2 bytes 4x new index of color
area_defs[4] = Get_Bits(packet, BPos, 16); // read 2 bytes 4x new index of contrast
colcon.add(area_defs);
}
}
break;
case 0xFF: // end of ctrl sequ.
Flush_Bits(BPos, 8);
break;
default:
Common.setMessage(Resource.getString("subpicture.msg3") + ": " + cmd_switch);
Flush_Bits(BPos, 8);
}
}
if (off + playtime_pos != BPos[0])
return -6;
int playtime = 0;
if (!simple_picture)
{
playtime = Get_Bits(packet, BPos, 16);
if (playtime_pos != Get_Bits(packet, BPos, 16))
return -7;
if (Get_Bits(packet, BPos, 8) != 2)
return -8;
Flush_Bits( BPos, ((BPos[0] & 1) != 1) ? 16 : 8 );
}
if (BPos[0] != picture_length)
return -9;
if (GlobalError)
return -3;
if (!decode)
return (playtime * 1024); //DM26052004 081.7 int03 changed , 900, 1000
start_pos[0] += off;
start_pos[1] += off;
paintVideoSize(obj);
//paint picture at background, fixed size
if (previewImage != null)
{
int aro = Common.getMpvDecoderClass().getMpg2AspectRatioOffset();
big.setColor(new Color(0xFF505050));
big.fillRect(0, 0, w, h);
int pic_preview_width = 0xFFF & previewflags >> 20;
int pic_preview_height = 0xFFF & previewflags >> 8;
if (aro != 0) //4:3 portion of widescreen preview
big.drawImage(previewImage, 0, 0, pic_preview_width, pic_preview_height, 64, 0, 448, 288, null);
else if ((previewflags & 2) != 0) // letterbox of widescreen
{
int blackborder = (pic_preview_height - ((pic_preview_height * 3) / 4)) / 2;
big.drawImage(previewImage, 0, blackborder, pic_preview_width, (pic_preview_height * 3) / 4, null);
}
else // anamorph widescreen
big.drawImage(previewImage, 0, 0, pic_preview_width, pic_preview_height, null);
}
int x0 = position[0];
int y0 = position[2];
int width = position[1] - position[0] + 1;
int height = position[3] - position[2] + 1;
big.setColor(Color.white);
big.drawRect(x0 - 1, y0 - 1, width + 1, height + 1);
big.setFont(font_std);
big.drawString("x" + x0 + ", y" + y0 + " / " + width + "*" + height
+ " , C-" + Common.adaptString(Integer.toHexString(0xFFFF & default_indices).toUpperCase(), 4)
+ ", T-" + Common.adaptString(Integer.toHexString(0xFFFF & default_indices>>16).toUpperCase(), 4)
, x0 + 1, y0 - 5);
//
// subarray - color index for each pixel 0xFFFFFFFF = Contrast/Color 32103210
int[] colcon_indices = new int[width * height];
// default filling, keeps default when no other def's exist
Arrays.fill(colcon_indices, default_indices);
// fill with new def's
for (int b = 0; (previewflags & 8) == 0 && b < colcon.size(); b++)
{
int[] area_defs = (int[]) colcon.get(b); // one def block
// replace indices per line from column to end
for (int i = (area_defs[0] - y0) * width, j = (area_defs[1] - y0) * width; i < j; i += width)
Arrays.fill(colcon_indices, i + area_defs[2] - x0, i + width, area_defs[3] | area_defs[4]<<16);
// area_defs[2] 2 bytes column, start of def.
// area_defs[3] 2 bytes 4x new index of color
// area_defs[4] 2 bytes 4x new index of contrast
}
//
for (int b = 0; b < 2; b++) // 2 fields painting
{
int Val = 0, x1 = x0, y1 = y0 + b;
BPos[1] = (BPos[0] = start_pos[b])<<3; // top_field at first
while (BPos[0] < start_pos[b + 1]) // stop at pos_marker
{
if ((Val = Get_Bits(packet, BPos, 4)) > 3) //4..F (0..3 never encodable)
x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 0xF) //10..3F
x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 0x3F) //40..FF
x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 3) //100..3FF
x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
else // 0 forced carriage return
{
if ((Val & 3) != 0)
{
Val |= (width - x1)<<2;
x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
}
x1 = x0;
y1 += 2;
align_Bits(BPos);
continue;
}
// line end, carriage return
if (x1 > position[1])
{
x1 = position[0];
y1 += 2;
align_Bits(BPos);
}
}
}
// paint rectangles of extra col-con definitions
for (int i = colcon.size() - 1; (previewflags & 4) == 0 && i >= 0; i--)
{
int[] area_defs = (int[]) colcon.get(i);
big.setColor(Color.magenta);
big.drawRect(area_defs[2] - 1, area_defs[0] - 1, width - area_defs[2] + x0 + 1, area_defs[1] - area_defs[0]);
big.setColor(Color.yellow);
big.drawString("area: " + i + " - " + area_defs[0] + ", " + area_defs[1] + ", " + area_defs[2]
+ ", C-" + Common.adaptString(Integer.toHexString(area_defs[3]).toUpperCase(), 4)
+ ", T-" + Common.adaptString(Integer.toHexString(area_defs[4]).toUpperCase(), 4)
, position[0], y0 - 22 - (i * 16));
}
repaint();
if (GlobalError)
return -3;
return (playtime * 1024); //DM26052004 081.7 int03 changed, 900, 1000
}
/**
* paint preview pixel from .sup
*/
private int paintPixel(int Val, int x1, int y1, int[] colcon_indices, int[] color_table, int x0, int y0, int width, int previewflags)
{
int table_index = Val & 3;
int line_length = Val>>>2;
int array_index;
int contrast_index = 0;
int color_index = 0;
boolean opaque = (previewflags & 0x10) != 0;
big.setColor(new Color(0));
for (int j = x1 + line_length, color, lastcolor = 0; x1 < j; x1++)
{
array_index = (y1 - y0) * width + x1 - x0;
//error condition
if (array_index >= colcon_indices.length)
break;
contrast_index = 0xF & colcon_indices[array_index]>>(16 + table_index * 4);
color_index = 0xF & colcon_indices[array_index]>>(table_index * 4);
// set ARGB color
color = (0x11 * (0xF ^ contrast_index))<<24 | (color_table[color_index] & 0xFFFFFF);
// check for a change
if (color != lastcolor)
big.setColor(new Color(color)); // needs (color, true) for alpha - but with less performance
lastcolor = color;
if (opaque || contrast_index > 0) // dont paint full transp. pixel
big.drawLine(x1, y1, x1, y1);
// big.drawLine(x1, y1, x1 + 1, y1);
}
return x1;
}
}