Script de Clases RTF para JSP y PHP


En mi entrada anterior llamada Script de Funciones RTF para JSP y PHP se crearon las funciones para tratar con archivos, tablas e imágenes; pero presentaban el inconveniente de que se podían invocar funciones de manera inapropiada y el usuario tendría que tener un conocimiento más profundo del formato RTF y su sintaxis, además de conocer las funciones y argumentos con mayor detalle.

En esta entrada se explica la creación de unas clases que cumplen los mismos propósitos, métodos públicos para que el usuario pueda crear archivos, tablas y manipular imágenes para cargarlas en los archivos RTF.

Ahora entraremos en detalle sobre nuestras clases para RTF.
Los archivos RTF.jsp y RTF.php almacenarán las mismas tres clases: RTFFile, RTFTable y RTFImage; estos dos archivos son diferentes en su contenido pero igual en propósito a los descritos en la entrada “Script de Funciones RTF para JSP y PHP“.

Script JSP (RTF.jsp)
Primero la importación…

<%@ page import="java.lang.*" %>
<%@ page import="java.io.*" %>
<%@ page errorPage ="error.jsp"%>

Detallando la clase RTFFile

<!-- RTFFile -->
<%!
  public class RTFFile {
    private String HeaderFile = "{\\rtf1"//Indicador RTF
          +"\\ansi\\ansicpg1252"//1252->Western European
          +"\\deff0\\deflang9226 \n";//9226->Español Colombia

    private String[] FamilyFont = {"\n",
          " {\\f1\\fnil\\fprq1\\fcharset0 TlwgMono;}\n",
          " {\\f2\\fswiss\\fprq1\\fcharset0 Arial;}\n",
          " {\\f3\\froman\\fprq1\\fcharset0 Times New Roman;}\n",
          " {\\f4\\fmodern\\fprq1\\fcharset0 Courier New;}\n",
          " {\\f5\\fscript\\fprq1\\fcharset0 Edwardian Script ITC;}\n"}; //Familia de Fuentes
    private String FontTable = "\n{\\fonttbl\n"+FamilyFont[0]+FamilyFont[1]
          +FamilyFont[2]+FamilyFont[3]+FamilyFont[4]+FamilyFont[5]+"}\n";//Tabla de Fuentes

    private String[] Colors = {
          "\\red0\\green0\\blue0;\n", //Negro
          "\\red0\\green0\\blue255;\n", //Azul
          "\\red0\\green255\\blue255;\n", //Cian
          "\\red0\\green255\\blue0;\n", //Verde
          "\\red255\\green0\\blue255;\n", //Magenta
          "\\red255\\green0\\blue0;\n", //Red
          "\\red255\\green255\\blue0;\n", //Amarillo
          "\\red255\\green255\\blue255;\n" //Blanco
           }; //Color de Fuentes
    private String ColorTable = "\n{\\colortbl;\n"+Colors[0]+Colors[1]+Colors[2]+Colors[3]+
          Colors[4]+Colors[5]+Colors[6]+Colors[7]+"}\n";//Tabla de Colores

    private String StartFile = HeaderFile+FontTable+ColorTable;
    private String CloseFile = "}";

    private String[] aAlign = {
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    };//Tipo De Alineación Horizontal de Texto

    private String BasicFormat = "";
    private String OtherFormat = "";
    private String RTFStringFile = "";

    private String NewParg = "\\par ";//Nuevo Parágrafo
    private String NewPage = "\n\\page \\par \n";//Nueva Página
    private String NewLine = "\n\\line";//Nueva Línea

    RTFFile() {
      ResetFile();
    }

    public void ResetFile(){
      this.RTFStringFile = this.StartFile;
    }

    public void CloseFile(){
      this.RTFStringFile += this.CloseFile;
    }

    public String GetFile(){
      return this.RTFStringFile;
    }

    public void InsertLine(){
      this.RTFStringFile += this.NewLine;
    }

    public void InsertPage(){
      this.RTFStringFile += this.NewPage;
    }

    public void InsertParg(){
      this.RTFStringFile += this.NewParg;
    }

    public void AddText(String Text){
      this.RTFStringFile += this.BasicFormat;
      this.RTFStringFile += this.OtherFormat;
      this.RTFStringFile += Text;
      this.RTFStringFile += "\n";
    }

    public void AddElement(String Element){
      this.RTFStringFile += Element;
    }

    public void SetBasicFormatTextFile(int Align, int CFrnt, int CFond, int Fuente, int Talla) {
      String sCFrnt = "\\cf"+String.valueOf(CFrnt);
      String sCFond = "\\highlight"+String.valueOf(CFond);
      String sFuente = "\\f"+String.valueOf(Fuente);
      String sTalla = "\\fs"+String.valueOf(2*Talla);
      this.BasicFormat = this.aAlign[Align]+sCFrnt+sCFond+sFuente+sTalla+"\n";
    }

    public void SetOtherFormatTextFile(int Negrt, int Italc, int Sbryd) {
      String sNegrt = Negrt==0?"\\b0":"\\b";//  Negrita
      String sItalc = Italc==0?"\\i0":"\\i";//  Itálica
      String sSbryd = Sbryd==0?"\\ul0":"\\ul";// Subrayar
      this.OtherFormat = sNegrt+sItalc+sSbryd+"\n";
    }
  }
%>

La clase RTFFile permite crear un archivo de tipo RTF al que le podemos siempre agregar elementos u objetos básicos, nunca retirar, solo limpiar o redisponerlo.

HeaderFile establece codificación y lenguaje predefinido, en mi caso Colombia.
FamilyFont Es un arreglo que nos permite definir nuestro conjunto de familia de fuentes.
FontTable Establece la tabla de fuentes siguiendo el formato interno de RTF.
Colors Este arreglo permite establecer los colores que se usarán en nuestro archivo RTF.
ColorTable Establece la tabla de colores siguiendo el formato de RTF.
StartFile Crea el inicio del archivo RTF, con sus objetos característicos.
CloseFile Es una cadena para cerrar finalmente el archivo RTF cuando se cree.

aAlign Es un arreglo que permite identificar la alineación que se usará en un texto.
BasicFormat Es una cadena que almacena el formato básico en uso del archivo, siempre que se requiera desplegar o mostrar un texto se usará el formato almacenado en esta cadena.
OtherFormat Al igual que el formato básico, esta cadena almacenará formato opcional, es decir no requerido para desplegar un texto en un archivo RTF; aunque internamente siempre acompañará al texto en cuestion, solo que desactaivará los formatos no aplicados.

RTFStringFile Almacena el contenido real del archivo RTF, todo lo que se agregue al archivo RTF, será agregado a esta cadena.

NewParg Es una cadena que se utiliza para agragar un nuevo parágrafo al archivo RTF.
NewPage Es una cadena que sirve para agregar una nueva página al archivo RTF.
NewLine Es una cadena útil para insertar una nueva línea al archivo RTF.

RTFFile() Es el constructor de la clase, al invocarse redispone el archivo RTF.
ResetFile() Limpia el contenido del archivo y solo pone lo que debería llevar al inicio.
CloseFile() Agrega la cadena del cierre o indicador de finalización del archivo.
GetFile() Retorna el contenido del archivo, es decir, el contenido de la cadena RTFStringFile.

InsertLine() Es un método que agrega una nueva línea al archivo RTF.
InsertPage() Este método agrega una página al final del archivo RTF.
InsertParg() Es un método que permite agregar un nuevo parágrafo a nuestro archivo RTF.

AddText(String Text) Permite agregar un texto al final del archivo teniendo encuenta los formatos básicos establecidos en BasicFormat y los formatos opcionales establecidos en OtherFormat.

AddElement(String Element) Permite agregar un elemento al archivo sin tener en cuenta formato alguno.

SetBasicFormatTextFile(int Align, int CFrnt, int CFond, int Fuente, int Talla) Este método permite indicar el formato básico a utilizar inmediatamente de que se llame al mismo. Los parámetros a esteblecer son: Align (Alineación del texto), CFrnt (Color del texto), CFond (Color de fondo), Fuente (Tipo de fuente) y Talla (Tamaño de la fuente).
Estos parámetros se almacenarán en la cadena BasicFormat.

SetOtherFormatTextFile(int Negrt, int Italc, int Sbryd) Similarmente al anterior permite modificar el formato del texto, en caso de que algún parámetro no sea aplicado se aplicará la desactivación del mismo. Los parámetros a establecer son: Negrt (Aplicación de texto en negrita), Italc (Aplicación de texto en itálica) y Sbryd (Aplicación de texto en subrayado). De igual manera los parámetros se almacenarán en la cadena OtherFormat.

Script PHP (RTF.php)
No es necesario hacer importación.
Entonces comencemos con la clase RTFFile

<!-- RTFFile -->
<?php
  class RTFFile {
    private $StartFile = "";
    private $CloseFile = "}";

    private $aAlign = array(
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    );//Tipo De Alineación Horizontal de Texto

    private $BasicFormat = "";
    private $OtherFormat = "";
    private $RTFStringFile = "";

    private $NewParg = "\\par ";//Nuevo Parágrafo
    private $NewPage = "\n\\page \\par \n";//Nueva Página
    private $NewLine = "\n\\line";//Nueva Línea

    private function SetStartFile() {
      $HeaderFile = "{\\rtf1"//Indicador RTF
          ."\\ansi\\ansicpg1252"//1252->Western European
          ."\\deff0\\deflang9226 \n";//9226->Español Colombia

      $FamilyFont = array("\n",
          " {\\f1\\fnil\\fprq1\\fcharset0 TlwgMono;}\n",
          " {\\f2\\fswiss\\fprq1\\fcharset0 Arial;}\n",
          " {\\f3\\froman\\fprq1\\fcharset0 Times New Roman;}\n",
          " {\\f4\\fmodern\\fprq1\\fcharset0 Courier New;}\n",
          " {\\f5\\fscript\\fprq1\\fcharset0 Edwardian Script ITC;}\n"); //Familia de Fuentes
      $FontTable = "\n{\\fonttbl\n".$FamilyFont[0].$FamilyFont[1]
            .$FamilyFont[2].$FamilyFont[3].$FamilyFont[4].$FamilyFont[5]."}\n";//Tabla de Fuentes

      $Colors = array(
          "\\red0\\green0\\blue0;\n", //Negro
          "\\red0\\green0\\blue255;\n", //Azul
          "\\red0\\green255\\blue255;\n", //Cian
          "\\red0\\green255\\blue0;\n", //Verde
          "\\red255\\green0\\blue255;\n", //Magenta
          "\\red255\\green0\\blue0;\n", //Red
          "\\red255\\green255\\blue0;\n", //Amarillo
          "\\red255\\green255\\blue255;\n" //Blanco
           ); //Color de Fuentes

      $ColorTable = "\n{\\colortbl;\n".$Colors[0].$Colors[1].$Colors[2].$Colors[3].
            $Colors[4].$Colors[5].$Colors[6].$Colors[7]."}\n";//Tabla de Colores

      $this->StartFile = $HeaderFile.$FontTable.$ColorTable;  

    }

    public function __construct() {
      $this->ResetFile();
    }

    public function ResetFile(){
      $this->SetStartFile();
      $this->RTFStringFile = $this->StartFile;
    }

    public function CloseFile(){
      $this->RTFStringFile .= $this->CloseFile;
    }

    public function GetFile(){
      return $this->RTFStringFile;
    }

    public function InsertLine(){
      $this->RTFStringFile .= $this->NewLine;
    }

    public function InsertPage(){
      $this->RTFStringFile .= $this->NewPage;
    }

    public function InsertParg(){
      $this->RTFStringFile .= $this->NewParg;
    }

    public function AddText($Text){
      $this->RTFStringFile .= $this->BasicFormat;
      $this->RTFStringFile .= $this->OtherFormat;
      $this->RTFStringFile .= $Text;
      $this->RTFStringFile .= "\n";
    }

    public function AddElement($Element){
      $this->RTFStringFile .= $Element;
    }

    public function SetBasicFormatTextFile($Align, $CFrnt, $CFond, $Fuente, $Talla) {
      $sCFrnt = "\\cf".$CFrnt;
      $sCFond = "\\highlight".$CFond;
      $sFuente = "\\f".$Fuente;
      $sTalla = "\\fs".(2*$Talla);
      global $aAlign;
      $this->BasicFormat = $this->aAlign[$Align].$sCFrnt.$sCFond.$sFuente.$sTalla."\n";
    }

    public function SetOtherFormatTextFile($Negrt,$Italc,$Sbryd) {
      $sNegrt = ($Negrt==0)?"\\b0":"\\b";//  Negrita
      $sItalc = ($Italc==0)?"\\i0":"\\i";//  Itálica
      $sSbryd = ($Sbryd==0)?"\\ul0":"\\ul";// Subrayar
      $sFrmtSP = $sNegrt.$sItalc.$sSbryd."\n";
      $this->OtherFormat = $sFrmtSP;
    }
  }
?>

La diferencia del Script en PHP con el generado en JSP es que las variables miembros de la clase deben tener valores constantes, no tener valores de variables miembros o el resultado de operaciones de variables miembros, sin importar que ese resultado sea producto de variables con valores constantes.
Para construir o darle el valor a $StartFile, se implementó un nuevo método llamado SetStartFile() que no es más que asignarle el mismo valor como se le asigna a StartFile en JSP.
Todos los metodos en PHP cumplen exactamente la misma función que su contraparte en JSP, se puede tomar la explicación que se dió anteriormente, excepto para el constructor RTFFile() en JSP de la clase RTFFile que en PHP es __construct().
ResetFile() Este método es un poco diferente al explicado en JSP porque además debe asignarsele el valor a la variable $StartFile por eso incluye o se invoca el método SetStartFile().

Ahora explicaremos la clase RTFTable

<!-- RTFTable -->
<?php
  class RTFTable {
    private $NumRows = 1;
    private $NumCols = 1;
    private $Cells = array();
    private $BasicFormatCells = array();
    private $OtherFormatCells = array();
    private $MergedVertCells = array();
    private $MergedHorzCells = array();
    private $ElementCells = array();
    private $WideColCells = array();
    private $TablEspMd = 0;
    private $TablPosic = 0;//Position
    private $TablAligH = 0;//Alineacion = Center(Center, Left, Right)
    private $TablEdgeT = 1;//Border Type = Single
    private $TablThick = 1; //Grosor
    private $TablColor = 1;
    private $CellAligV = 0;//Alineacion Vertical = Top(Top, Center, Botton)
    private $CellEdgeT = 1;//Border Type = Single
    private $CellThick = 1; //Grosor
    private $CellColor;
    private $WideCols = 1200;
    private $BasicFormat = "";
    private $OtherFormat = "";

    private $aBorde = array(
      '\\brdrnone', //No border.
      '\\brdrs', //Single-thickness border.
      '\\brdrth', //Double-thickness border.
      '\\brdrsh', //Shadowed border.
      '\\brdrdb', //Double border.
      '\\brdrdot', // Dotted border.
      '\\brdrdash', //Dashed border.
      '\\brdrinset', //Inset border.
      '\\brdroutset'  //Outset border.
    );//Arreglo de Tipos de Borde

    private $aAlign = array(
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    );//Tipo De Alineación Horizontal de Texto

    private $aAliHT = array(
      '\\trqc', //Centers a table row with respect to its containing column.
      '\\trql', //Left-justifies a table row with respect to its containing column.
      '\\trqr'  //Right-justifies a table row with respect to its containing column.
    );//Tipo De Alineación Horizontal de Tabla

    private $aAliVC = array(
      "\\clvertalt", //Text is top-aligned in cell (the default).
      "\\clvertalc", //Text is centered vertically in cell.
      "\\clvertalb"  //Text is bottom-aligned in cell.
    );//Tipo De Alineación Vertical de Celda

    private $aMrgVC = array(
      "", //Ninguna Mezcla.
      "\\clvmgf", //The first cell in a range of table cells to be vertically merged
      "\\clvmrg"  //Contents of the table cell are vertically merged with those of the preceding cell
    );//Tipo De Unión Vertical de Celda

    public function __construct($NumCols, $NumRows) {
      $this->SetRowsCols($NumCols, $NumRows);
    }

    public function SetRowsCols($NumCols, $NumRows) {
      $this->NumRows=$NumRows;
      $this->NumCols=$NumCols;
      $this->Cells[$this->NumCols][$this->NumRows];
      $this->BasicFormatCells[$this->NumCols][$this->NumRows];
      $this->OtherFormatCells[$this->NumCols][$this->NumRows];
      $this->MergedVertCells[$this->NumCols][$this->NumRows];
      $this->MergedHorzCells[$this->NumCols][$this->NumRows];
      $this->ElementCells[$this->NumCols][$this->NumRows];
      $this->WideColCells[$this->NumCols];
      for($i = 0; $i < $this->NumCols;$i++){
        for($j = 0; $j < $this->NumRows;$j++){
          $this->Cells[$i][$j] = "";
          $this->BasicFormatCells[$i][$j] = "";
          $this->OtherFormatCells[$i][$j] = "";
          $this->MergedVertCells[$i][$j] = 0;
          $this->MergedHorzCells[$i][$j] = 0;
          $this->ElementCells[$i][$j] = 0;
        }
        $this->WideColCells[$i] = 0;
      }
    }

    public function SetFormatTable($EspMd,$Posic,$AligH,$EdgeT,$Thick,$Color) {
      $this->TablEspMd = $EspMd;
      $this->TablPosic = $Posic;
      $this->TablAligH = $AligH;
      $this->TablEdgeT = $EdgeT;
      $this->TablThick = $Thick;
      $this->TablColor = $Color;
    }

    private function GetHeaderTable() {
      $sEspMd = "\\trgaph".$this->TablEspMd;
      $sPosic = "\\trleft".$this->TablPosic;
      global $aAliHT;
      $sHdT = "\n\\par\\ltrrow\\trowd".$sEspMd.$sPosic.$this->aAliHT[$this->TablAligH];
      global $aBorde;
      $sBorde = ($this->TablEdgeT==0)?"":$this->aBorde[$this->TablEdgeT];//Tipo de Borde
      $sHdT = ($this->TablEdgeT==0)?$sHdT." \n":$sHdT."\\trhdr \n";
      $sGrosr = ($this->TablThick==0)?"":"\\brdrw".$this->TablThick;
      $sColor = ($this->TablColor==0)?"":"\\brdrcf".$this->TablColor;
      //BordesDeTabla
      $sTop = "\\trbrdrt".$sBorde.$sGrosr.$sColor." ";//Table row border top
      $sBot = "\\trbrdrb".$sBorde.$sGrosr.$sColor." ";//Table row border bottom
      $sLft = "\\trbrdrl".$sBorde.$sGrosr.$sColor." ";//Table row border left
      $sRgt = "\\trbrdrr".$sBorde.$sGrosr.$sColor." ";//Table row border right
      $sHHz = "\\trbrdrh".$sBorde.$sGrosr.$sColor." ";//Table row border horizontal (inside).
      $sHVt = "\\trbrdrv".$sBorde.$sGrosr.$sColor." ";//Table row border vertical (inside).
      $sTablIH = $sHdT.$sTop.$sLft.$sBot.$sRgt."\n".$sHHz.$sHVt."\n";
      return $sTablIH;
    }

    private function SetNewRowTable() {
      $sEspMd = "\\trgaph".$this->TablEspMd;
      $sPosic = "\\trleft".$this->TablPosic;
      global $aAliHT;
      $sHdT = "\n\\ltrrow\\trowd".$sEspMd.$sPosic.$this->aAliHT[$this->TablAligH];
      $sHdT = $this->GetEndTable().$sHdT." \n";
      return $sHdT;
    }

    private function GetFooterTable() {
      //Fin de Cabecera de Tabla;
      $sTablFH = "\n\\pard\\intbl\\pard\\plain \n";
      return $sTablFH;
    }

    public function SetFormatCellsTable($AligV,$EdgeT,$Thick,$Color) {
      $this->CellAligV = $AligV;
      $this->CellEdgeT = $EdgeT;
      $this->CellThick = $Thick;
      $this->CellColor = $Color;
    }

    public function SetWideColsTable($WideCols) {
      $this->WideCols = $WideCols;
      for($i = 0; $i<$this->NumCols;$i++){
        $this->WideColCells[$i] = $this->WideCols;
      }
    }

    public function SetWideColTable($Col,$WideCols) {
      if($Col < $this->NumCols){
        $this->WideColCells[$Col] = $WideCols;
      }
    }

    public function SetBasicFormatTextTable($Align, $CFrnt, $CFond, $Fuente, $Talla) {
      //Formatos Necesarios
      $sCFrnt = "\\cf".$CFrnt;
      $sCFond = "\\highlight".$CFond;
      $sFuente = "\\f".$Fuente;
      $sTalla = "\\fs".(2*$Talla);
      $this->BasicFormat = $this->aAlign[$Align].$sCFrnt.$sCFond.$sFuente.$sTalla."\n";
    }

    public function SetOtherFormatTextTable($Negrt,$Italc,$Sbryd) {
      //Aplicar o Quitar Formatos Especiales
      $sNegrt = ($Negrt==0)?"\\b0":"\\b";//  Negrita
      $sItalc = ($Italc==0)?"\\i0":"\\i";//  Itálica
      $sSbryd = ($Sbryd==0)?"\\ul0":"\\ul";// Subrayar
      $sFrmtSP = $sNegrt.$sItalc.$sSbryd."\n";
      $this->OtherFormat = $sFrmtSP;
    }

    public function SetBasicFormatTextCell($Col, $Row, $Align, $CFrnt, $CFond, $Fuente, $Talla) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $sCFrnt = "\\cf".$CFrnt;
        $sCFond = "\\highlight".$CFond;
        $sFuente = "\\f".$Fuente;
        $sTalla = "\\fs".(2*$Talla);
        $this->BasicFormatCells[$Col][$Row] = $this->aAlign[$Align].$sCFrnt.$sCFond.$sFuente.$sTalla."\n";
      }
    }

    public function SetOtherFormatTextCell($Col, $Row, $Negrt,$Italc,$Sbryd) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $sNegrt = ($Negrt==0)?"\\b0":"\\b";//  Negrita
        $sItalc = ($Italc==0)?"\\i0":"\\i";//  Itálica
        $sSbryd = ($Sbryd==0)?"\\ul0":"\\ul";// Subrayar
        $this->OtherFormatCells[$Col][$Row] = $sNegrt.$sItalc.$sSbryd."\n";
      }
    }

    public function SetMergeVertCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->MergedVertCells[$Col][$Row] = $Value;
      }
    }

    public function SetMergeHorzCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->MergedHorzCells[$Col][$Row] = $Value;
      }
    }

    public function SetElementCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->Cells[$Col][$Row] = $Value;
        $this->ElementCells[$Col][$Row] = 1;
      }
    }

    public function SetTextCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->Cells[$Col][$Row] = $Value;
        $this->ElementCells[$Col][$Row] = 0;
      }
    }

    private function GetHeaderCell($Col, $Row){
      $sBorde = $this->CellEdgeT==0?"":$this->aBorde[$this->CellEdgeT];
      $sGrosr = $this->CellThick==0?"":"\\brdrw".$this->TablThick;
      $sColor = $this->CellColor==0?"":"\\brdrcf".$this->CellColor;
      $sTop = "\\clbrdrt".$sBorde.$sGrosr.$sColor." ";//Top table cell border
      $sBot = "\\clbrdrb".$sBorde.$sGrosr.$sColor." ";//Bottom table cell border
      $sLft = "\\clbrdrl".$sBorde.$sGrosr.$sColor." ";//Left row border left
      $sRgt = "\\clbrdrr".$sBorde.$sGrosr.$sColor." ";//Right table cell border
      $Width = 0;
      for ($i = 0; $i <= $Col;$i++){
        if ($this->WideColCells[$i]==0){
          $Width += $this->WideCols;
        } else {
          $Width += $this->WideColCells[$i];
        }
      }
      if ($this->MergedHorzCells[$Col][$Row]==1){
        for($i = $Col; $i < $this->NumCols;$i++){
          if($this->MergedHorzCells[$i][$Row]==2){
            if ($this->WideColCells[$i]==0){
              $Width += $this->WideCols;
            } else {
              $Width += $this->WideColCells[$i];
            }
          }
          if($this->MergedHorzCells[$i][$Row]==0) {
            $i = $this->NumRows;
          }
        }
      }
      $sLimit = "\\cellx".$Width." \n";
      $Merged = $this->MergedVertCells[$Col][$Row];
      $sCeldaH = $this->aMrgVC[$Merged].$this->aAliVC[$this->CellAligV].$sTop.$sLft.$sBot.$sRgt.$sLimit;
      if($this->MergedHorzCells[$Col][$Row]==2){
        $sCeldaH = "";
      }
      return $sCeldaH;
    }

    private function GetTextCell($Col, $Row) {
      $TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";

      if (!$this->BasicFormatCells[$Col][$Row]=="")
        $TextFormattedCell .= $this->BasicFormatCells[$Col][$Row];
      else
        $TextFormattedCell .= $this->BasicFormat;

      if (!$this->OtherFormatCells[$Col][$Row]=="")
        $TextFormattedCell .= $this->OtherFormatCells[$Col][$Row];
      else
        $TextFormattedCell .= $this->OtherFormat;
      $TextFormattedCell .= $this->Cells[$Col][$Row];
      $TextFormattedCell .= "\\cell \n";
      if($this->MergedHorzCells[$Col][$Row]==2){
        $TextFormattedCell = "";
      }
      return $TextFormattedCell;
    }

    private function GetElementCell($Col, $Row) {
      $TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";
      $TextFormattedCell .= $this->Cells[$Col][$Row];
      $TextFormattedCell .= "\\cell \n";
      if($this->MergedHorzCells[$Col][$Row]==2){
        $TextFormattedCell = "";
      }
      return $TextFormattedCell;
    }

    private function GetEndTable() {
      $sTablFF = "\n\\row\\pard \n";
      return $sTablFF;
    }

    public function GetTable(){
      $StringTable = "";
      if($this->NumRows>0){
        $StringTable .= $this->GetHeaderTable();
        for($i = 0; $i<$this->NumCols;$i++){
          $StringTable .= $this->GetHeaderCell($i,0);
        }
        $StringTable .= $this->GetFooterTable();

        for($i = 0; $i<$this->NumCols;$i++){
          if ($this->ElementCells[$i][0]==0){
            $StringTable .= $this->GetTextCell($i,0);
          } else {
            $StringTable .= $this->GetElementCell($i,0);
          }
        }

        if($this->NumRows>1){
          for ($j = 1; $j<$this->NumRows;$j++){
            $StringTable .= $this->SetNewRowTable();
            for($i = 0; $i<$this->NumCols;$i++){
              $StringTable .= $this->GetHeaderCell($i,$j);
            }
            $StringTable .= $this->GetFooterTable();

            for($i = 0; $i<$this->NumCols;$i++){
              if ($this->ElementCells[$i][$j]==0){
                $StringTable .= $this->GetTextCell($i,$j);
              } else {
                $StringTable .= $this->GetElementCell($i,$j);
              }
            }
          }
        }
        $StringTable .= $this->GetEndTable();
      }
      return $StringTable;
    }
  }
?>

RTFTable es una clase que nos permite construir una tabla que se insertará como un elemento en un archivo RTF, es decir, un objeto de la clase RTFFile.
Los miembros de la clase son:
$NumRows Número de Filas de la tabla, predefinida a 1.
$NumCols Número de Columnas de la tabla, predefinida a 1.
$Cells Es una matriz o arreglo bidimensional que almacenará el contenido de cada celda.
$BasicFormatCells Es una matriz que almacenará opcionalmente el formato básico de una celda en particular.
$OtherFormatCells Es una matriz similar a la anterior, la diferencia es que almacena opcionalmente el formato opcional del una celda de manera particular.
$MergedVertCells Matriz que permite almacenar las combinaciones o mezclas de celdas de manera vertical establecidas.
$MergedHorzCells Matriz que permite almacenar las combinaciones o mezclas de celdas de manera horizontal establecidas.
$ElementCells Matriz que almacena identicadores de Texto o Elemento almacenados en la matriz $Cells.
$WideColCells Es un arreglo unidimensional que almacena los anchos de las columnas, también es opcional.

$TablEspMd Espacio medio en twips entre las celdas de una fila de una tabla.
$TablPosic Posición en twips del borde izquierdo de la tabla con respecto a la columna de la izquierda. ver \trleftN en documentación RTF.
$TablAligH Alineación horizontal de la tabla.
$TablEdgeT Almacena el tipo de borde de la tabla.
$TablThick ALmacena el grosor de la tabla.
$TablColor Guarda el color de la tabla, debe tenerse en cuenta que este valor será tomado del archivo RTF, que es de tipo RTFFile.

$CellAligV Alineación vertical en la celda.
$CellEdgeT Tipo de borde de la celda.
$CellThick Grosor del borde de la celda.
$CellColor Permite establecer el color del borde de la celda.

$WideCols Almacena el ancho genérico de las columnas.
$BasicFormat Guarda el formato básico de texto para todas las celdas, se excluye aquellas celdas que tienen su valor de formato básico particular en la matriz $BasicFormatCells
$OtherFormat Funciona de manera identica a $BasicFormat, solo que almacena el formato opcional.

$aBorde Es un arreglo que almacena los posibles bordes a utilizar en la tabla o en las celdas.
$aAlign Es un arreglo que almacena las posibles alineaciones horizontales aplicables al texto, bien general o por celdas.
$aAliHT Arreglo que almacena las alineaciones horizontales de tabla posibles.
$aAliVC Arreglo que almacena los valores de alineación vertical de contenido de celdas.
$aMrgVC Arreglo que almacena los valores posibles y necesarios para combinar celdas de manera vertical.

__construct($NumCols, $NumRows) Permite crear una instancia de RTFTable, tomando como argumentos $NumCols para el número de columnas y $NumRows para el número de filas y llamando al método SetRowsCols.
SetRowsCols($NumCols, $NumRows) Este método establece el número de Columnas y Filas para la tabla en cuestión, establece las dimensiones de las matrices de la clase y las inicializa.
SetFormatTable($EspMd,$Posic,$AligH,$EdgeT,$Thick,$Color) Permite asignarles los valores a las variables relacionadas con los parámetros de las tablas.
GetHeaderTable() Genera el encabezado de la tabla según los parámetros establecidos con SetFormatTable.
SetNewRowTable() Permite insertar o crear una nueva fila teniendo en cuenta algunos parámetros establecidos para la tabla con el método SetFormatTable.
GetFooterTable() Retorna una cadena que indica la declaración de una fila de una tabla.
SetFormatCellsTable($AligV,$EdgeT,$Thick,$Color) Establece los valores a las variables que determinan los parámetros de las celdas de la Tabla.
SetWideColsTable($WideCols) Permite asignarle a todas las columnas de la tabla un único valor según el argumento $WideCols para el ancho de cada una de ellas.
SetWideColTable($Col,$WideCols) Permite asignarle a una columna en particular indicada por el argumento $Col el valor de ancho $WideCols.
SetBasicFormatTextTable($Align, $CFrnt, $CFond, $Fuente, $Talla) Establece el formato básico de texto para todas las celdas de la tabla, excepto para aquellas celdas que se les asigne un formato básico particular.
SetOtherFormatTextTable($Negrt,$Italc,$Sbryd) Establece el formato opcional de texto para todas las celdas de la tabla, excepto para aquellas celdas que se les asigne un formato opcional particular.

SetBasicFormatTextCell($Col, $Row, $Align, $CFrnt, $CFond, $Fuente, $Talla) Establece el formato básico de texto para una celda en particular indicada según los argumentos $Col y $Row y se almacena en la matriz BasicFormatCells.
SetOtherFormatTextCell($Col, $Row, $Negrt,$Italc,$Sbryd) Establece el formato opcional de texto para una celda en particular indicada según los argumentos $Col y $Row y se almacena en la matriz OtherFormatCells.
SetMergeVertCell($Col, $Row, $Value) Permite establecer la mezcla de manera vertical de una celda indicada por $Col y $Row y su manera según el argumento $Value.
SetMergeHorzCell($Col, $Row, $Value) Permite establecer la mezcla de manera horizontal de una celda indicada por $Col y $Row y su manera según el argumento $Value.
SetElementCell($Col, $Row, $Value) Dispone un elemento para una celda, éste se almacena en la matriz Cells, indicándose con un “1” que es de tipo elemento en la matriz ElementCells.
SetTextCell($Col, $Row, $Value) Dispone el texto para una celda, su valor se almacenará en la matriz Cells, indicándose con un “0” que es de tipo texto en la matriz ElementCells.
GetHeaderCell($Col, $Row) Retorna la cabecera de una celda, es con este método que se crea la celda, teniendo en cuenta si es mezclada verical u horizontal, borde, color, entre otros parámetros.
GetTextCell($Col, $Row) Retorna el texto de una celda, con el formato básico y formato opcional, teniendo en cuenta de que estos formatos son específicos para la celda indicada por los argumentos $Col y $Row o genéricos; también si existe la mezcla horizontal.
GetElementCell($Col, $Row) Funciona de manera similar a GetTextCell la diferencia es que no se aplican los formatos básicos y opcionales que se le aplican al texto, también tiene en cuenta si debe aplicarse la mezcla horizontal.

GetEndTable() Retorna una cadena indicando el fin de la de tabla.
GetTable() Retorna la tabla completamente, es decir, formato de tabla, formato de celdas y contenido de celas, mezclas verticales y horizontales.

Script JSP (RTF.jsp)
Ahora miremos el código de la clase RTFTable para JSP

<!-- RTFTable -->
<%!
  public class RTFTable {
    private int NumRows = 1;
    private int NumCols = 1;
    private String[][] Cells;
    private String[][] BasicFormatCells;
    private String[][] OtherFormatCells;
    private Integer[][] MergedVertCells;
    private Integer[][] MergedHorzCells;
    private Integer[][] ElementCells;
    private Integer[] WideColCells;
    private int TablEspMd = 0;
    private int TablPosic = 0;//Position
    private int TablAligH = 0;//Alineacion = Center(Center, Left, Right)
    private int TablEdgeT = 1;//Border Type = Single
    private int TablThick = 1; //Grosor
    private int TablColor = 1;
    private int CellAligV = 0;//Alineacion Vertical = Top(Top, Center, Botton)
    private int CellEdgeT = 1;//Border Type = Single
    private int CellThick = 1; //Grosor
    private int CellColor;
    private int WideCols = 1200;
    private String BasicFormat = "";
    private String OtherFormat = "";

    private String[] aBorde = {
      "\\brdrnone", //No border.
      "\\brdrs", //Single-thickness border.
      "\\brdrth", //Double-thickness border.
      "\\brdrsh", //Shadowed border.
      "\\brdrdb", //Double border.
      "\\brdrdot", // Dotted border.
      "\\brdrdash", //Dashed border.
      "\\brdrinset", //Inset border.
      "\\brdroutset"  //Outset border.
    };//Arreglo de Tipos de Borde

    private String[] aAlign = {
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    };//Tipo De Alineación Horizontal de Texto

    private String[] aAliHT = {
      "\\trqc", //Centers a table row with respect to its containing column.
      "\\trql", //Left-justifies a table row with respect to its containing column.
      "\\trqr"  //Right-justifies a table row with respect to its containing column.
    };//Tipo De Alineación Horizontal de Tabla

    private String[] aAliVC = {
      "\\clvertalt", //Text is top-aligned in cell (the default).
      "\\clvertalc", //Text is centered vertically in cell.
      "\\clvertalb"  //Text is bottom-aligned in cell.
    };//Tipo De Alineación Vertical de Celda

    private String[] aMrgVC = {
      "", //Ninguna Mezcla.
      "\\clvmgf", //The first cell in a range of table cells to be vertically merged
      "\\clvmrg"  //Contents of the table cell are vertically merged with those of the preceding cell
    };//Tipo De Unión Vertical de Celda

    RTFTable(int NumCols, int NumRows) {
      SetRowsCols(NumCols,NumRows);
    }

    private void SetRowsCols(int NumCols, int NumRows) {
      this.NumCols = NumCols;
      this.NumRows = NumRows;
      this.Cells = new String[this.NumCols][this.NumRows];
      this.BasicFormatCells = new String[this.NumCols][this.NumRows];
      this.OtherFormatCells = new String[this.NumCols][this.NumRows];
      this.MergedVertCells = new Integer[this.NumCols][this.NumRows];
      this.MergedHorzCells = new Integer[this.NumCols][this.NumRows];
      this.ElementCells = new Integer[this.NumCols][this.NumRows];
      this.WideColCells = new Integer[this.NumCols];
      for(int i = 0; i < this.NumCols;i++){
        for(int j = 0; j < this.NumRows;j++){
          this.Cells[i][j] = "";
          this.BasicFormatCells[i][j] = "";
          this.OtherFormatCells[i][j] = "";
          this.MergedVertCells[i][j] = 0;
          this.MergedHorzCells[i][j] = 0;
          this.ElementCells[i][j] = 0;
        }
        this.WideColCells[i] = 0;
      }
    }

    public void SetFormatTable(int EspMd,int Posic,int AligH,int EdgeT,int Thick,int Color) {
      this.TablEspMd = EspMd;
      this.TablPosic = Posic;
      this.TablAligH = AligH;
      this.TablEdgeT = EdgeT;
      this.TablThick = Thick;
      this.TablColor = Color;
    }

    private String GetHeaderTable() {
      String sEspMd = "\\trgaph"+String.valueOf(this.TablEspMd);
      String sPosic = "\\trleft"+String.valueOf(this.TablPosic);//
      String sHdT = "\n\\par\\ltrrow\\trowd"+sEspMd+sPosic+this.aAliHT[this.TablAligH];
      String sBorde = this.TablEdgeT==0?"":this.aBorde[this.TablEdgeT];//Tipo de Borde
      sHdT = this.TablEdgeT==0?sHdT+" \n":sHdT+"\\trhdr \n";
      String sGrosr = this.TablThick==0?"":"\\brdrw"+String.valueOf(this.TablThick);
      String sColor = this.TablColor==0?"":"\\brdrcf"+String.valueOf(this.TablColor);
      //BordesDeTabla
      String sTop = "\\trbrdrt"+sBorde+sGrosr+sColor+" ";//Table row border top
      String sBot = "\\trbrdrb"+sBorde+sGrosr+sColor+" ";//Table row border bottom
      String sLft = "\\trbrdrl"+sBorde+sGrosr+sColor+" ";//Table row border left
      String sRgt = "\\trbrdrr"+sBorde+sGrosr+sColor+" ";//Table row border right
      String sHHz = "\\trbrdrh"+sBorde+sGrosr+sColor+" ";//Table row border horizontal (inside).
      String sHVt = "\\trbrdrv"+sBorde+sGrosr+sColor+" ";//Table row border vertical (inside).
      String sTablIH = sHdT+sTop+sLft+sBot+sRgt+"\n"+sHHz+sHVt+"\n";
      return sTablIH;
    }

    private String SetNewRowTable() {
      String sEspMd = "\\trgaph"+String.valueOf(this.TablEspMd);
      String sPosic = "\\trleft"+String.valueOf(this.TablPosic);//
      String sHdT = "\n\\ltrrow\\trowd"+sEspMd+sPosic+this.aAliHT[this.TablAligH];
      sHdT = this.GetEndTable() + sHdT+" \n";
      return sHdT;
    }

    private String GetFooterTable() {
      //Fin de Cabecera de Tabla;
      String sTablFH = "\n\\pard\\intbl\\pard\\plain \n";
      return sTablFH;
    }

    public void SetFormatCellsTable(int AligV,int EdgeT,int Thick,int Color) {
      this.CellAligV = AligV;
      this.CellEdgeT = EdgeT;
      this.CellThick = Thick;
      this.CellColor = Color;
    }

    public void SetWideColsTable(int WideCols) {
      this.WideCols = WideCols;
      for(int i = 0; i<this.NumCols;i++){
        this.WideColCells[i] = WideCols;
      }
    }

    public void SetWideColTable(int Col,int WideCols) {
      if(Col < this.NumCols){
        this.WideColCells[Col] = WideCols;
      }
    }

    public void SetBasicFormatTextTable(int Align, int CFrnt, int CFond, int Fuente, int Talla) {
      String sCFrnt = "\\cf"+String.valueOf(CFrnt);
      String sCFond = "\\highlight"+String.valueOf(CFond);
      String sFuente = "\\f"+String.valueOf(Fuente);
      String sTalla = "\\fs"+String.valueOf(2*Talla);
      this.BasicFormat = this.aAlign[Align]+sCFrnt+sCFond+sFuente+sTalla+"\n";
    }

    public void SetOtherFormatTextTable(int Negrt, int Italc, int Sbryd) {
      String sNegrt = Negrt==0?"\\b0":"\\b";//  Negrita
      String sItalc = Italc==0?"\\i0":"\\i";//  Itálica
      String sSbryd = Sbryd==0?"\\ul0":"\\ul";// Subrayar
      this.OtherFormat = sNegrt+sItalc+sSbryd+"\n";
    }

    public void SetBasicFormatTextCell(int Col, int Row, int Align, int CFrnt, int CFond, int Fuente, int Talla) {
      if(Col<this.NumCols && Row<this.NumRows){
        String sCFrnt = "\\cf"+String.valueOf(CFrnt);
        String sCFond = "\\highlight"+String.valueOf(CFond);
        String sFuente = "\\f"+String.valueOf(Fuente);
        String sTalla = "\\fs"+String.valueOf(2*Talla);
        this.BasicFormatCells[Col][Row] = this.aAlign[Align]+sCFrnt+sCFond+sFuente+sTalla+"\n";
      }
    }

    public void SetOtherFormatTextCell(int Col, int Row, int Negrt, int Italc, int Sbryd) {
      if(Col<this.NumCols && Row<this.NumRows){
        String sNegrt = Negrt==0?"\\b0":"\\b";//  Negrita
        String sItalc = Italc==0?"\\i0":"\\i";//  Itálica
        String sSbryd = Sbryd==0?"\\ul0":"\\ul";// Subrayar
        this.OtherFormatCells[Col][Row] = sNegrt+sItalc+sSbryd+"\n";
      }
    }

    public void SetMergeVertCell(int Col, int Row,int Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.MergedVertCells[Col][Row] = Value;
      }
    }

    public void SetMergeHorzCell(int Col, int Row,int Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.MergedHorzCells[Col][Row] = Value;
      }
    }

    public void SetElementCell(int Col, int Row,String Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.Cells[Col][Row] = Value;
        this.ElementCells[Col][Row] = 1;
      }
    }

    public void SetTextCell(int Col, int Row,String Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.Cells[Col][Row] = Value;
        this.ElementCells[Col][Row] = 0;
      }
    }

    private String GetHeaderCell(int Col, int Row){
      String sBorde = this.CellEdgeT==0?"":this.aBorde[this.CellEdgeT];
      String sGrosr = this.CellThick==0?"":"\\brdrw"+String.valueOf(this.CellThick);
      String sColor = this.CellColor==0?"":"\\brdrcf"+String.valueOf(this.CellColor);
      String sTop = "\\clbrdrt"+sBorde+sGrosr+sColor+" ";//Top table cell border
      String sBot = "\\clbrdrb"+sBorde+sGrosr+sColor+" ";//Bottom table cell border
      String sLft = "\\clbrdrl"+sBorde+sGrosr+sColor+" ";//Left row border left
      String sRgt = "\\clbrdrr"+sBorde+sGrosr+sColor+" ";//Right table cell border
      int Width = 0;
      for (int i = 0; i <= Col;i++){
        if (this.WideColCells[i]==0){
          Width += this.WideCols;
        } else {
          Width += this.WideColCells[i];
        }
      }
      if (this.MergedHorzCells[Col][Row]==1){
        for(int i = Col; i < this.NumCols;i++){
          if(this.MergedHorzCells[i][Row]==2){
            if (this.WideColCells[i]==0){
              Width += this.WideCols;
            } else {
              Width += this.WideColCells[i];
            }
          }
          if(this.MergedHorzCells[i][Row]==0) {
            i = this.NumRows;
          }
        }
      }
      String sLimit = "\\cellx"+Width+" \n";
      int Merged = this.MergedVertCells[Col][Row];
      String sCeldaH = this.aMrgVC[Merged]+this.aAliVC[this.CellAligV]+sTop+sLft+sBot+sRgt+sLimit;
      if(this.MergedHorzCells[Col][Row]==2){
        sCeldaH = "";
      }
      return sCeldaH;
    }

    private String GetTextCell(int Col, int Row) {
      String TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";

      if (!this.BasicFormatCells[Col][Row].isEmpty())
        TextFormattedCell += this.BasicFormatCells[Col][Row];
      else
        TextFormattedCell += this.BasicFormat;

      if (!this.OtherFormatCells[Col][Row].isEmpty())
        TextFormattedCell += this.OtherFormatCells[Col][Row];
      else
        TextFormattedCell += this.OtherFormat;
      TextFormattedCell += this.Cells[Col][Row];
      TextFormattedCell += "\\cell \n";
      if(this.MergedHorzCells[Col][Row]==2){
        TextFormattedCell = "";
      }
      return TextFormattedCell;
    }

    private String GetElementCell(int Col, int Row) {
      String TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";
      TextFormattedCell += this.Cells[Col][Row];
      TextFormattedCell += "\\cell";
      if(this.MergedHorzCells[Col][Row]==2){
        TextFormattedCell = "";
      }
      return TextFormattedCell;
    }

    private String GetEndTable() {
      String sTablFF = "\n\\row\\pard \n";
      return sTablFF;
    }

    public String GetTable(){
      String StringTable = "";
      if(this.NumRows>0){
        StringTable += this.GetHeaderTable();
        for(int i = 0; i<this.NumCols;i++){
          StringTable += this.GetHeaderCell(i,0);
        }
        StringTable += this.GetFooterTable();

        for(int i = 0; i<this.NumCols;i++){
          if (this.ElementCells[i][0]==0){
            StringTable += this.GetTextCell(i,0);
          } else {
            StringTable += this.GetElementCell(i,0);
          }
        }
        if(this.NumRows>1){
          for (int j = 1; j<this.NumRows;j++){
            StringTable += this.SetNewRowTable();
            for(int i = 0; i<this.NumCols;i++){
              StringTable += this.GetHeaderCell(i,j);
            }
            StringTable += this.GetFooterTable();
            for(int i = 0; i<this.NumCols;i++){
              if (this.ElementCells[i][j]==0){
                StringTable += this.GetTextCell(i,j);
              } else {
                StringTable += this.GetElementCell(i,j);
              }
            }
          }
        }
        StringTable += this.GetEndTable();
      }
      return StringTable;
    }
  }
%>

Vemos que conceptualmente las variables y métodos de JSP son iguales a los de PHP por eso las explicaciones son iguales a las anteriormente dadas, teniendo en cuenta lo mismo para el caso de los métodos de los constructores respectivos RTFTable(int NumCols, int NumRows) en JSP corresponde a __construct($NumCols, $NumRows) en PHP.

Ahora explicaré la clase RTFImage

<!-- RTFImage -->
<%!
  public class RTFImage {
    private String HexImageString = "";

    public RTFImage(String ImageFileName,int[] Frmt,int[] High,int[] Wide) {
      byte[] BytesFile = new byte[(int)(new File(ImageFileName).length())];
      FileInputStream fis;
      try {
        fis = new FileInputStream(ImageFileName);
        fis.read(BytesFile);
        fis.close();
      }
      catch (FileNotFoundException fnfe)
      {System.out.println(fnfe.toString());}
      catch (EOFException eofe)
      {System.out.println(eofe.toString());}
      catch (IOException ioe)
      {System.out.println(ioe.toString());}
      this.ByteStreamImageString(BytesFile,Frmt,High,Wide);
    }

    public RTFImage(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
      this.ByteStreamImageString(ByteStream,Frmt,High,Wide);
    }

    private void ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
      High[0] = 0;
      Wide[0] = 0;
      Frmt[0] = -1;
      this.HexImageString = "Error";
      if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
        Frmt[0] = 1; //PNG
        High[0] = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
        Wide[0] = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
      }
      if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
          &&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
        Frmt[0] = 2; //JPG
        int PosJPG = 2;
        while (PosJPG<ByteStream.length){
          if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
            High[0] = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
            Wide[0] = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
          }
          PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
        }
      }
      if (Frmt[0] > 0){
        this.HexImageString = "";
        int Salto = 0;
        for (int i=0;i < ByteStream.length; i++){
          Salto++;
          this.HexImageString += String.format("%02x", ByteStream[i]);
          if (Salto==64){
            this.HexImageString += "\n";
            Salto = 0;
          }
        }
      }
    }

    public String GetHexImage(){
      return this.HexImageString;
    }

    public String GetImage(String ImageString,int Type,int High,int Wide,
          int SclY,int SclX, int AltP,int AncP,int CropL,int CropR,int CropT,int CropB) {
      String RTFImagen = "\n"+"{\\pict";
      String sLibI = "\\";
     switch (Type){
      case 1:
        sLibI = sLibI+"pngblip";
        break;
      case 2:
        sLibI = sLibI+"jpegblip";
        break;
      }
      String sHigh = "\\pich"+String.valueOf(High);
      String sWide = "\\picw"+String.valueOf(Wide);
      String sSclX = "\\picscalex"+String.valueOf(SclY);
      String sSclY = "\\picscaley"+String.valueOf(SclX);
      String sAltP = "\\pichgoal"+String.valueOf(AltP);
      String sAncP = "\\picwgoal"+String.valueOf(AncP);
      String sCrpL = "\\piccropl"+String.valueOf(CropL);
      String sCrpR = "\\piccropr"+String.valueOf(CropR);
      String sCrpT = "\\piccropt"+String.valueOf(CropT);
      String sCrpB = "\\piccropb"+String.valueOf(CropB);
      RTFImagen = RTFImagen+sSclX+sSclY+sCrpL+sCrpR+sCrpT+sCrpB+"\n"+sWide+
              sHigh+sAncP+sAltP+sLibI+"\n"+ImageString+"\n}";
      return RTFImagen;
    }

    private Integer Byte2PosInt(byte Byte08, byte Byte00) {
      return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
    }
  }
%>

HexImageString Es una variable interna que almacena como texto hexadecimal la información de la imagen sea de tipo JPG o PNG.

RTFImage(String ImageFileName,int[] Frmt,int[] High,int[] Wide) Es un constructor de la clase RTFImage, sus argumentos son: ImageFileName (Ruta y nombre del archivo imagen), Frmt es un argumento que será retornado por referencia indicando el tipo de formato en caso de ser válido, High retorna la altura de la imagen por referencia, Wide retorna el ancho de la imagen pasando su valor por referencia. El archivo es leído y si es válido como imagen se representará su contenido de manera hexadecimal en HexImageString apoyándose en el método ByteStreamImageString.
RTFImage(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) Es otro constructor, que difiere en sus argumentos en que en vez de recibir la ruta y nombre del archivo imagen, recibe la información binaria de la imagen, ésta es la misma que se extrae leyendola de un archivo, puede obtenerse también desde una fuente como una base de datos, los demás argumentos son y funcionan exactamente iguales.
ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) Es un método importante ya que se encarga de extraer la información binaria pasada por los constructores antes mencionados, analizarla determinando si corresponde al formato JPG o PNG, extrae las dimensiones y las retorna por los argumentos pasando su valor por referencia.
GetHexImage() Retorna la representación en hexadecimal de la imagen como texto, almacenada en la variable HexImageString.
GetImage(String ImageString,int Type,int High,int Wide,int SclY,int SclX, int AltP,int AncP,int CropL,int CropR,int CropT,int CropB) Es un metodo que retorna la representación de la imagen con los parámetros propios del formato RTF, entre ellos dimensiones, escala, dimensiones preferidas y recortes en sus extremos; que son recibidos como argumentos en conjunto con la representación hexadecimal de la imagen ImageString.
Byte2PosInt(byte Byte08, byte Byte00) Es un método de apoyo que convierte 2 bytes y retorna su correspondiente valor a entero.

Script PHP (RTF.php)

<!-- RTFImage -->
<?php
  class RTFImage {
    private $HexImageString = "";

    public function __construct($ImageFileName,&$Formato,&$High,&$Wide) {
      $fis = fopen($ImageFileName, "rb");
      if ($fis!=false){
        $BytesFile = NULL;
        while (!feof($fis)){
          $BytesFile .= fread($fis, 8192);
        }
        fclose($fis);
        $this->ByteStreamImageString($BytesFile,$Formato,$High,$Wide);
      }else {
        $this->ByteStreamImageString($ImageFileName,$Formato,$High,$Wide);
      }
    }

    public function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
      $Alto = 0;
      $Ancho = 0;
      $Formato = -1;
      $this->HexImageString = "Error";
      if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
        $Formato = 1; //PNG
        $Alto = $this->Byte2PosInt($ByteStream[22],$ByteStream[23]);
        $Ancho = $this->Byte2PosInt($ByteStream[18],$ByteStream[19]);
      }
      if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
          && ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
        $Formato = 2; //JPG
        $PosJPG = 2;
        while ($PosJPG<strlen($ByteStream)){
          if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
            $Alto = $this->Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
            $Ancho = $this->Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
          }
          $PosJPG = $PosJPG+2+$this->Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
        }
      }
      if ($Formato > 0){
        $this->HexImageString = "";
        $Salto = 0;
        for ($i=0;$i < strlen($ByteStream); $i++){
          $Salto++;
          $this->HexImageString .= sprintf("%02x", ord($ByteStream[$i]));
          if ($Salto==64){
            $this->HexImageString .= "\n";
            $Salto = 0;
          }
        }
      }
    }

    public function GetHexImage(){
      return $this->HexImageString;
    }

    public function GetImage($ImageString,$Type,$High,$Wide,$SclY,$SclX,
          $AltP,$AncP,$CropL,$CropR,$CropT,$CropB) {
      $RTFImagen = "\n"."{\\pict";
      $sLibI = "\\";
      switch ($Type){
        case 1:
          $sLibI = $sLibI."pngblip";
          break;
        case 2:
          $sLibI = $sLibI."jpegblip";
          break;
      }
      $sHigh = "\\pich".$High;
      $sAnch = "\\picw".$Wide;
      $sSclX = "\\picscalex".$SclY;
      $sSclY = "\\picscaley".$SclX;
      $sAltP = "\\pichgoal".$AltP;
      $sAncP = "\\picwgoal".$AncP;
      $sCrpL = "\\piccropl".$CropL;
      $sCrpR = "\\piccropr".$CropR;
      $sCrpT = "\\piccropt".$CropT;
      $sCrpB = "\\piccropb".$CropB;
      $RTFImagen = $RTFImagen.$sSclX.$sSclY.$sCrpL.$sCrpR.$sCrpT.$sCrpB."\n".$sAnch.
              $sHigh.$sAncP.$sAltP.$sLibI."\n".$ImageString."\n}";
      return $RTFImagen;
    }

    private function Byte2PosInt($Byte08,$Byte00) {
      return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
    }
  }
?>

A diferencia de JSP que los objetos String y arreglo de bytes son diferentes, en PHP no lo son puesto que son tratados como cadenas de texto; es por ello que la ruta de un archivo y el arreglo de bytes son del mismo tipo y de esta manera no hay formas de diferenciarlos sino por el contenido.
En JSP hubo dos constructores, mientras que en PHP solo hay uno, que es __construct($ImageFileName,&$Formato,&$High,&$Wide), este verifica que el argumento $ImageFileName sea una ruta de imagen, de serlo lo lee y carga su contenido en un arreglo de bytes y será tratado por el método ByteStreamImageString; de no ser una ruta de archivo de imagen no se intentará leer sino que se considerará un arreglo de bytes y también será tratado por el método ByteStreamImageString. Los demás métodos son iguales en su propósito.

Anuncios

Acerca de joseluisbz

Hasta ahora, espero actualizarlo después, ahora no.
Esta entrada fue publicada en Classes, Java, Java Server Pages, JSP, JSP, Methods, OOP, PHP, PHP, Programming, RTF, Scripts y etiquetada , , , , , , , , , . Guarda el enlace permanente.

Una respuesta a Script de Clases RTF para JSP y PHP

  1. Ogeretal dijo:

    Muuuuchas gracias,

    Por hacer la pregunta y como nadie te respondia hacer publico tu codigo que funciona a las mil maravillas.

    Garcias

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s