Exemplo n.º 1
0
        private void AddTopTextRow24(ref byte[] byPage)
        {
            int offsetRow24 = -1;
            int maxRows     = byPage.Length / 42;

            for (int row = 0; row < maxRows; ++row)
            {
                int packetNr = Hamming.GetPacketNumber(row * 42, ref byPage);
                if (packetNr == 24 || packetNr < 0)
                {
                    offsetRow24 = row * 42;
                    break;
                }
            }
            if (offsetRow24 < 0)
            {
                return;
            }
            byte[] row24 = _topTextDecoder.Row24;
            for (int i = 0; i < 42; ++i)
            {
                byPage[i + offsetRow24] = row24[i];
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Decodes the specified row data.
        /// </summary>
        /// <param name="rowData">The row data.</param>
        /// <param name="startOff">The start off.</param>
        /// <param name="rows">The rows.</param>
        public void Decode(byte[] rowData, int startOff, int rows)
        {
            _line = "";
            try
            {
                int line;
                for (line = 0; line < rows; line++)
                {
                    int  off      = startOff + line * 43;
                    bool copyData = false;
                    int  byte1    = Hamming.Decode[rowData[off + 0]];
                    int  byte2    = Hamming.Decode[rowData[off + 1]];

                    //check for invalid hamming bytes
                    if (byte1 == 0xFF || byte2 == 0xFF)
                    {
                        //hamming error
                        _line += "HE1 ";
                        continue;
                    }
                    byte magazine = (byte)(byte1 & 0x7);

                    //get packet number
                    int packetNumber = Hamming.GetPacketNumber(off, ref rowData);
                    if (packetNumber < 0)
                    {
                        _line += "HE2 ";
                        _vbiLine[magazine] += "HE2 ";
                        continue;
                    }

                    if (packetNumber == 0)
                    {
                        _line += String.Format("{0:X}'", Hamming.GetPageNumber(off, ref rowData));
                        _vbiLine[magazine] += String.Format(" [{0}] {1:X}'", (line), Hamming.GetPageNumber(off, ref rowData));
                    }
                    else if (packetNumber < 10)
                    {
                        _line += String.Format("{0}0{1} ", magazine, packetNumber);
                        _vbiLine[magazine] += String.Format(" [{0}] {1}0{2} ", (line), magazine, packetNumber);
                    }
                    else
                    {
                        _line += String.Format("{0}{1} ", magazine, packetNumber);
                        _vbiLine[magazine] += String.Format(" [{0}] {1}{2} ", (line), magazine, packetNumber);
                    }


                    if (packetNumber == 30 && magazine == 0)
                    {
                        /*
                         * byte type = (byte)(Hamming.Decode[rowData[off + 2]]);
                         * if ((type != 0) && (type != 2))
                         * {
                         * continue;
                         * }
                         */
                        //Log.Write("Packet Number:{0}, type:{1}", packetNumber, type);
                        string channelName = "";
                        for (int i = 0; i < 20; i++)
                        {
                            char char1 = (char)(rowData[off + 22 + i] & 127);
                            //Log.Write("{0}-{1:x}", char1, (byte)(rowData[off + 22 + i] & 127));
                            channelName += char1;
                        }
                        int pos = channelName.LastIndexOf("teletext", StringComparison.InvariantCultureIgnoreCase);
                        if (pos != -1)
                        {
                            channelName = channelName.Substring(0, pos);
                        }
                        //Some times channel name includes program name after :
                        pos = channelName.LastIndexOf(":");
                        if (pos != -1)
                        {
                            channelName = channelName.Substring(0, pos);
                        }
                        channelName            = channelName.TrimEnd(new char[] { '\'', '\"', '´', '`' });
                        channelName            = channelName.Trim();
                        _pageCache.ChannelName = channelName;
                        continue;
                    }

                    //ignore invalid packets and packets 25,26,28,29,30,31
                    if (packetNumber < 0 || packetNumber == 25 || packetNumber == 26 || packetNumber > 27)
                    {
                        continue;
                    }


                    if (packetNumber == 0)
                    {
                        UpdatePage(magazine);
                        _vbiLine[magazine] = String.Format(" [{0}] {1:X}'", (line), Hamming.GetPageNumber(off, ref rowData));
                        _magazineCurrentPageNr[magazine]  = -1;
                        _magazineCurrentSubPage[magazine] = -1;

                        // check if header contains errors
                        bool headerError = false;
                        for (int i = 2; i <= 9; ++i)
                        {
                            if (Hamming.Decode[rowData[off + i]] == 0xFF)
                            {
                                headerError = true;
                                break;
                            }
                        }
                        if (headerError)
                        {
                            //yes then ignore this header.
                            _line += "[HER]";
                            continue;
                        }

                        int pageNr    = Hamming.GetPageNumber(off, ref rowData);
                        int subPageNr = Hamming.GetSubPageNumber(off, ref rowData);
                        _isSerial     = Hamming.IsSerial(off, ref rowData);
                        _prevMagazine = magazine;

                        if (!ToptextDecoder.IsTopTextPage(pageNr, subPageNr))
                        {
                            if (!IsDecimalPage(pageNr))
                            {
                                //ignore hexadecimal pages
                                _magazineCurrentPageNr[magazine]  = -1;
                                _magazineCurrentSubPage[magazine] = -1;
                                continue;
                            }

                            if (!IsDecimalSubPage(subPageNr))
                            {
                                //ignore hexadecimal subpages
                                _magazineCurrentPageNr[magazine]  = -1;
                                _magazineCurrentSubPage[magazine] = -1;
                                continue;
                            }
                        }
                        else
                        {
                            subPageNr = 0;
                        }
                        _magazineCurrentPageNr[magazine]  = pageNr;
                        _magazineCurrentSubPage[magazine] = subPageNr;

                        //strip parity of header

                        copyData = true;
                        _magazineLastRow[magazine] = 0;
                    }
                    else if (packetNumber <= 24)
                    {
                        if (_magazineCurrentPageNr[magazine] == -1)
                        {
                            //no header received for this page
                            continue;
                        }
                        if (_isSerial && _prevMagazine != magazine)
                        {
                            _magazineCurrentPageNr[magazine]  = -1;
                            _magazineCurrentSubPage[magazine] = -1;
                            _line += "[MAG1]";
                            continue;
                        }
                        if (_magazineLastRow[magazine] != 27)
                        {
/*
 *            if (packetNumber <= _magazineLastRow[magazine])
 *            {
 *              if (_magazineLastRow[magazine] >= 23)
 *              {
 *                //UpdatePage(magazine);
 *                //continue;
 *              }
 *              // packet number received is less then previous row
 *              _magazineCurrentPageNr[magazine] = -1;
 *              _magazineCurrentSubPage[magazine] = -1;
 *              //System.Diagnostics.Trace.WriteLine(_line);
 *              //System.Diagnostics.Trace.WriteLine("ERR2");
 *              _line += "[ERR2]";
 *              continue;
 *            }
 *            if (_rowsReceived[magazine, packetNumber])
 *            {
 *              // packet number received is 2 times
 *              _magazineCurrentPageNr[magazine] = -1;
 *              _magazineCurrentSubPage[magazine] = -1;
 *              //System.Diagnostics.Trace.WriteLine(_line);
 *              //System.Diagnostics.Trace.WriteLine("ERR3");
 *              _line += "[ERR3]";
 *              continue;
 *            }*/
                        }

                        copyData = true;
                        _magazineLastRow[magazine] = packetNumber;
                    }
                    else if (packetNumber == 27)
                    {
                        if (_magazineCurrentPageNr[magazine] == -1)
                        {
                            continue;
                        }
                        if (_isSerial && _prevMagazine != magazine)
                        {
                            _magazineCurrentPageNr[magazine]  = -1;
                            _magazineCurrentSubPage[magazine] = -1;
                            _line += "[MAG2]";
                            continue;
                        }

                        /*
                         * if (_magazineLastRow[magazine] >= 1)
                         * {
                         * if (_magazineLastRow[magazine] >= 23)
                         * {
                         *  //UpdatePage(magazine);
                         *  //continue;
                         * }
                         * _magazineCurrentPageNr[magazine] = -1;
                         * _magazineCurrentSubPage[magazine] = -1;
                         * //System.Diagnostics.Trace.WriteLine(_line);
                         * //System.Diagnostics.Trace.WriteLine("ERR5");
                         * _line += "[ERR4]";
                         * continue;
                         * }
                         * if (_rowsReceived[magazine, packetNumber])
                         * {
                         * // packet number received is 2 times
                         * _magazineCurrentPageNr[magazine] = -1;
                         * _magazineCurrentSubPage[magazine] = -1;
                         * //System.Diagnostics.Trace.WriteLine(_line);
                         * //System.Diagnostics.Trace.WriteLine("ERR6");
                         * _line += "[ERR5]";
                         * continue;
                         * }*/
                        copyData = true;
                        _magazineLastRow[magazine] = packetNumber;
                    }

                    if (copyData)
                    {
                        if (_magazineCurrentPageNr[magazine] != -1 && _magazineCurrentSubPage[magazine] != -1)
                        {
                            //_rowsReceived[magazine, packetNumber] = true;
                            int offwp = packetNumber * 42;
                            for (int c = 0; c < 42; ++c)
                            {
                                _workingPage[magazine][offwp + c] = rowData[off + c];
                            }
                        }
                    }
                } // for (line = 0; line < rows; line++)
            }
            catch (Exception)
            {
                System.Diagnostics.Trace.WriteLine("EXCEPTION");
                //        Log.WriteFile(Log.LogType.Error,true,"Exception while decoding teletext");
                //        Log.Write(ex);
            }
            //System.Diagnostics.Trace.WriteLine(_line);
            //Log.Log.WriteFile(_line);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Updates the page.
        /// </summary>
        /// <param name="subPageNumber">The sub page number.</param>
        /// <param name="pageData">The page data.</param>
        /// <returns></returns>
        private void UpdatePage(int subPageNumber, byte[] pageData)
        {
            if (subPageNumber < 0 || subPageNumber > _numberOfSubPages)
            {
                return;
            }
            IntPtr pagePtr = _pageCache[subPageNumber];

            unsafe
            {
                byte *ptr   = (byte *)pagePtr.ToPointer();
                bool  isSet = Hamming.IsEraseBitSet(0, ref pageData);
                for (int row = 0; row < 31; row++)
                {
                    int off = row * 42;
                    if (row != 0)
                    {
                        if (pageData[off] == 32 && isSet)
                        {
                            for (int col = 0; col < 42; col++)
                            {
                                if (ptr[off + col] != 32 && pageData[off + col] == 32)
                                {
                                    ptr[off + col] = 32;
                                }
                            }
                            continue;
                        }
                    }


                    off = row * 42;
                    int rowNr = Hamming.GetPacketNumber(off, ref pageData);
                    if (rowNr < 0)
                    {
                        continue;
                    }
                    for (int col = 0; col < 42; col++)
                    {
                        byte newData = pageData[off + col];
                        if (rowNr != 0)
                        {
                            if (ptr[off + col] != newData)
                            {
                                if (rowNr >= 1 && rowNr <= 24)
                                {
                                    if (col >= 2)
                                    {
                                        if (OddParity.IsCorrect(newData))
                                        {
                                            ptr[off + col] = newData;
                                        }
                                    }
                                    else if (Hamming.Decode[newData] != 0xff)
                                    {
                                        //bytes 0-1 = row/column, hamming 8/4 coded
                                        ptr[off + col] = newData;
                                    }
                                }
                                else
                                {
                                    //rows 25,26,27
                                    ptr[off + col] = newData;
                                }
                            }
                        }
                        else
                        {
                            //row 0
                            ptr[off + col] = newData;
                        }
                    }
                }
            }

            return;
        }
Exemplo n.º 4
0
        private bool PageDiffers(byte[] pageData, int subPageNumber)
        {
            if (subPageNumber < 0 || subPageNumber > _numberOfSubPages)
            {
                return(false);
            }
            IntPtr pagePtr = _pageCache[subPageNumber];

            if (pagePtr == IntPtr.Zero)
            {
                return(false);
            }
            unsafe
            {
                byte *ptr   = (byte *)pagePtr.ToPointer();
                bool  isSet = Hamming.IsEraseBitSet(0, ref pageData);
                for (int row = 0; row < 31; row++)
                {
                    int off = row * 42;
                    if (row != 0)
                    {
                        if (pageData[off] == 32 && isSet)
                        {
                            for (int col = 0; col < 42; col++)
                            {
                                if (ptr[off + col] != 32 && pageData[off + col] == 32)
                                {
                                    return(true);
                                }
                            }
                            continue;
                        }
                    }


                    off = row * 42;
                    int rowNr = Hamming.GetPacketNumber(off, ref pageData);

                    if (rowNr < 0)
                    {
                        continue;
                    }
                    for (int col = 0; col < 42; col++)
                    {
                        byte newData = pageData[off + col];
                        if (rowNr != 0)
                        {
                            if (ptr[off + col] != newData)
                            {
                                if (rowNr >= 1 && rowNr <= 24)
                                {
                                    if (col >= 2)
                                    {
                                        if (OddParity.IsCorrect(newData))
                                        {
                                            // Trace.WriteLine(String.Format("2) {0:X}/{1} r:{2} c:{3} {4} {5:X}!={6:X}", _pageNumber, subPageNumber, row, col, _clearSubPage[subPageNumber], ptr[off + col], pageData[off + col]));
                                            return(true);
                                        }
                                    }
                                    else if (Hamming.Decode[newData] != 0xff)
                                    {
                                        //bytes 0-1 = row/column, hamming 8/4 coded

                                        //Trace.WriteLine(String.Format("3) {0:X}/{1} r:{2} c:{3} {4} {5:X}!={6:X}", _pageNumber, subPageNumber, row, col, _clearSubPage[subPageNumber], ptr[off + col], pageData[off + col]));
                                        return(true);
                                    }
                                }
                                else
                                {
                                    //rows 25,26,27

                                    //Trace.WriteLine(String.Format("4) {0:X}/{1} r:{2} c:{3} {4} {5:X}!={6:X}", _pageNumber, subPageNumber, row, col, _clearSubPage[subPageNumber], ptr[off + col], pageData[off + col]));
                                    return(true);
                                }
                            }
                        }
                    }
                }
            }
            return(false);
        }
        /// <summary>
        /// Renders a teletext page to a bitmap
        /// </summary>
        /// <param name="byPage">Teletext page data</param>
        /// <param name="mPage">Pagenumber</param>
        /// <param name="sPage">Subpagenumber</param>
        /// <returns>Rendered teletext page as bitmap</returns>
        public Bitmap RenderPage(byte[] byPage, int mPage, int sPage)
        {
            // Create Bitmap and set HotPink as the transparent color
            if (_pageBitmap == null)
            {
                _pageBitmap = new Bitmap(_pageRenderWidth, _pageRenderHeight);
                _pageBitmap.MakeTransparent(Color.HotPink);
            }
            if (_renderGraphics == null)
            {
                _renderGraphics = Graphics.FromImage(_pageBitmap);
            }

            int  col;
            bool flag = false;

            byte[] pageChars   = new byte[31 * 40];
            int[]  pageAttribs = new int[31 * 40];
            bool   row24       = false;

            // Decode the page data (Hamming 8/4 or odd parity)
            for (int rowNr = 0; rowNr < MAX_ROWS; rowNr++)
            {
                if (rowNr * 42 >= byPage.Length)
                {
                    break;
                }
                int packetNumber = Hamming.GetPacketNumber(rowNr * 42, ref byPage);
                // Only the packets 0-25 are accepted
                if (packetNumber < 0 || packetNumber > 25)
                {
                    continue;
                }
                bool stripParity = true;
                // Packets 0 and 25 are hamming 8/4 encoded
                if (packetNumber == 25 || packetNumber == 0)
                {
                    stripParity = false;
                }
                // Decode the whole row and remove the first two bytes
                for (col = 2; col < 42; col++)
                {
                    // After pageheader in packet 0 (Bit 10) odd parity is used
                    if (col >= 10 && packetNumber == 0)
                    {
                        stripParity = true;
                    }
                    byte kar = byPage[rowNr * 42 + col];
                    if (stripParity)
                    {
                        kar &= 0x7f;
                    }
                    pageChars[packetNumber * 40 + col - 2] = kar;
                }
                // Exists a packet 24 (Toptext line)
                if (packetNumber == 24)
                {
                    row24 = true;
                }
            }
            int row;
            int txtLanguage;
            // language detection. Extract the bit C12-C14 from the teletext header and set the language code
            int  languageCode;
            byte byte1 = Hamming.Decode[byPage[9]];

            if (byte1 == 0xFF)
            {
                languageCode = 0;
            }
            else
            {
                languageCode = ((byte1 >> 3) & 0x01) | (((byte1 >> 2) & 0x01) << 1) | (((byte1 >> 1) & 0x01) << 2);
            }

            switch (languageCode)
            {
            case 0:
                txtLanguage = 1;
                break;

            case 1:
                txtLanguage = 4;
                break;

            case 2:
                txtLanguage = _isRegionalDK ? 13 : 11;
                break;

            case 3:
                txtLanguage = 5;
                break;

            case 4:
                txtLanguage = 3;
                break;

            case 5:
                txtLanguage = 8;
                break;

            case 6:
                txtLanguage = 0;
                break;

            default:
                txtLanguage = 1;
                break;
            }
            // Detect if it's a boxed page. Boxed Page = subtitle and/or newsflash bit is set
            bool isSubtitlePage = Hamming.IsSubtitleBitSet(0, ref byPage);
            bool isNewsflash    = Hamming.IsNewsflash(0, ref byPage);
            bool isBoxed        = isNewsflash | isSubtitlePage;

            // Determine if the header or toptext line sould be displayed.
            bool displayHeaderAndTopText = !_fullscreenMode || !isBoxed || (_selectedPageText.IndexOf("-") != -1)
                                           ||
                                           (_selectedPageText.IndexOf("-") == -1 &&
                                            !_selectedPageText.Equals(Convert.ToString(mPage, 16)));

            // Iterate over all lines of the teletext page and prepare the rendering
            for (row = 0; row <= 24; row++)
            {
                // If row 24 and no toptext exists, then skip this row
                if (row == 24 && !row24)
                {
                    continue;
                }
                // If not display the header and toptext line, then clear these two rows
                if ((row == 0 || row == 24) && !displayHeaderAndTopText)
                {
                    for (int i = 0; i < 40; ++i)
                    {
                        pageChars[row * 40 + i]   = 32;
                        pageAttribs[row * 40 + i] = ((int)TextColors.Trans1 << 4) | ((int)TextColors.White);
                    }
                }
                else
                {
                    // Otherwise, analyse the information. First set the forground to white and the background to:
                    // - Transparent, if transparent mode or boxed and fullscreen and not display the header and toptext line
                    // - Black otherwise
                    int foreground = (int)TextColors.White;
                    int background;
                    if ((isBoxed || _transparentMode) && _fullscreenMode && !displayHeaderAndTopText)
                    {
                        background = (int)TextColors.Trans1;
                    }
                    else
                    {
                        background = (int)TextColors.Black;
                    }

                    // Reset the attributes
                    int  doubleheight = 0;
                    int  charset      = 0;
                    int  mosaictype   = 0;
                    int  hold         = 0;
                    byte held_mosaic  = 32;
                    // Iterate over all columns in the row and check if a box starts
                    for (int loop1 = 0; loop1 < 40; loop1++)
                    {
                        // Box starts in this row
                        if (pageChars[(row * 40) + loop1] == (int)Attributes.StartBox)
                        {
                            flag = true;
                            break;
                        }
                    }

                    // If boxed page and box doesn't start in this line, than set foreground and background to black or transparent
                    // depending on the mode (fullscreen <-> windowed)
                    if (isBoxed && flag == false)
                    {
                        if (_fullscreenMode)
                        {
                            foreground = (int)TextColors.Trans1;
                            background = (int)TextColors.Trans1;
                        }
                        else
                        {
                            foreground = (int)TextColors.Black;
                            background = (int)TextColors.Black;
                        }
                    }

                    // Iterate over all columns in the row again and now analyse every byte
                    for (col = 0; col < 40; col++)
                    {
                        int index = row * 40 + col;

                        // Set the attributes
                        pageAttribs[index] = (doubleheight << 10 | charset << 8 | background << 4 | foreground);
                        // Boxed and no flag and not row 24 than delete the characters
                        if (isBoxed && !flag && row != 24)
                        {
                            pageChars[index] = 32;
                        }
                        // Analyse the attributes
                        if (pageChars[index] < 32)
                        {
                            switch (pageChars[index])
                            {
                            case (int)Attributes.AlphaBlack:
                                foreground = (int)TextColors.Black;
                                charset    = 0;
                                break;

                            case (int)Attributes.AlphaRed:
                                foreground = (int)TextColors.Red;
                                charset    = 0;
                                break;

                            case (int)Attributes.AlphaGreen:
                                foreground = (int)TextColors.Green;
                                charset    = 0;
                                break;

                            case (int)Attributes.AlphaYellow:
                                foreground = (int)TextColors.Yellow;
                                charset    = 0;
                                break;

                            case (int)Attributes.AlphaBlue:
                                foreground = (int)TextColors.Blue;
                                charset    = 0;
                                break;

                            case (int)Attributes.AlphaMagenta:
                                foreground = (int)TextColors.Magenta;
                                charset    = 0;
                                break;

                            case (int)Attributes.AlphaCyan:
                                foreground = (int)TextColors.Cyan;
                                charset    = 0;
                                break;

                            case (int)Attributes.AlphaWhite:
                                foreground = (int)TextColors.White;
                                charset    = 0;
                                break;

                            case (int)Attributes.Flash:
                                break;

                            case (int)Attributes.Steady:
                                break;

                            case (int)Attributes.EndBox:
                                if (isBoxed)
                                {
                                    if (_fullscreenMode)
                                    {
                                        foreground = (int)TextColors.Trans1;
                                        background = (int)TextColors.Trans1;
                                    }
                                    else
                                    {
                                        foreground = (int)TextColors.Black;
                                        background = (int)TextColors.Black;
                                    }
                                }
                                break;

                            case (int)Attributes.StartBox:
                                if (isBoxed)
                                {
                                    // Clear everything until this position in the line
                                    if (col > 0)
                                    {
                                        for (int loop1 = 0; loop1 < col; loop1++)
                                        {
                                            pageChars[(row * 40) + loop1] = 32;
                                        }
                                    }
                                    // Clear also the page attributes
                                    for (int clear = 0; clear < col; clear++)
                                    {
                                        if (_fullscreenMode)
                                        {
                                            pageAttribs[row * 40 + clear] = doubleheight << 10 | charset << 8 | (int)TextColors.Trans1 << 4 |
                                                                            (int)TextColors.Trans1;
                                        }
                                        else
                                        {
                                            pageAttribs[row * 40 + clear] = doubleheight << 10 | charset << 8 | (int)TextColors.Black << 4 |
                                                                            (int)TextColors.Black;
                                        }
                                    }
                                    // Set the standard background color
                                    if (background == (int)TextColors.Trans1)
                                    {
                                        background = (int)TextColors.Black;
                                    }
                                }
                                break;

                            case (int)Attributes.NormalSize:
                                doubleheight       = 0;
                                pageAttribs[index] = (doubleheight << 10 | charset << 8 | background << 4 | foreground);
                                break;

                            case (int)Attributes.DoubleHeight:
                                if (row < 23)
                                {
                                    doubleheight = 1;
                                }
                                break;

                            case (int)Attributes.MosaicBlack:
                                foreground = (int)TextColors.Black;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.MosaicRed:
                                foreground = (int)TextColors.Red;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.MosaicGreen:
                                foreground = (int)TextColors.Green;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.MosaicYellow:
                                foreground = (int)TextColors.Yellow;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.MosaicBlue:
                                foreground = (int)TextColors.Blue;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.MosaicMagenta:
                                foreground = (int)TextColors.Magenta;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.MosaicCyan:
                                foreground = (int)TextColors.Cyan;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.MosaicWhite:
                                foreground = (int)TextColors.White;
                                charset    = 1 + mosaictype;
                                break;

                            case (int)Attributes.Conceal:
                                if (_hiddenMode == false)
                                {
                                    foreground         = background;
                                    pageAttribs[index] = (doubleheight << 10 | charset << 8 | background << 4 | foreground);
                                }
                                break;

                            case (int)Attributes.ContiguousMosaic:
                                mosaictype = 0;
                                if (charset > 0)
                                {
                                    charset            = 1;
                                    pageAttribs[index] = (doubleheight << 10 | charset << 8 | background << 4 | foreground);
                                }
                                break;

                            case (int)Attributes.SeparatedMosaic:
                                mosaictype = 1;
                                if (charset > 0)
                                {
                                    charset            = 2;
                                    pageAttribs[index] = (doubleheight << 10 | charset << 8 | background << 4 | foreground);
                                }
                                break;

                            case (int)Attributes.Esc:
                                break;

                            case (int)Attributes.BlackBackground:
                                background         = (int)TextColors.Black;
                                pageAttribs[index] = (doubleheight << 10 | charset << 8 | background << 4 | foreground);
                                break;

                            case (int)Attributes.NewBackground:
                                background         = foreground;
                                pageAttribs[index] = (doubleheight << 10 | charset << 8 | background << 4 | foreground);
                                break;

                            case (int)Attributes.HoldMosaic:
                                hold = 1;
                                break;

                            case (int)Attributes.ReleaseMosaic:
                                hold = 2;
                                break;
                            }

                            if (hold > 0 && charset > 0)
                            {
                                pageChars[index] = held_mosaic;
                            }
                            else
                            {
                                pageChars[index] = 32;
                            }

                            if (hold == 2)
                            {
                                hold = 0;
                            }
                        }
                        else
                        {
                            if (charset > 0)
                            {
                                held_mosaic = pageChars[index];
                            }
                            // If doubleheight is selected than delete the following line
                            if (doubleheight > 0)
                            {
                                pageChars[index + 40] = 0xFF;
                            }
                        }
                    }
                    // Check, if there is double height selected in than set the attributes for the next row and skip it
                    for (int count = (row + 1) * 40; count < ((row + 1) * 40) + 40; count++)
                    {
                        if (pageChars[count] == 255)
                        {
                            for (int loop1 = 0; loop1 < 40; loop1++)
                            {
                                pageAttribs[(row + 1) * 40 + loop1] = ((pageAttribs[(row * 40) + loop1] & 0xF0) |
                                                                       ((pageAttribs[(row * 40) + loop1] & 0xF0) >> 4));
                            }

                            row++;
                            break;
                        }
                    }
                }
            } //for (int rowNr = 0; rowNr < 24; rowNr++)

            // Generate header line, if it should be displayed
            if (IsDecimalPage(mPage) && displayHeaderAndTopText)
            {
                int    i;
                string pageNumber;
                int    lineColor;
                // Determine the state, of the header line.
                // Red=Incomplete page number
                // Yellow=Waiting for page
                // Green=Page is displayed
                if (_selectedPageText.IndexOf("-") == -1)
                {
                    if (_selectedPageText.Equals(Convert.ToString(mPage, 16)))
                    {
                        lineColor  = (int)TextColors.Green;
                        pageNumber = Convert.ToString(mPage, 16) + "/" + Convert.ToString(sPage, 16);
                    }
                    else
                    {
                        lineColor  = (int)TextColors.Yellow;
                        pageNumber = _selectedPageText;
                    }
                }
                else
                {
                    lineColor  = (int)TextColors.Red;
                    pageNumber = _selectedPageText;
                }
                string headline = "MediaPortal P." + pageNumber;
                headline += new string((char)32, 32 - headline.Length);
                byte[] mpText = System.Text.Encoding.ASCII.GetBytes(headline);
                Array.Copy(mpText, 0, pageChars, 0, mpText.Length);
                for (i = 0; i < 11; i++)
                {
                    pageAttribs[i] = ((int)TextColors.Black << 4) | lineColor;
                }
                for (i = 12; i < 40; i++)
                {
                    pageAttribs[i] = ((int)TextColors.Black << 4) | ((int)TextColors.White);
                }
            }

            // Now we generate the bitmap
            int   y           = 0;
            int   width       = _pageRenderWidth / 40;
            int   height      = (_pageRenderHeight - 2) / 25;
            float fntSize     = Math.Min(width, height);
            float nPercentage = ((float)_percentageOfMaximumHeight / 100);

            _fontTeletext = new Font("Verdana", fntSize, FontStyle.Regular, GraphicsUnit.Pixel);
            float fntHeight = _fontTeletext.GetHeight(_renderGraphics);

            while (fntHeight > nPercentage * height || fntHeight > nPercentage * width)
            {
                fntSize      -= 0.1f;
                _fontTeletext = new Font("Verdana", fntSize, FontStyle.Regular, GraphicsUnit.Pixel);
                fntHeight     = _fontTeletext.GetHeight(_renderGraphics);
            }
            SolidBrush brush = null;

            try
            {
                // Select the brush, depending on the page and mode
                if ((isBoxed || _transparentMode) && _fullscreenMode)
                {
                    brush = new SolidBrush(Color.HotPink);
                }
                else
                {
                    brush = new SolidBrush(Color.Black);
                }

                // Draw the base rectangle
                _renderGraphics.FillRectangle(brush, 0, 0, _pageRenderWidth, _pageRenderHeight);
                // Fill the rectangle with the teletext page informations
                if (_renderGraphics != null && _pageBitmap != null)
                {
                    for (row = 0; row < 25; row++)
                    {
                        // If not display a toptext line than abort
                        if (!displayHeaderAndTopText && row == 24)
                        {
                            break;
                        }
                        int x = 0;
                        // Draw a single point
                        for (col = 0; col < 40; col++)
                        {
                            Render(_renderGraphics, pageChars[row * 40 + col], pageAttribs[row * 40 + col], ref x, ref y, width,
                                   height, txtLanguage);
                        }

                        y += height + (row == 23 ? 2 : 0);
                    }
                }
            }
            finally
            {
                if (brush != null)
                {
                    brush.Dispose();
                }
                _fontTeletext.Dispose();
                _fontTeletext = null;
            }
            return(_pageBitmap);
            // send the bitmap to the callback
        }