1 /* 2 * @(#)SUBPICTURE.java - creates SUP file to use as DVD subtitles 3 * 4 * Copyright (c) 2003-2009 by dvb.matt, All Rights Reserved. 5 * 6 * This file is part of ProjectX, a free Java based demux utility. 7 * By the authors, ProjectX is intended for educational purposes only, 8 * as a non-commercial test project. 9 * 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 * 25 */ 26 27 /* 28 * thanx to Samuel Hocevar for his very helpful annotations of DVD subtitle RLE stuff 29 * http://sam.zoy.org/writings/dvd/subtitles/ 30 */ 31 /* 32 * multicolor subtitling patch (UK Freeview) by Duncan (Shannock9) UK 33 * 2008-12 34 */ 35 36 37 package net.sourceforge.dvb.projectx.subtitle; 38 39 // 40 import java.awt.Image; 41 42 import java.awt.Color; 43 import java.awt.Dimension; 44 import java.awt.Font; 45 import java.awt.Graphics; 46 import java.awt.Graphics2D; 47 import java.awt.event.WindowAdapter; 48 import java.awt.event.WindowEvent; 49 import java.awt.font.FontRenderContext; 50 import java.awt.image.BufferedImage; 51 import java.awt.geom.Rectangle2D; 52 import java.io.ByteArrayOutputStream; 53 import java.io.IOException; 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.StringTokenizer; 57 58 import net.sourceforge.dvb.projectx.common.Resource; 59 import net.sourceforge.dvb.projectx.common.Keys; 60 import net.sourceforge.dvb.projectx.common.Common; 61 62 import net.sourceforge.dvb.projectx.parser.CommonParsing; 63 64 65 public class Subpicture extends Object { 66 67 private int w = Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_enableHDSub) ? 1920 : 720; 68 private int h = Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_enableHDSub) ? 1088 : 576; 69 private int x = 20; 70 private int nibble = 0; 71 private int val = 0; 72 private int default_alpha = 10; 73 private int modified_alpha = 0; 74 75 private BufferedImage bimg; 76 private Graphics2D big; 77 private Font font, font_std; 78 private FontRenderContext frc; 79 80 private final int default_teletext_colors[] = { 81 //bg = 0 = black 82 0xFF606060, //Y 40% 83 0xFFEB6060, //red lighter 84 0xFF10EB10, //green 85 0xFFEBEB10, //yellow 86 0xFF5050EB, //blue lighter 87 0xFFEB60EB, //magenta lighter 88 0xFF10EBEB, //cyan 89 0xFFEBEBEB, //Y 100% 90 91 //bg = 1 = red 92 0xFF606060, //Y black 93 0xFFE06060, //red 94 0xFF60E060, //green 95 0xFFE0E060, //yellow 96 0xFF6060E0, //blue 97 0xFFE060E0, //magenta 98 0xFF60E0E0, //cyan 99 0xFFE0E0E0, //white-gray 100 101 //bg = 2 = green 102 0xFF707070, //Y black 103 0xFFD07070, //red 104 0xFF70D070, //green 105 0xFFD0D070, //yellow 106 0xFF7070D0, //blue 107 0xFFD070D0, //magenta 108 0xFF70D0D0, //cyan 109 0xFFD0D0D0, //white-gray 110 111 //bg = 3 = yellow 112 0xFF808080, //Y black 113 0xFFC08080, //red 114 0xFF80C080, //green 115 0xFFC0C080, //yellow 116 0xFF8080C0, //blue 117 0xFFC080C0, //magenta 118 0xFF80C0C0, //cyan 119 0xFFC0C0C0, //white-gray 120 121 //bg = 4 = blue 122 0xFF909090, //Y black 123 0xFFC09090, //red 124 0xFF90C090, //green 125 0xFFC0C090, //yellow 126 0xFF9090C0, //blue 127 0xFFC090C0, //magenta 128 0xFF90C0C0, //cyan 129 0xFFB0B0B0, //white-gray 130 131 //bg = 5 = magenta 132 0xFFA0A0A0, //Y black 133 0xFFB0A0A0, //red 134 0xFFA0B0A0, //green 135 0xFFB0B0A0, //yellow 136 0xFFA0A0B0, //blue 137 0xFFB0A0B0, //magenta 138 0xFFA0B0B0, //cyan 139 0xFFA0A0A0, //white-gray 140 141 //bg = 6 = cyan 142 0xFFB0B0B0, //Y black 143 0xFFC0A0A0, //red 144 0xFFA0D0A0, //green 145 0xFFC0D0A0, //yellow 146 0xFFA0A0D0, //blue 147 0xFFD0A0D0, //magenta 148 0xFFA0D0D0, //cyan 149 0xFF909090, //white-gray 150 151 //bg = 7 = white 152 0xFFD0D0D0, //Y black 153 0xFFE09090, //red 154 0xFF90E090, //green 155 0xFFE0E090, //yellow 156 0xFF9090E0, //blue 157 0xFFE090E0, //magenta 158 0xFF90E0E0, //cyan 159 0xFF808080, //white-gray 160 161 0, // backgr black, user_transparency 162 0x80 // backgr blue, sign for full transparency 163 }; 164 165 private final int default_sup_colors[] = { 166 0xFF101010, //black 167 0xFFA0A0A0, //Y 50% 168 0xFFEBEBEB, //Y 100% 169 0xFF606060, //Y 25% 170 0xFFEB1010, //red 171 0xFF10EB10, //green 172 0xFFEBEB10, //yellow 173 0xFF1010EB, //blue 174 0xFFEB10EB, //magenta 175 0xFF10EBEB, //cyan 176 0xFFEB8080, //red lighter 177 0xFF80EB80, //green lighter 178 0xFFEBEB80, //yellow lighter 179 0xFF8080EB, //blue lighter 180 0xFFEB80EB, //magante lighter 181 0xFF80EBEB, //cyan lighter 182 0 // full transparency black bg 183 }; 184 185 private int[] alternative_sup_colors = new int[17]; 186 187 private Object[] str = new Object[0]; 188 189 private byte[] RLEheader = { 0x53,0x50,0,0,0,0,0,0,0,0,0,0,0,0 }; // startcode + later reverse 5PTS, DTS=0 190 private byte[] sections = { 191 0, 0, // next contr sequ. 192 3, 0x32, 0x10, // color palette linkage 193 4, (byte)0xFF, (byte)0xFA, // color alpha channel linkage F=opaque 194 5, 0, 0, 0, 0, 0, 0, // coordinates Xa,Ya,Xe,Ye 195 6, 0, 0, 0, 0, // bytepos start top_field, start bottom_field 196 1, // start displ. //0 means force display 197 (byte)0xFF, // end of sequ. 198 1, 0x50, // time for next sequ, 199 0, 0, //next contr sequ. 200 2, // stop displ. 201 (byte)0xFF // end of sequ: timedur in pts/1100, size s.a. , add 0xFF if size is not WORD aligned 202 }; 203 204 private ByteArrayOutputStream out = new ByteArrayOutputStream(); 205 206 private byte newline[] = { 0,0 }; 207 208 private int Rect[] = new int[4]; 209 private int pos[] = new int[4]; 210 private int option[] = new int[11]; 211 private int standard_values[] = { 26, 10, 32, 80, 560, 720, 576, -1, 4, 3, 1 }; 212 private int isforced_status = 0; 213 private int ismulticolor_status = 0; 214 private int line_offset = 28; 215 216 private ArrayList user_color_table = new ArrayList(); 217 private Bitmap bitmap; 218 219 private boolean read_from_Image = false; 220 private boolean global_error = false; 221 222 private int X_Offset = 0; 223 private int Y_Offset = 0; 224 private int DisplayMode = 0; 225 226 227 public DVBSubpicture dvb = new DVBSubpicture(); 228 229 public ColorAreas s9CA = new ColorAreas(); //S9 230 231 /** 232 * 233 */ Subpicture()234 public Subpicture() 235 { 236 bimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 237 big = bimg.createGraphics(); 238 239 set("Tahoma", ("26;10;32;80;560;720;576;-1;4;3;1")); 240 frc = big.getFontRenderContext(); 241 242 // big.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 243 } 244 245 /** 246 * 247 */ repaint()248 public void repaint() 249 { 250 if (big == null) 251 return; 252 253 Common.getGuiInterface().repaintSubpicture(); 254 } 255 256 /** 257 * 258 */ getImage()259 public Image getImage() 260 { 261 return bimg; 262 } 263 264 /** 265 * 266 */ getScaledImage(int scaled_w, int scaled_h)267 public Image getScaledImage(int scaled_w, int scaled_h) 268 { 269 return bimg.getScaledInstance(scaled_w, scaled_h, Image.SCALE_FAST); 270 } 271 272 /** 273 * paint any picture, for export it should only have 2bit depth 274 */ paintPicture(byte[] array, int _width, int _height, int _scansize, int _x, int _y)275 public void paintPicture(byte[] array, int _width, int _height, int _scansize, int _x, int _y) 276 { 277 big.setColor(Color.gray); 278 big.fillRect(0, 0, w, h); 279 // bimg.setRGB(_x, _y, _width, _height, array, 0, _scansize); 280 281 repaint(); 282 } 283 284 /** 285 * paint pic from ttx 286 */ showPicTTX(Object[] _str, Object obj)287 public void showPicTTX(Object[] _str, Object obj) 288 { 289 str = _str; 290 buildImgTTX(obj); 291 repaint(); 292 } 293 294 /** 295 * set display time 296 */ setTime(byte tmp[], long out_time)297 public byte[] setTime(byte tmp[], long out_time) 298 { 299 long in_time = 0; 300 301 for (int a = 0; a < 4; a++) // in_pts, from offs 2 302 in_time |= (0xFF & tmp[a + 2])<<(a * 8); 303 304 //long difference = (long)Math.round((out_time - in_time) / 1100.0); // 900.0, should be 1024, not 1000 305 long difference = 1L + ((out_time - in_time) / 1024); 306 307 int tp = (0xFF & tmp[12])<<8 | (0xFF & tmp[13]); 308 tmp[34 + tp] = (byte)(0xFF & difference>>>8); 309 tmp[35 + tp] = (byte)(0xFF & difference); 310 311 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) ); 312 313 // if (debug) 314 // System.out.println("in " + in_time + "/out " + out_time + "/d1 " + (out_time - in_time) + "/90 " + ((out_time - in_time)/90) + "/d2 " + difference); 315 316 return tmp; 317 } 318 319 /** 320 * build Image from text 321 */ buildImgTTX(Object obj)322 private void buildImgTTX(Object obj) 323 { 324 int space = 6; 325 326 Rect[0] = option[3]; 327 Rect[3] = (2 * space) + (line_offset * str.length); 328 Rect[1] = option[6] - option[2] - Rect[3]; 329 Rect[2] = option[4]; 330 331 pos[0] = Rect[0]; 332 pos[1] = Rect[1]; 333 pos[2] = Rect[0] + Rect[2] - 1; 334 pos[3] = Rect[1] + Rect[3] - 1; 335 336 paintVideoSize(obj); 337 338 big.setColor(Color.white); 339 big.drawRect(Rect[0] - 1, Rect[1] - 1, Rect[2] + 1, Rect[3] + 1); 340 big.setFont(font_std); 341 big.drawString("x" + pos[0] + ", y" + pos[1] + " / " + (pos[2] - pos[0] + 1) + "*" + (pos[3] - pos[1] + 1), Rect[0] - 1, Rect[1] - 5); 342 343 int color_table[] = getColorTable(1); 344 345 big.setFont(font); 346 347 ArrayList list = new ArrayList(); 348 boolean antialiasing; 349 350 /** 351 * pre-check, whether we have not more than 2 'speaker-colors' 352 */ 353 for (int a = 0; a < str.length; a++) 354 { 355 int[] chars = (int[])str[a]; 356 357 for (int b = 0; b < chars.length; b++) 358 { 359 //source background color 360 int offset = (7 & chars[b]>>>4)<<3; 361 362 //source modified foreground color 363 int paint_color = color_table[offset + (7 & chars[b])]; 364 String nstr = Integer.toString(paint_color); 365 String sign = new Character((char)(chars[b]>>>8)).toString(); 366 367 //remember new color 368 if (list.indexOf(nstr) < 0 && !sign.equals(" ")) 369 list.add(nstr); 370 } 371 } 372 373 /** 374 * define background; if less than 3 front-colors, use 'simple' antialiasing with full transparency 375 */ 376 if (list.size() < 3 && Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_useTextOutline)) 377 { 378 big.setColor(new Color(color_table[65])); // deep blue, full transp 379 modified_alpha = 0; 380 antialiasing = true; 381 } 382 else 383 { 384 big.setColor(new Color(color_table[64])); // black, half transp 385 modified_alpha = default_alpha; 386 antialiasing = false; 387 } 388 389 big.fillRect(Rect[0], Rect[1], Rect[2], Rect[3]); // background 390 391 Rectangle2D r; 392 393 // paint background of char 394 for (int a = 0; antialiasing && a < str.length; a++) 395 { 396 int[] chars = (int[])str[a]; 397 String nstr = ""; 398 399 big.setColor(new Color(color_table[64])); // black 400 401 /** 402 * concatenate string, no special colors required 403 */ 404 for (int i = 0; i < chars.length; i++) 405 nstr += new Character((char)(chars[i]>>>8)).toString(); 406 407 x = option[3]; 408 int y = Rect[1] + (line_offset * (1 + a)); 409 410 int[] offs = new int[(option[9] * 2) + 1]; 411 412 /** 413 * overhead around a pixel: x pix WEST, 1 pix MID, x pix EAST 414 * pix > 4 not recommended, option[9] = outline_pixels 415 */ 416 offs[0] = offs[offs.length - 1] = option[9] - 1; 417 Arrays.fill(offs, 1, offs.length - 1, option[9]); 418 419 for (int i = 0; i < offs.length; i++) // horiz. lines 420 { 421 int _x = x; 422 int _y = y - (offs.length / 2) + i; 423 424 for (int j = -offs[i]; j < offs[i] + 1; j++) 425 big.drawString(nstr, _x + j, _y); 426 } 427 } 428 429 430 // paint ascii char 431 for (int a=0; a < str.length; a++) 432 { 433 int[] chars = (int[])str[a]; 434 x = option[3]; 435 436 for (int b=0; b < chars.length; b++) 437 { 438 //source background color 439 int offset = (7 & chars[b]>>>4)<<3; 440 441 //source foreground color 442 big.setColor(new Color(color_table[offset + (7 & chars[b])])); 443 big.drawString("" + (char)(chars[b]>>>8), x, Rect[1] + (line_offset * (1 + a))); 444 445 x += font.getStringBounds("" + (char)(chars[b]>>>8), frc).getWidth(); 446 } 447 } 448 } 449 resetUserColorTable()450 public void resetUserColorTable() 451 { 452 user_color_table.clear(); 453 } 454 getUserColorTableArray()455 public Object[] getUserColorTableArray() 456 { 457 return user_color_table.toArray(); 458 } 459 getUserColorTable()460 public ArrayList getUserColorTable() 461 { 462 return user_color_table; 463 } 464 updateUserColorTable(Bitmap new_bitmap)465 public void updateUserColorTable(Bitmap new_bitmap) 466 { 467 bitmap = new_bitmap; 468 469 int pixel[] = bitmap.getPixel(); 470 471 for (int a=0; a < pixel.length; a++) 472 { 473 String pixel_str = "" + pixel[a]; 474 475 if (!user_color_table.contains(pixel_str)) 476 user_color_table.add(pixel_str); 477 478 bitmap.getColorIndex(getUserColorTableIndex(pixel[a])); 479 } 480 } 481 updateUserColorTable(int pixel[])482 private void updateUserColorTable(int pixel[]) 483 { 484 for (int a=0; a < pixel.length; a++) 485 { 486 String pixel_str = "" + pixel[a]; 487 488 if (user_color_table.contains(pixel_str)) 489 continue; 490 491 else 492 user_color_table.add(pixel_str); 493 } 494 } 495 getUserColorTableIndex(int color_index)496 private int getUserColorTableIndex(int color_index) 497 { 498 int value; 499 500 if ((value = user_color_table.indexOf("" + color_index)) < 0) 501 return 0; 502 503 return value; 504 } 505 writeRLE(long start_time, int onscreen_time)506 public byte[] writeRLE(long start_time, int onscreen_time) throws IOException 507 { 508 read_from_Image = true; // use user defined alpha value for color index 0 509 510 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); 511 512 return buildRLE(); 513 } 514 writeRLE(Bitmap new_bitmap)515 public byte[] writeRLE(Bitmap new_bitmap) throws IOException 516 { 517 bitmap = new_bitmap; 518 setArea(); 519 520 return buildRLE(); 521 } 522 buildRLE()523 private byte[] buildRLE() 524 { 525 byte picture_packet[] = null; 526 527 try { 528 529 if (ColorAreas.active) //multicolor DVB to SUP active //S9 530 resetUserColorTable(); //so retention counterproductive //S9 531 532 updateUserColorTable(bitmap.getPixel()); //base code re-ordered //S9 533 534 if (ColorAreas.active) //multicolor DVB to SUP active //S9 535 s9CA.analyse(bitmap, getUserColorTable()); //which can correct noisy pixels!! //S9 536 537 int pixels[] = bitmap.getPixel(); //base code re-ordered //S9 538 539 out.reset(); 540 out.write(RLEheader); //start picture in .sup form 541 542 int bottom_field_start_pos = 0; 543 int pgc_color = 0; //holds bp12 for a run of pixels //S9 544 545 // read out interlaced RGB 546 for (int i = 0, l = 0, a = 0, b = 0, color_index = 0; i < 2; i++) 547 { 548 // top_field first 549 for (l = 0, color_index = 0, a = i * bitmap.getWidth(); a < pixels.length; a += (2 * bitmap.getWidth())) 550 { 551 for (l = 0, color_index = 0, b = 0; b < bitmap.getWidth(); b++, l++) 552 { 553 if (ColorAreas.active) //multicolor DVB to SUP active //S9 554 pgc_color = s9CA.bp12[a + b]; //bp12 was filled during analyse() //S9 555 else //pre-existing approach but fewer runs//S9 556 { 557 pgc_color = pixels[a + b]; 558 // pgc_color = bitmap.getColorIndex(getUserColorTableIndex(color_index)); //S9 559 // pgc_color = bitmap.getColorIndex(pgc_color); 560 } 561 562 if (s9CA.active && s9CA.dbgline() == a / bitmap.getWidth()) //see every pixel on specific dbgline //S9dbg 563 { 564 int q = s9CA.getQuant(getUserColorTableIndex(pixels[a + b])); //quant as Integer //S9dbg 565 566 System.out.println("dbg line " + s9CA.d(3, a / bitmap.getWidth()) + "/x " + s9CA.d(3, b) //S9dbg 567 + "/pixel " + s9CA.X(8, pixels[a + b]) + "/clr_ndx " + s9CA.X(2, color_index) //S9dbg 568 + "/pgc_clr " + s9CA.X(2, pgc_color) + "/Q " + s9CA.X(8, q) + "/run " + s9CA.d(3, l)); 569 } //S9dbg 570 571 if (pgc_color != color_index) //S9 572 { 573 // write last RLE nibbles, while color change 574 updateRLE(l, color_index); 575 color_index = pgc_color; //S9 576 l = 0; 577 } 578 else if ( l > 254 ) 579 { 580 // write last RLE nibbles, cannot incl. more than 255 pixels 581 updateRLE(l, color_index); 582 l = 0; 583 } 584 // std: adds l-bit to active color 585 } 586 587 // when last pixel is length = 1 then it will be 0 and missing ? 588 // see CR 589 //l -= 1; 590 591 while ( l > 255 ) // never used ?! 592 { 593 updateRLE(255, color_index); 594 l -= 255; 595 } 596 597 updateRLE(l, color_index); // write last RLE nibbles, line end 598 alignRLE(); 599 600 if (b < bitmap.getWidth()) //fix, add CR only when less pixel have been painted 601 out.write(newline); // new line CR, byte aligned 602 } 603 604 alignRLE(); 605 606 if (bottom_field_start_pos == 0) 607 bottom_field_start_pos = out.size() - 10; // save startpos of bottom_field (size-14) 608 } 609 610 if (ColorAreas.active) //++multicolor DVB to SUP active++ //S9 611 { //S9 612 //commands() must encapsulate command buffer design - do not patch command buffer from //S9 613 //here. All delay timing fields will be set by commands() from information in bitmap //S9 614 615 int command_start_pos = out.size() - 10; //offset in subpic >including 1st delay< //S9 616 617 out.write(s9CA.commands(command_start_pos, bottom_field_start_pos, bitmap));//cmd buffer //S9 618 619 if ((out.size() & 1) == 1) 620 out.write((byte)255); 621 622 out.flush(); 623 624 //Fixups to integrate command buffer into subpic are legitimate part of this method //S9 625 //Note "0xFF &" is redundant - the (byte) cast does that anyway. Mask only needed //S9 626 //for moving byte to int (implicitly or explicitly) to overcome any sign extension. //S9 627 628 picture_packet = out.toByteArray(); 629 630 int size = picture_packet.length - 10; 631 632 picture_packet[10] = (byte)(0xFF & size>>>8); 633 picture_packet[11] = (byte)(0xFF & size); 634 picture_packet[12] = (byte)(0xFF & command_start_pos>>>8); //S9 635 picture_packet[13] = (byte)(0xFF & command_start_pos); //S9 636 637 for (int a = 0; a < 4; a++) 638 picture_packet[a + 2] = (byte)(0xFF & bitmap.getInTime()>>>(a * 8)); 639 } //S9 640 else //++original code pre multicolor DVB++ //S9 641 { //S9 642 643 out.write(newline); //DM26052004 081.7 int03 add , not the best solution, but need the "0,0" here 644 645 int pack = out.size() - 12; 646 int control_block_pos = pack + 24; 647 int onscreen_time_pos = out.size() + 22; 648 649 setScreenPosition(bitmap.getX(), bitmap.getY(), bitmap.getMaxX() - 1, bitmap.getMaxY() - 1); 650 setControlBlockPosition(control_block_pos, bottom_field_start_pos); 651 setPGCsection(); 652 653 out.write(sections); //write control_block 654 655 if ((out.size() & 1) == 1) 656 out.write((byte)255); 657 658 out.flush(); 659 660 picture_packet = out.toByteArray(); 661 662 int size = picture_packet.length - 10; 663 664 picture_packet[10] = (byte)(0xFF & size>>>8); 665 picture_packet[11] = (byte)(0xFF & size); 666 picture_packet[12] = (byte)(0xFF & pack>>>8); 667 picture_packet[13] = (byte)(0xFF & pack); 668 669 for (int a = 0; a < 4; a++) 670 picture_packet[a + 2] = (byte)(0xFF & bitmap.getInTime()>>>(a * 8)); 671 672 picture_packet[onscreen_time_pos] = (byte)(0xFF & bitmap.getPlayTime()>>>8); 673 picture_packet[onscreen_time_pos + 1] = (byte)(0xFF & bitmap.getPlayTime()); 674 } //++endif original code pre multicolor DVB++ //S9 675 676 if (s9CA.dbgSub(1)) 677 s9CA.dumpHdrAndCmd(picture_packet); //so what was generated? //S9dbg 678 679 } catch (IOException e) { 680 681 Common.setExceptionMessage(e); 682 } 683 684 read_from_Image = false; 685 686 return picture_packet; 687 } 688 689 // write last nibble, if it was not aligned alignRLE()690 private void alignRLE() 691 { 692 if (nibble == 0) 693 return; 694 695 else 696 { 697 out.write((byte)val); 698 val = nibble = 0; 699 } 700 } 701 702 // private void updateRLE(int l, int pgc_color) //S9 updateRLE(int l, int color_index)703 private void updateRLE(int l, int color_index) //S9 704 { 705 if (l < 1) 706 return; 707 708 //pgc_color shall not exceed value 3! //S9 709 int pgc_color = getUserColorTableIndex(color_index); 710 711 //look-up of pgc_color refactored to caller <= it's the RESOLVED 2 bits we want runs of //S9 712 if (ColorAreas.active) 713 pgc_color = color_index; 714 else 715 pgc_color = bitmap.getColorIndex(pgc_color); 716 717 l = l<<2 | pgc_color; // combine bits + color_index 718 719 // new byte begin 720 if (nibble == 0) 721 { 722 if (l > 0xFF) // 16 723 { 724 out.write((byte)(0xFF & l>>>8)); 725 out.write((byte)(0xFF & l)); 726 } 727 else if (l > 0x3F) // 12 728 { 729 out.write((byte)(0xFF & l>>>4)); 730 val = 0xF0 & l<<4; 731 nibble = 4; 732 } 733 else if (l > 0xF) // 8 734 { 735 out.write((byte)(0xFF & l)); 736 } 737 else // 4 738 { 739 val = 0xF0 & l<<4; 740 nibble = 4; 741 } 742 } 743 else // middle of byte 744 { 745 if (l > 0xFF) // 16 746 { 747 out.write((byte)(val | (0xF & l>>>12))); 748 out.write((byte)(0xFF & l>>>4)); 749 val = 0xF0 & l<<4; 750 } 751 else if (l > 0x3F) // 12 752 { 753 out.write((byte)(val | (0xF & l>>>8))); 754 out.write((byte)(0xFF & l)); 755 val = nibble = 0; 756 } 757 else if (l > 0xF) // 8 758 { 759 out.write((byte)(val | (0xF & l>>>4))); 760 val = 0xF0 & l<<4; 761 } 762 else // 4 763 { 764 out.write((byte)(val | (0xF & l))); 765 val = nibble = 0; 766 } 767 } 768 } 769 setScreenPosition(int minX, int minY, int maxX, int maxY)770 private void setScreenPosition(int minX, int minY, int maxX, int maxY) 771 { 772 // set planned pic pos. on tvscreen 773 sections[9] = (byte)(minX>>>4); 774 sections[10] = (byte)(minX<<4 | maxX>>>8); 775 sections[11] = (byte)maxX; 776 sections[12] = (byte)(minY>>>4); 777 sections[13] = (byte)(minY<<4 | maxY>>>8); 778 sections[14] = (byte)maxY; 779 } 780 setControlBlockPosition(int control_block_pos, int bottom_field_start_pos)781 private void setControlBlockPosition(int control_block_pos, int bottom_field_start_pos) 782 { 783 // top_field 784 sections[16] = 0; 785 sections[17] = 4; 786 787 // bottom_field 788 sections[18] = (byte)(0xFF & bottom_field_start_pos>>>8); 789 sections[19] = (byte)(0xFF & bottom_field_start_pos); 790 791 // control_block 792 sections[0] = sections[24] = (byte)(0xFF & control_block_pos>>>8); 793 sections[1] = sections[25] = (byte)(0xFF & control_block_pos); 794 } 795 setPGCsection()796 private void setPGCsection() 797 { 798 int pgc_values = setPGClinks(); 799 800 // color index 3,2 + 1,0 801 sections[3] = (byte)(0xFF & pgc_values>>>8); 802 sections[4] = (byte)(0xFF & pgc_values); 803 804 // alpha index 3,2 + 1,0 805 sections[6] = (byte)(0xFF & pgc_values>>>24); 806 sections[7] = (byte)(0xFF & pgc_values>>>16); 807 } 808 setPGClinks()809 public int setPGClinks() 810 { 811 Object pgc_color_links[] = bitmap.getColorIndices(); 812 Object pgc_alpha_links[] = getUserColorTableArray(); 813 int pgc_colors = 0xFE10; 814 int pgc_alphas = 0xFFF9; 815 int pgc_color_value, pgc_alpha_value; 816 817 for (int a=0; a < 4; a++) 818 { 819 if (a < pgc_color_links.length) 820 { 821 pgc_color_value = 0xF & Integer.parseInt(pgc_color_links[a].toString()); 822 pgc_alpha_value = 0xF & Integer.parseInt(pgc_alpha_links[pgc_color_value].toString())>>>28; 823 pgc_colors = (pgc_colors & ~(0xF<<(a * 4))) | pgc_color_value<<(a * 4); 824 pgc_alphas = (pgc_alphas & ~(0xF<<(a * 4))) | pgc_alpha_value<<(a * 4); 825 } 826 } 827 828 if (read_from_Image) 829 // pgc_alphas &= (0xFFF0 | default_alpha); 830 pgc_alphas &= (0xFFF0 | modified_alpha); 831 832 return (pgc_alphas<<16 | pgc_colors); 833 } 834 set2()835 public void set2() 836 { 837 option[2] = option[7]; 838 } 839 getMaximumLines()840 public int getMaximumLines() 841 { 842 return option[8]; 843 } 844 845 /*** set user packet ("Font pointsize; Backgr. Alpha value; Yoffset; Xoffset; Screenwidth"); **/ set(String nm, String values)846 public int[] set(String nm, String values) 847 { 848 return set(nm, values, false); 849 } 850 851 /*** set user packet ("Font pointsize; Backgr. Alpha value; Yoffset; Xoffset; Screenwidth"); **/ set(String nm, String values, boolean keepColourTable)852 public int[] set(String nm, String values, boolean keepColourTable) 853 { 854 if (!keepColourTable) 855 resetUserColorTable(); 856 857 System.arraycopy(standard_values, 0, option, 0, standard_values.length); 858 859 StringTokenizer st = new StringTokenizer(values, ";"); 860 int a = 0; 861 862 while (st.hasMoreTokens() && a < option.length) 863 { 864 option[a] = Integer.parseInt(st.nextToken()); 865 a++; 866 } 867 868 line_offset = option[0] + 2; 869 default_alpha = 0xF & option[1]; 870 871 font = new Font(nm, option[10] == 0 ? Font.PLAIN : Font.BOLD, option[0]); 872 font_std = new Font("Tahoma", Font.PLAIN, 14); //DM01032004 081.6 int18 add 873 874 int[] ret_val = { option[2], option[7] }; 875 876 return ret_val; 877 } 878 879 /** 880 * 881 */ getColorTable(int flag)882 public int[] getColorTable(int flag) 883 { 884 //define alternative color_table here 885 if (flag == 0) 886 { 887 if (alternative_sup_colors[0] == 0) 888 return default_sup_colors; 889 890 else 891 return alternative_sup_colors; 892 } 893 894 else 895 return default_teletext_colors; 896 } 897 898 /** 899 * 900 */ setColorTable(int[] values)901 public void setColorTable(int[] values) 902 { 903 //define alternative color_table here 904 if (values == null) 905 Arrays.fill(alternative_sup_colors, 0); 906 907 else 908 System.arraycopy(values, 0, alternative_sup_colors, 0, values.length); 909 } 910 911 /** 912 * 913 */ setArea()914 private void setArea() 915 { 916 Rect[0] = bitmap.getX(); 917 Rect[1] = bitmap.getY(); 918 Rect[2] = bitmap.getWidth(); 919 Rect[3] = bitmap.getHeight(); 920 921 pos[0] = bitmap.getX(); 922 pos[1] = bitmap.getY(); 923 pos[2] = bitmap.getMaxX(); 924 pos[3] = bitmap.getMaxY(); 925 } 926 927 /** 928 * 929 */ getArea()930 public String getArea() 931 { 932 String string = ""; 933 string += "x " + Rect[0]; 934 string += " y " + Rect[1]; 935 string += " w " + Rect[2]; 936 string += " h " + Rect[3]; 937 938 string += " x1 " + pos[0]; 939 string += " y1 " + pos[1]; 940 string += " x2 " + pos[2]; 941 string += " y2 " + pos[3]; 942 943 return string; 944 } 945 946 /** 947 * 948 */ paintVideoSize(Object obj)949 private int paintVideoSize(Object obj) 950 { 951 String[] str = (String[]) obj; 952 int video_horizontal = w; 953 int video_vertical = h; 954 955 // H 956 video_horizontal = str[0] == null ? video_horizontal : Integer.parseInt(str[0]); 957 958 // V 959 video_vertical = str[1] == null ? video_vertical : Integer.parseInt(str[1]); 960 961 //deep red background to verify picture rectangle with given video resolution 962 big.setColor(new Color(0xFF550000)); 963 big.fillRect(0, 0, w, h); 964 965 //picture area which the subpicture must not exceed, have to adjust to the hor. middle of it 966 big.setColor(Color.gray); 967 big.fillRect(0, 0, video_horizontal, video_vertical); 968 969 return video_vertical; 970 } 971 972 /** 973 * 974 */ Set_Bits(byte buf[], int BPos[], int N, int Val)975 private void Set_Bits(byte buf[], int BPos[], int N, int Val) 976 { 977 int Pos = BPos[1]>>>3; 978 int BitOffs = BPos[1] & 7; 979 980 if (Pos >= buf.length || BitOffs + N >= (BPos[1] & ~7) + 32) 981 { 982 global_error = true; 983 } 984 985 else 986 { 987 int NoOfBytes = 1 + ((BitOffs + N - 1)>>>3); 988 int NoOfBits = NoOfBytes<<3; 989 990 int tmp_value = CommonParsing.getIntValue(buf, Pos, NoOfBytes, !CommonParsing.BYTEREORDERING); 991 992 int mask = (-1)>>>(32 - N); 993 int k = NoOfBits - N - BitOffs; 994 995 mask <<= k; 996 Val <<= k; 997 998 tmp_value &= ~mask; 999 tmp_value |= (Val & mask); 1000 1001 CommonParsing.setValue(buf, Pos, NoOfBytes, !CommonParsing.BYTEREORDERING, tmp_value); 1002 } 1003 1004 BPos[1] += N; 1005 BPos[0] = BPos[1]>>>3; 1006 } 1007 1008 /** 1009 * 1010 */ Get_Bits(byte buf[], int BPos[], int N)1011 private int Get_Bits(byte buf[], int BPos[], int N) 1012 { 1013 int Pos, Val; 1014 Pos = BPos[1]>>>3; 1015 1016 if (Pos >= buf.length) 1017 { 1018 global_error = true; 1019 BPos[1] += N; 1020 BPos[0] = BPos[1]>>>3; 1021 return 0; 1022 } 1023 1024 Val = (0xFF & buf[Pos++])<<24; 1025 1026 if (Pos < buf.length) 1027 Val |= (0xFF & buf[Pos++])<<16; 1028 1029 if (Pos < buf.length) 1030 Val |= (0xFF & buf[Pos++])<<8; 1031 1032 if (Pos < buf.length) 1033 Val |= (0xFF & buf[Pos]); 1034 1035 Val <<= BPos[1] & 7; 1036 Val >>>= 32-N; 1037 1038 BPos[1] += N; 1039 BPos[0] = BPos[1]>>>3; 1040 1041 return Val; 1042 } 1043 1044 /** 1045 * 1046 */ Show_Bits(byte buf[], int BPos[], int N)1047 private int Show_Bits(byte buf[], int BPos[], int N) 1048 { 1049 int Pos, Val; 1050 Pos = BPos[1]>>>3; 1051 1052 if (Pos >= buf.length) 1053 { 1054 global_error = true; 1055 return 0; 1056 } 1057 1058 Val = (0xFF & buf[Pos++])<<24; 1059 1060 if (Pos < buf.length) 1061 Val |= (0xFF & buf[Pos++])<<16; 1062 1063 if (Pos < buf.length) 1064 Val |= (0xFF & buf[Pos++])<<8; 1065 1066 if (Pos < buf.length) 1067 Val |= (0xFF & buf[Pos]); 1068 1069 Val <<= BPos[1] & 7; 1070 Val >>>= 32 - N; 1071 1072 return Val; 1073 } 1074 1075 /** 1076 * 1077 */ Flush_Bits(int BPos[], int N)1078 private void Flush_Bits(int BPos[], int N) 1079 { 1080 BPos[1] += N; 1081 BPos[0] = BPos[1]>>>3; 1082 } 1083 1084 /** 1085 * 1086 */ align_Bits(int BPos[])1087 private void align_Bits(int BPos[]) 1088 { 1089 if ((1 & BPos[1]>>>2) != 0) 1090 Flush_Bits( BPos, 4); 1091 } 1092 1093 /** 1094 * 1095 */ isForced_Msg()1096 public String isForced_Msg() 1097 { 1098 return isForced_Msg(0); 1099 } 1100 1101 /** 1102 * 1103 */ isForced_Msg(int val)1104 public String isForced_Msg(int val) 1105 { 1106 String str = null; 1107 1108 //change of status occured 1109 if ((isforced_status & 1) == 0 || val == 1) 1110 { 1111 if ((isforced_status & 2) > 0) 1112 str = Resource.getString("subpicture.msg.forced.no"); 1113 1114 else 1115 str = Resource.getString("subpicture.msg.forced.yes"); 1116 } 1117 1118 isforced_status |= 1; 1119 1120 return str; 1121 } 1122 1123 /** 1124 * 1125 */ reset()1126 public void reset() 1127 { 1128 isforced_status = 0; 1129 ismulticolor_status = 0; 1130 set_XY_Offset(0, 0); 1131 setDisplayMode(0); 1132 } 1133 1134 /** 1135 * modify X,Y Position 1136 */ set_XY_Offset(int x_value, int y_value)1137 public void set_XY_Offset(int x_value, int y_value) 1138 { 1139 X_Offset = x_value; 1140 Y_Offset = y_value; 1141 } 1142 1143 /** 1144 * modify force display flag 1145 */ setDisplayMode(int value)1146 public void setDisplayMode(int value) 1147 { 1148 DisplayMode = value; 1149 } 1150 1151 /** 1152 * 1153 */ decode_picture(byte[] packet, int off, boolean decode, Object obj)1154 public int decode_picture(byte[] packet, int off, boolean decode, Object obj) 1155 { 1156 return decode_picture(packet, off, decode, obj, 0, false, true); 1157 } 1158 1159 /** 1160 * 1161 */ decode_picture(byte[] packet, int off, boolean decode, Object obj, Image previewImage, int previewflags)1162 public int decode_picture(byte[] packet, int off, boolean decode, Object obj, Image previewImage, int previewflags) 1163 { 1164 return decode_picture(packet, off, decode, obj, 0, false, true, previewImage, previewflags); 1165 } 1166 1167 /** 1168 * 1169 */ decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible)1170 public int decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible) 1171 { 1172 return decode_picture(packet, off, decode, obj, pts, save, visible, null, 0); 1173 } 1174 1175 /** 1176 * 1177 */ decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible, Image previewImage, int previewflags)1178 public int decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible, Image previewImage, int previewflags) 1179 { 1180 read_from_Image = false; 1181 global_error = false; 1182 1183 boolean simple_picture = false; 1184 int picture_length = packet.length; 1185 1186 int[] BPos = { off, off<<3 }; //BytePos, BitPos 1187 int[] position = new int[4]; 1188 int[] start_pos = new int[3]; 1189 int default_indices = 0; 1190 1191 ArrayList colcon = new ArrayList(); 1192 1193 if (BPos[0] > picture_length) 1194 return -4; 1195 1196 int packetlength = Get_Bits(packet, BPos, 16); // required pack length 1197 1198 if (Show_Bits(packet, BPos, 24) == 0xF) // DVB subpicture: 8bit padding 0x00 + 8bit subtitle_stream_id 0x00 + start of subtitle segment 0x0F 1199 { 1200 big.setFont(font_std); 1201 1202 byte[] data = new byte[picture_length + 4]; 1203 System.arraycopy(packet, 0, data, 0, picture_length); 1204 1205 int ret = dvb.decodeDVBSubpicture(data, BPos, big, bimg, pts, save, visible); 1206 1207 if (ret > -2) 1208 repaint(); 1209 1210 return ret; 1211 } 1212 1213 if (BPos[0] + packetlength != picture_length + 2) 1214 return -5; 1215 1216 start_pos[2] = Get_Bits(packet, BPos, 16) - 2; 1217 Flush_Bits(BPos, start_pos[2]<<3); // jump to sections chunk 1218 1219 //fixed pos, so it must follow the 1st ctrl sequ, 1220 //delay of 2nd ctrl sequ execution - usually stop displaying 1221 int playtime_pos = Get_Bits(packet, BPos, 16); 1222 1223 if (playtime_pos == start_pos[2] + 2) 1224 { 1225 playtime_pos = packetlength; 1226 simple_picture = true; 1227 Common.setMessage(Resource.getString("subpicture.msg2")); 1228 } 1229 else 1230 start_pos[2] += off + 2; 1231 1232 int[] color_table = getColorTable(0); 1233 1234 while (BPos[0] < off + playtime_pos) // read sections chunk 1235 { 1236 int cmd_switch = Show_Bits(packet, BPos, 8); // show at first, to enable editing 1237 1238 switch(cmd_switch) 1239 { 1240 case 0: // force display flag 1241 isforced_status = (isforced_status & 5) != 5 ? 4 : 5; 1242 1243 if (DisplayMode == 2) //set normal 1244 Set_Bits(packet, BPos, 8, 1); 1245 1246 else 1247 Flush_Bits(BPos, 8); 1248 1249 break; 1250 1251 case 1: // start display flag, normal 1252 isforced_status = (isforced_status & 3) != 3 ? 2 : 3; 1253 1254 if (DisplayMode == 1) //set forced 1255 Set_Bits(packet, BPos, 8, 0); 1256 1257 else 1258 Flush_Bits(BPos, 8); 1259 1260 break; 1261 1262 case 2: // stop display flag 1263 Flush_Bits(BPos, 8); 1264 break; 1265 1266 case 3: // 4 color links 1267 Flush_Bits(BPos, 8); 1268 default_indices |= 0xFFFF & Get_Bits(packet, BPos, 16); 1269 break; 1270 1271 case 4: // alpha blending 1272 Flush_Bits(BPos, 8); 1273 default_indices |= (0xFFFF & Get_Bits(packet, BPos, 16))<<16; 1274 break; 1275 1276 case 5: // x,y pos. 1277 Flush_Bits(BPos, 8); 1278 1279 if (X_Offset != 0) //move X-pos 1280 { 1281 position[0] = Show_Bits(packet, BPos, 12) + X_Offset; //X-links 1282 Set_Bits(packet, BPos, 12, position[0]); //X-links 1283 1284 position[1] = Show_Bits(packet, BPos, 12) + X_Offset; //X-rechts 1285 Set_Bits(packet, BPos, 12, position[1]); //X-rechts 1286 } 1287 else 1288 { 1289 position[0] = Get_Bits(packet, BPos, 12); //X-links 1290 position[1] = Get_Bits(packet, BPos, 12); //X-rechts 1291 } 1292 1293 if (Y_Offset != 0) //move Y-pos 1294 { 1295 position[2] = Show_Bits(packet, BPos, 12) + Y_Offset; //Y-oben 1296 Set_Bits(packet, BPos, 12, position[2]); //Y-oben 1297 1298 position[3] = Show_Bits(packet, BPos, 12) + Y_Offset; //Y-unten 1299 Set_Bits(packet, BPos, 12, position[3]); //Y-unten 1300 } 1301 else 1302 { 1303 position[2] = Get_Bits(packet, BPos, 12); //X-links 1304 position[3] = Get_Bits(packet, BPos, 12); //X-rechts 1305 } 1306 1307 break; 1308 1309 case 6: // pos. of decode_start of a field 1310 Flush_Bits(BPos, 8); 1311 1312 for (int b = 0; b < 2; b++) 1313 start_pos[b] = Get_Bits(packet, BPos, 16); 1314 1315 break; 1316 1317 case 7: // extra alpha + color area definition 1318 Flush_Bits(BPos, 8); 1319 int blen = Get_Bits(packet, BPos, 16); // get length 1320 1321 if (ismulticolor_status == 0) 1322 { 1323 ismulticolor_status |= 1; 1324 Common.setMessage("-> contains extra area definitions!"); 1325 } 1326 1327 int area_size = 0; 1328 int endofcmd = BPos[0] + blen; 1329 1330 while (BPos[0] < endofcmd) 1331 { 1332 area_size = Show_Bits(packet, BPos, 32); // read 4 bytes linenumbers & def. index 1333 1334 if (area_size == 0x0FFFFFFF) //end marker 1335 { 1336 Flush_Bits(BPos, 32); 1337 break; 1338 } 1339 1340 if (Y_Offset != 0) //move Y-pos 1341 { 1342 area_size = (0xF000 & area_size) | ((0xFFF & area_size>>16) + Y_Offset)<<16 | ((0xFFF & area_size) + Y_Offset); //Y 1343 Set_Bits(packet, BPos, 32, area_size); 1344 } 1345 else 1346 Flush_Bits(BPos, 32); 1347 1348 for (int i = 0, j = 0xF & area_size>>12; i < j; i++) //parameter count 1349 { 1350 int[] area_defs = new int[5]; // 5 parameters 1351 1352 area_defs[0] = 0xFFF & area_size>>16; //from top line number 1353 area_defs[1] = 0xFFF & area_size; //to bottom line number 1354 1355 if (X_Offset != 0) //move X-pos 1356 { 1357 area_defs[2] = Show_Bits(packet, BPos, 16) + X_Offset; // read 2 bytes column, start of def. 1358 Set_Bits(packet, BPos, 16, area_defs[2]); //set new 1359 } 1360 else 1361 area_defs[2] = Get_Bits(packet, BPos, 16); // read 2 bytes column, start of def. 1362 1363 area_defs[3] = Get_Bits(packet, BPos, 16); // read 2 bytes 4x new index of color 1364 area_defs[4] = Get_Bits(packet, BPos, 16); // read 2 bytes 4x new index of contrast 1365 1366 colcon.add(area_defs); 1367 } 1368 } 1369 1370 break; 1371 1372 case 0xFF: // end of ctrl sequ. 1373 Flush_Bits(BPos, 8); 1374 break; 1375 1376 default: 1377 Common.setMessage(Resource.getString("subpicture.msg3") + ": " + cmd_switch); 1378 Flush_Bits(BPos, 8); 1379 } 1380 } 1381 1382 if (off + playtime_pos != BPos[0]) 1383 return -6; 1384 1385 int playtime = 0; 1386 1387 if (!simple_picture) 1388 { 1389 playtime = Get_Bits(packet, BPos, 16); 1390 if (playtime_pos != Get_Bits(packet, BPos, 16)) 1391 return -7; 1392 1393 if (Get_Bits(packet, BPos, 8) != 2) 1394 return -8; 1395 1396 Flush_Bits( BPos, ((BPos[0] & 1) != 1) ? 16 : 8 ); 1397 } 1398 1399 if (BPos[0] != picture_length) 1400 return -9; 1401 1402 if (global_error) 1403 return -3; 1404 1405 if (!decode) 1406 return (playtime * 1024); //DM26052004 081.7 int03 changed , 900, 1000 1407 1408 1409 for (int b=0; b<2; b++) 1410 start_pos[b] += off; 1411 1412 paintVideoSize(obj); 1413 1414 //paint picture at background, fixed size 1415 if (previewImage != null) 1416 { 1417 int aro = Common.getMpvDecoderClass().getMpg2AspectRatioOffset(); 1418 1419 big.setColor(new Color(0xFF505050)); 1420 big.fillRect(0, 0, w, h); 1421 1422 int pic_preview_width = 0xFFF & previewflags >> 20; 1423 int pic_preview_height = 0xFFF & previewflags >> 8; 1424 1425 if (aro != 0) //4:3 portion of widescreen preview 1426 big.drawImage(previewImage, 0, 0, pic_preview_width, pic_preview_height, 64, 0, 448, 288, null); 1427 1428 else if ((previewflags & 2) != 0) // letterbox of widescreen 1429 { 1430 int blackborder = (pic_preview_height - ((pic_preview_height * 3) / 4)) / 2; 1431 big.drawImage(previewImage, 0, blackborder, pic_preview_width, (pic_preview_height * 3) / 4, null); 1432 } 1433 1434 else // anamorph widescreen 1435 big.drawImage(previewImage, 0, 0, pic_preview_width, pic_preview_height, null); 1436 1437 } 1438 1439 int x0 = position[0]; 1440 int y0 = position[2]; 1441 1442 int width = position[1] - position[0] + 1; 1443 int height = position[3] - position[2] + 1; 1444 1445 big.setColor(Color.white); 1446 big.drawRect(x0 - 1, y0 - 1, width + 1, height + 1); 1447 big.setFont(font_std); 1448 big.drawString("x" + x0 + ", y" + y0 + " / " + width + "*" + height 1449 + " , C-" + Common.adaptString(Integer.toHexString(0xFFFF & default_indices).toUpperCase(), 4) 1450 + ", T-" + Common.adaptString(Integer.toHexString(0xFFFF & default_indices>>16).toUpperCase(), 4) 1451 , x0 + 1, y0 - 5); 1452 1453 // 1454 // subarray - color index for each pixel 0xFFFFFFFF = Contrast/Color 32103210 1455 int[] colcon_indices = new int[width * height]; 1456 1457 // default filling, keeps default when no other def's exist 1458 Arrays.fill(colcon_indices, default_indices); 1459 1460 // fill with new def's 1461 for (int b = 0; (previewflags & 8) == 0 && b < colcon.size(); b++) 1462 { 1463 int[] area_defs = (int[]) colcon.get(b); // one def block 1464 1465 // replace indices per line from column to end 1466 for (int i = (area_defs[0] - y0) * width, j = (area_defs[1] - y0) * width; i < j; i += width) 1467 Arrays.fill(colcon_indices, i + area_defs[2] - x0, i + width, area_defs[3] | area_defs[4]<<16); 1468 1469 // area_defs[2] 2 bytes column, start of def. 1470 // area_defs[3] 2 bytes 4x new index of color 1471 // area_defs[4] 2 bytes 4x new index of contrast 1472 } 1473 // 1474 1475 for (int b = 0; b < 2; b++) // 2 fields painting 1476 { 1477 int Val = 0, x1 = x0, y1 = y0 + b; 1478 BPos[1] = (BPos[0] = start_pos[b])<<3; // top_field at first 1479 1480 while (BPos[0] < start_pos[b + 1]) // stop at pos_marker 1481 { 1482 if ((Val = Get_Bits(packet, BPos, 4)) > 3) //4..F (0..3 never encodable) 1483 x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags); 1484 1485 else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 0xF) //10..3F 1486 x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags); 1487 1488 else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 0x3F) //40..FF 1489 x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags); 1490 1491 else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 3) //100..3FF 1492 x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags); 1493 1494 else // 0 forced carriage return 1495 { 1496 if ((Val & 3) != 0) 1497 { 1498 Val |= (width - x1)<<2; 1499 x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags); 1500 } 1501 1502 x1 = x0; 1503 y1 += 2; 1504 align_Bits(BPos); 1505 continue; 1506 } 1507 1508 // line end, carriage return 1509 if (x1 > position[1]) 1510 { 1511 x1 = position[0]; 1512 y1 += 2; 1513 align_Bits(BPos); 1514 } 1515 } 1516 } 1517 1518 // paint rectangles of extra col-con definitions 1519 for (int i = colcon.size() - 1; (previewflags & 4) == 0 && i >= 0; i--) 1520 { 1521 int[] area_defs = (int[]) colcon.get(i); 1522 1523 big.setColor(Color.magenta); 1524 big.drawRect(area_defs[2] - 1, area_defs[0] - 1, width - area_defs[2] + x0 + 1, area_defs[1] - area_defs[0]); 1525 1526 big.setColor(Color.yellow); 1527 big.drawString("area: " + i + " - " + area_defs[0] + ", " + area_defs[1] + ", " + area_defs[2] 1528 + ", C-" + Common.adaptString(Integer.toHexString(area_defs[3]).toUpperCase(), 4) 1529 + ", T-" + Common.adaptString(Integer.toHexString(area_defs[4]).toUpperCase(), 4) 1530 , position[0], y0 - 22 - (i * 16)); 1531 } 1532 1533 repaint(); 1534 1535 if (global_error) 1536 return -3; 1537 1538 return (playtime * 1024); //DM26052004 081.7 int03 changed, 900, 1000 1539 } 1540 1541 /** 1542 * paint preview pixel from .sup 1543 */ paintPixel(int Val, int x1, int y1, int[] colcon_indices, int[] color_table, int x0, int y0, int width, int previewflags)1544 private int paintPixel(int Val, int x1, int y1, int[] colcon_indices, int[] color_table, int x0, int y0, int width, int previewflags) 1545 { 1546 int table_index = Val & 3; 1547 int line_length = Val>>>2; 1548 int array_index; 1549 int contrast_index = 0; 1550 int color_index = 0; 1551 boolean opaque = (previewflags & 0x10) != 0; 1552 1553 big.setColor(new Color(0)); 1554 1555 for (int j = x1 + line_length, color, lastcolor = 0; x1 < j; x1++) 1556 { 1557 array_index = (y1 - y0) * width + x1 - x0; 1558 1559 //error condition 1560 if (array_index >= colcon_indices.length) 1561 break; 1562 1563 contrast_index = 0xF & colcon_indices[array_index]>>(16 + table_index * 4); 1564 color_index = 0xF & colcon_indices[array_index]>>(table_index * 4); 1565 1566 // set ARGB color 1567 color = (0x11 * (0xF ^ contrast_index))<<24 | (color_table[color_index] & 0xFFFFFF); 1568 1569 // check for a change 1570 if (color != lastcolor) 1571 big.setColor(new Color(color)); // needs (color, true) for alpha - but with less performance 1572 1573 lastcolor = color; 1574 1575 if (opaque || contrast_index > 0) // dont paint full transp. pixel 1576 big.drawLine(x1, y1, x1, y1); 1577 // big.drawLine(x1, y1, x1 + 1, y1); 1578 } 1579 1580 return x1; 1581 } 1582 } 1583