Navigation

Search

Categories

On this page

A simple demonstration about how to comparing 2 Oracle Database Instance(or Schema) objects(such as tables)
Solution of ORA-02070 "database .... does not support ..... In this context"
Data Compression :: Running RLE Algorithm on BMP and PGM Image Files Using C#
Sequence In Oracle RAC System might not generate numbers In a sequence!
Reading-Writing PGM(Portable Graphics Media) Image Files With C#(C Sharp)
Compression With Run Length Encoding(RLE) Algorithm With C#(C Sharp)

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 291
This Year: 0
This Month: 0
This Week: 0
Comments: 0

Sign In
Pick a theme:

# Monday, December 24, 2007
Monday, December 24, 2007 1:25:59 AM (GTB Standard Time, UTC+02:00) ( Oracle )

I want to show, how to compare objects of 2 oracle instances or schemas. Below, i show indexes and referential constraints. You can write for all other objects. There are some tools or scripts to compare 2 schemas. But they compare by object names. For instance if an index is renamed, you can see that as if the index does not exist. I compare the objects by their structures:

 

--QUERY_001
--This query compares SOURCE_DBLINK and current database in terms of INDEXes.
--Comparison is done only by INDEX_NAMEs. Renamed-indexes can not be found!!!
--Returns INDEXes which exist in only SOURCE_DBLINK

SELECT index_name, table_name
  FROM all_indexes@SOURCE_DBLINK md
WHERE table_owner = 'DBUSER'
   AND NOT EXISTS (SELECT 1
          FROM all_indexes db
         WHERE md.table_owner = db.table_owner
           AND md.index_name  = db.index_name);

--QUERY_002
--This query compares SOURCE_DBLINK and current database in terms of INDEXes.
--Comparison is done by index structure. Renamed-indexes can be found.This is am enhancement of QUERY_001
--Returns INDEXes which exist in only SOURCE_DBLINK

SELECT *
  FROM all_ind_columns@SOURCE_DBLINK md
WHERE table_owner = 'DBUSER'
   AND index_owner = 'DBUSER'
   AND NOT EXISTS (SELECT 1
          FROM all_ind_columns db
         WHERE md.table_owner     = db.table_owner
           AND md.index_owner     = db.index_owner
           AND md.table_name      = db.table_name
           AND md.column_name     = db.column_name
           AND md.column_position = db.column_position);
--QUERY_003
--This query compares SOURCE_DBLINK and current database in terms of Referantial Constraints.
--Comparison is done only by CONTRAINT_NAMEs. Renamed-ref-constraints can not be found!!!
--Returns REF-CONTRAINTs which exist in only SOURCE_DBLINK
        
SELECT constraint_name, table_name,
  FROM all_constraints@SOURCE_DBLINK md
WHERE owner = 'DBUSER'
   AND constraint_type = 'R'
   AND NOT EXISTS
(SELECT 1
          FROM all_constraints db
         WHERE md.owner = db.owner
           AND md.constraint_type = db.constraint_type
           AND md.constraint_name = db.constraint_name);
--QUERY_004
--This query compares SOURCE_DBLINK and current database in terms of Referantial Constraints.
--Comparison is done by constraint structure. Renamed-ref-constraints can be found.This is am enhancement of QUERY_003
--Returns REF-CONTRAINTs which exist in only SOURCE_DBLINK
         
SELECT *
  FROM all_cons_columns@SOURCE_DBLINK md
WHERE owner = 'DBUSER'
   AND NOT EXISTS
(SELECT 1
          FROM all_cons_columns db
         WHERE md.owner = db.owner
           AND md.table_name = db.table_name
           AND md.column_name = db.column_name
           AND NVL(md.position, 0) = NVL(db.position, 0));

Comments [1] | | # 
# Sunday, December 23, 2007
Sunday, December 23, 2007 2:43:53 PM (GTB Standard Time, UTC+02:00) ( Oracle )

Today, when i checking migration reliability i got an error, ORA-02070. When i analyzed that i realized that columns which are LONG data-type were caused of this problem:

 

Connected to Oracle Database 10g Enterprise Edition Release 10.1.0.5.0
Connected as DBUSER

SQL>
SQL> SELECT *
  2    FROM all_constraints@UAT md
  3   WHERE owner = 'DBUSER'
  4     AND constraint_type = 'R'
  5     AND NOT EXISTS
  6   (SELECT 1
  7            FROM all_constraints db
  8           WHERE md.owner = db.owner
  9             AND md.constraint_type = db.constraint_type
10             AND md.constraint_name = db.constraint_name);

SELECT *
  FROM all_constraints@UAT md
WHERE owner = 'DBUSER'
   AND constraint_type = 'R'
   AND NOT EXISTS
(SELECT 1
          FROM all_constraints db
         WHERE md.owner = db.owner
           AND md.constraint_type = db.constraint_type
           AND md.constraint_name = db.constraint_name)

ORA-02070: veritabanı UAT bu içerik içinde operator USERENV desteklemez
database UAT does not support  USERENV in this context

SQL> describe all_constraints@UAT;
Object all_constraints@UAT does not exist.

SQL> describe all_constraints;
Name              Type         Nullable Default Comments                                                                   
----------------- ------------ -------- ------- ---------------------------------------------------------------------------
OWNER             VARCHAR2(30)                  Owner of the table                                                         
CONSTRAINT_NAME   VARCHAR2(30)                  Name associated with constraint definition                                 
CONSTRAINT_TYPE   VARCHAR2(1)  Y                Type of constraint definition                                              
TABLE_NAME        VARCHAR2(30)                  Name associated with table with constraint definition                      
---->>>>
SEARCH_CONDITION  LONG         Y                Text of search condition for table check                                   
----<<<<
R_OWNER           VARCHAR2(30) Y                Owner of table used in referential constraint                              
R_CONSTRAINT_NAME VARCHAR2(30) Y                Name of unique constraint definition for referenced table                  
DELETE_RULE       VARCHAR2(9)  Y                The delete rule for a referential constraint                               
STATUS            VARCHAR2(8)  Y                Enforcement status of constraint - ENABLED or DISABLED                     
DEFERRABLE        VARCHAR2(14) Y                Is the constraint deferrable - DEFERRABLE or NOT DEFERRABLE                
DEFERRED          VARCHAR2(9)  Y                Is the constraint deferred by default -  DEFERRED or IMMEDIATE             
VALIDATED         VARCHAR2(13) Y                Was this constraint system validated? -  VALIDATED or NOT VALIDATED        
GENERATED         VARCHAR2(14) Y                Was the constraint name system generated? -  GENERATED NAME or USER NAME   
BAD               VARCHAR2(3)  Y                Creating this constraint should give ORA-02436.  Rewrite it before 2000 AD.
RELY              VARCHAR2(4)  Y                If set, this flag will be used in optimizer                                
LAST_CHANGE       DATE         Y                The date when this column was last enabled or disabled                     
INDEX_OWNER       VARCHAR2(30) Y                The owner of the index used by this constraint                             
INDEX_NAME        VARCHAR2(30) Y                The index used by this constraint                                          
INVALID           VARCHAR2(7)  Y                                                                                           
VIEW_RELATED      VARCHAR2(14) Y                                                                                           

SQL>
SQL> SELECT constraint_name, table_name
  2    FROM all_constraints@UAT md
  3   WHERE owner = 'DBUSER'
  4     AND constraint_type = 'R'
  5     AND NOT EXISTS
  6   (SELECT 1
  7            FROM all_constraints db
  8           WHERE md.owner = db.owner
  9             AND md.constraint_type = db.constraint_type
10             AND md.constraint_name = db.constraint_name);

CONSTRAINT_NAME                TABLE_NAME
------------------------------ ------------------------------
....                           .....
....                           .....
....                           .....

26 rows selected

SQL>

Comments [0] | | # 
# Tuesday, December 18, 2007
Tuesday, December 18, 2007 11:52:20 PM (GTB Standard Time, UTC+02:00) ( Articles | C# | Data Compression )

Aşağıda, Data Compression için hazırlamış olduğum çalışmayı inceleyebilirsiniz. Bu çalışmada, sıkıştırma algoritmalarından RLE(Run Length Encoding) i, BMP ve PGM dosyaları üzerinde farklı şekillerde uygulanması gösterilecektir. Çalışma için, görüntü işleme camiasında sıkça kullanılan Lenna resmi kullanılacaktır.

1.   Konu

 

Aşağıda özellikleri verilen 2 tane 512x512 boyutunda resim dosyasının RLE (Run Length Encoding) yöntemi ile sıkıştırma ve sonra orijinal olarak geri açma istenmektedir.

 

·         BMP (siyah - beyaz),

·         PGM (8 bit grayscale)

 

RLE uygularken aşağıdaki sıra ile kodlama(encoding) ve geri açma(decoding) yapılmalı her resim ve yöntem için analiz yapılmalıdır

 

1.      Her satırı ayrı ayrı.

2.      Her sütunu ayrı ayrı.

3.      Tüm resim satır satır

4.      Tüm resim sütun sütun.

5.      Tüm resim 64x64’lük bloklar halinde zigzag

 

 lenna           lenna


2.   RLE

Run Length Encoding, kayıpsız veri sıkıştırma(Lossless Data Compression). algoritmalarının bir çeşididir. Bu yöntemin temel amacı veri üzerinde, var olan bir veriyi tekrar eski haline dönüştürmeye olanak sağlayan, veri kayıplarının ihmal edilemediği metin gibi verilerinin boyutunu daha küçültmeye yarayan işlemler yapmaktır. Sadece metinlerde değil, siyah-beyaz veya renk sayısı az olan ve tekrarların fazla olduğu görüntülerde de var olan veriyi sıkıştırarak kaynakların daha verimli kullanılmasını sağlar.

 

Bu yöntem, diğer sıkıştırma yöntemleri kadar sıkıştırma oranlarında başarılı olmasa da kolay uygulanabilirliği açısından diğer karmaşık yöntemlerden ayrılır. Run, tekrar eden anlamlı veya anlamsız bir verinin sayısını gösterir. Örneğin “para para para ” dizisinde ardı ardına 3 tane “para ” dizisi geçmektedir. Bu dizi {3}”para “ olarak ifade edilebilir. Baştaki 3, kendisinden sonra dizinin 3 defa tekrar ettiğini belirtmektedir. RLE, en temel haliyle bu şekilde ifade edilebilir.

 

RLE algoritmasının uygulama aşamasında birçok yöntem bulunmaktadır. Her bir yöntem, burada belirtilmeyecektir. Sadece görüntülerin sıkıştırılması için kullanılacak yöntemler açıklanacaktır.

3.   BMP

Windows işletim sistemlerinin kullandığı,  Device-Independent Bitmap(DIB) olarak adlandırılan görüntü dosya formatıdır. Bu sayede herhangi bir ekranda herhangi bir formata bağımlı kalmaksızın görüntülenebilmesidir. Bu tip dosyalarının bir çok çeşidi bulunmaktadır.

 

Uygulamada kullanılan “1 Bit Per Pixel Indexed” tipidir. Yani bir piksel i ifade edebilmek için 1 bit(0 veya 1) e ihtiyaç duyulmaktadır. Bu da bir görüntüdeki toplam piksel çeşidinin 2 ile olarak sınırlandırılmasıdır. Genellikle siyah-beyaz görüntü dosyalarında bu tip ile saklanmaktadır. Bitmap in “Indexed” olması, görüntü verisinin içinde piksel değerleri yerine header da bulunan piksel paletinin indeksini göstermesidir. Kullanılan Bitmap’in header da bulunan paleti aşağıdaki gibidir:

 

 

Red

Green

Blue

Reserved

0

255

255

255

0

1

0

0

0

0

 

Örneğin resim verisi içinde 011... gibi bir sıra bulunuyorsa, (255, 255, 255)(0,0,0)(0,0,0)... piksellerinden oluştuğu anlamına gelmektedir.

 

 

4.   PGM

 

“Portable Gray Map” olarak adlandırılan, oldukça basit, gri tonlu(grayscale) resim dosyasıdır. Piksel değerleri 0-255 arasında değişmektedir. İçerdikleri görüntü bilgisini saklama şekillerine göre Binary ve Text olmak üzere iki farklı tipi bulunmaktadır.

 

 

 

5.    Uygulama

Uygulama, yukarıda belirtilen RLE yöntemini kullanarak BMP ve PGM dosyalarının sıkıştırılmasını yapmaktadır.

5.1.        Kullanılan RLE Yöntemi

RLE’nin çek değişik türleri olduğundan, kullanılan yöntem aşağıda ayrıca belirtilecektir.

5.1.1.   BMP

Kullanılan Bitmap dosyası “1 Bit Per Pixel Indexed” tipindedir. Her görüntü “0” pikseli ile başladığı kabul edilmiştir. Ardından gelen tekrar eden pikseller toplamsal olarak yazılmıştır. O nedenle ilk byte “0” indeksli pikselin, ikinci byte ise “1” indeksli pikselin run değerini tutmaktadır.

 

Aşağıda bu yöntemin uygulandığı çeşitli örnekler bulunmaktadır:

 

Orijinal Bit Hali

Orijinal Byte Hali

Sıkıştırılmış Bit Hali

Sıkıştırılmış Byte Hali

0000000011111111 

[0][255]

8 8

[8][8]

0111111111111111

[127][255]

1 15

[1][15]

1111111111111111

[255][255]

0 16

[0][16]

1001100111111100

[153][252]

0 2 2 2 8 2

[0][2][2][2][8][2]

 

 

Run değeri 1 byte(255) değerini geçtiğinde ise bir sonraki byte geçilir. Örneğin ardı ardına 300 adet 1 gelirse, [255][0][45] olarak kodlanır.

 

Bu yöntemde, run değeri en fazla 255 olarak belirlenmiştir. Hiçbir run değeri bu kısıtın üzerine çıkamaz. O nedenle, bir dezavantaj olarak, ardı ardına gelen ve 255 ten büyük tekrarlar gösterilebilir. Çünkü her 255 ten büyük değerler için, bit değerini kaybetmemek için bir sahte bit([0] veya [1]) eklenir. Bu da sıkıştırma oranını, resmin içeriğine bağlı olarak, değiştirir. Eğer run değeri 2 byte(65535) olarak seçilirse, yine resmin içeriğine bağlı olarak, sıkıştırma oranında ters yönde etkileyebilecektir.

 

Burada, belki bir gelecek çalışması(future work) olarak, resmin içeriğini analiz edip ona göre en uygun run değerinin bulunması sıkıştırma oranının düşürülmesi için daha etkili olacaktır

 

Bu yöntemde başarı, ardı ardına gelen bitlerde çok sık değişimin olup olmamasına göre değişmektedir.

 

Sadece görüntünün “veri” kısmında bir sıkıştırılma yapılmıştır. Header da herhangi bir sıkıştırmaya gidilmemiştir.

rle_encoded_column_lenna

5.1.2.   PGM

Burada kullanılan RLE yöntemi, ardı ardına gelen piksellerden 2 veya daha fazla tekrar eden piksellerin sayısının run değeri olarak kullanılmasıyla elde edilmiştir.

 

Aşağıda bu yöntemin uygulandığı çeşitli örnekler bulunmaktadır:

 

Orijinal Pikseller

Sıkıştırılmış  Pikseller

160 160 159 159 159 159 159

160 160 0 159 159 3

255 90 90 112 112 112

255 90 90 0 112 112 1

 

Sadece görüntünün “veri” kısmında bir sıkıştırılma yapılmıştır. Header da herhangi bir sıkıştırmaya gidilmemiştir.

 

rle_encoded_64by64_based_lenna

6.    Analiz

Uygulama sonucunda elde edilen sıkıştırma oranları(sıkıştırılmış / orijinal) aşağıdaki gibidir

 

 

 

BMP

PGM

Her satır ayrı ayrı

0,241425

0,947268

Her sütun ayrı ayrı

0,395522

0,934769

Tüm resim satır

0,234054

0,947268

Tüm resim sütun

0,394334

0,934761

64X64 zigzag

0,355498

0.948937

Sıkıştırma oranları(sıkıştırılmış / orijinal)

 

 

Boyut(byte)

Dosya Adı

979.970

lenna.pgm

964.610

rle_decoded_column_lenna.pgm

964.610

rle_decoded_row_lenna.pgm

964.610

rle_decoded_two_dim_column_lenna.pgm

964.610

rle_decoded_two_dim_row_lenna.pgm

964.610

rle_decoded_zigzag_64_lenna.pgm

901.680

rle_encoded_column_lenna.pgm

913.743

rle_encoded_row_lenna.pgm

901.688

rle_encoded_two_dim_column_lenna.pgm

913.745

rle_encoded_two_dim_row_lenna.pgm

915.355

rle_encoded_zigzag_64_lenna.pgm

 

 

32.830

lenna.bmp

32.830

rle_decoded_64by64_based_lenna.bmp

32.830

rle_decoded_column_based_lenna.bmp

32.830

rle_decoded_column_lenna.bmp

32.830

rle_decoded_row_based_lenna.bmp

32.830

rle_decoded_row_lenna.bmp

11.671

rle_encoded_64by64_based_lenna.bmp

12.985

rle_encoded_column_based_lenna.bmp

12.946

rle_encoded_column_lenna.bmp

7.926

rle_encoded_row_based_lenna.bmp

7.684

rle_encoded_row_lenna.bmp

Oluşan Dosyalar ve boyutları

 

 

Yukarıda belirtilen sıkıştırma oranları tamamen resim içeriğine bağlı olarak değişmektedir. Kullanılan örnek resimler için başarılı olarak sıkıştırma yapan bir yöntem bir başka resim için aynı başarıyı göstermeyebilir.

6.Programın Çalıştırılması

    program kodunu indirebilirsiniz. Yapmanız gereken bin/debug altındaki exe yi çalıştırmak. Eğer Visual Studio 2005 sahibi iseniz, ilgili projeyi .sln uzantılı dosyasından açıp inceleyebilirsiniz.  Ayrıca kaynak kod içinden PGM ve BMPdosyaları üzerinde okuma ve yazmanın nasıl yapıldığı, RLE algoritma motoru da bulunmaktadır. Kaynak kod, isim vermek veya vermemek suretiyle, herhaliyle kullanılabilir, değiştirilebilinir.

 

Comments [2] | | # 
# Monday, December 17, 2007
Monday, December 17, 2007 10:23:24 PM (GTB Standard Time, UTC+02:00) ( Oracle )

Today, after migration to RAC system, i realized that sequence numbers(usally for generating primary keys) are not generated in a sequence. Applications that read historical data would fail because of that.  Before RAC system ;

ID    INSERT_DATE

1     16.12.2007 16:21:00

2     16.12.2007 16:21:10

3     16.12.2007 16:23:49

 

Note that ID field is generated with an Oracle SEQUENCE.

 

After migration to RAC it became as;

ID    INSERT_DATE

81     16.12.2007 19:43:23

82     16.12.2007 16:39:00

83     16.12.2007 16:46:08

 

As you see, insert date of 82 is before than insert date of 81. There is a mismatch with insertion dates and sequences. Then i read Oracle documentation:

 

ORDER

Specify ORDER to guarantee that sequence numbers are generated in order of request. This clause is useful if you are using the sequence numbers as timestamps. Guaranteeing order is usually not important for sequences used to generate primary keys.

ORDER is necessary only to guarantee ordered generation if you are using Oracle Database with Real Application Clusters. If you are using exclusive mode, sequence numbers are always generated in order.

NOORDER

Specify NOORDER if you do not want to guarantee sequence numbers are generated in order of request. This is the default.

 

So, in order to keep numbers in an order, i altered the sequence and the problem was solved:

SQL>ALTER SEQUENCE SEQ_ID ORDER;

Comments [2] | | # 
# Monday, December 10, 2007
Monday, December 10, 2007 8:59:18 PM (GTB Standard Time, UTC+02:00) ( C# )

I demonstrate a simple example in order to show how to read-write PGM files.

 

Yo can download source from here

 

Output is below:

Type       = P2
ColorSize  = 255
Comment    = Created by ..
Length     = 512
Width      = 512

 

 

Program.cs:

 

using System;

namespace PGM
{
    class Program
    {
        static void Main(string[] args)
        {
            string InputFileName = "lenna.pgm"; //args[0]

            //read PGM 
            PGM Picture = new PGM(InputFileName);
            //Print info
            Picture.PrintPGMInfo();
            //Set image data 
            //Picture.Data
            //Save PGM
            Picture.Save("new_"+InputFileName);

            Console.ReadLine();
            
        }
    }
}

 

PGM.cs:


using System;
using System.IO;

namespace PGM
{
    public class PGM
    {
        private int mWidth;
        private int mLength;
        private int mColor;
        private string mType;
        private byte[] mData;
        private string mComments;

        public string Comment
        {
            get { return this.mComments; }
        }

        public int Width
        {
            get { return this.mWidth; }
        }

        public int Length
        {
            get { return this.mLength; }
        }

        public int ColorSize
        {
            get { return this.mColor; }
        }
        public string Type
        {
            get
            {
                return this.mType;
            }
        }

        public string Header
        {
            get
            {
                return this.Type + Convert.ToChar(10) +
                       '#' + this.Comment + Convert.ToChar(10) +
                        this.mWidth.ToString() + " " + this.mLength.ToString() + Convert.ToChar(10) +
                        this.mColor.ToString() + Convert.ToChar(10);
            }
        }

        public byte[] Data
        {
            get { return this.mData; }
            set { this.mData = value; }
        }


        public PGM(string _filePath)
        {
            ReadPGM(_filePath);
        }

        public void Save(string _filePath)
        {
            WritePGM(_filePath);
        }

        private void ReadPGM(string _filePath)
        {
            FileStream InputStream = File.OpenRead(_filePath);
            BinaryReader PGMReader = new BinaryReader(InputStream);
            char[] Seperators = { ' ', '\n' };

            byte NewLineAsciiCode = 10;
            byte DiezAsciiCode = 35;
            byte SpaceAsciiCode = 32;
            byte[] TempArray = new byte[1000];
            int i = 0;

            string TempS;
            byte TempByte;


            /* Sample PGM :
             * 
             * 
             * P2
             * # Created by ...
             * 512 512
             * 255
             * [data]
             */


            //read PGM Type P2, P5
            TempArray[0] = PGMReader.ReadByte();
            TempArray[1] = PGMReader.ReadByte();
            this.mType = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, 2);

            //read until new line
            while (PGMReader.ReadByte() != NewLineAsciiCode) { ;}

            //read comments if exists. Only one comment line supported!!
            i = 0;
            TempArray[i] = PGMReader.ReadByte();

            if (TempArray[i] == DiezAsciiCode)
            {
                TempByte = PGMReader.ReadByte();
                while (TempByte != NewLineAsciiCode)
                {
                    TempArray[i++] = TempByte;
                    TempByte = PGMReader.ReadByte();
                }
            }
            this.mComments = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);

            //read width
            i = 0;
            TempByte = PGMReader.ReadByte();
            while (TempByte != SpaceAsciiCode)
            {
                TempArray[i++] = TempByte;
                TempByte = PGMReader.ReadByte();
            }

            TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
            this.mWidth = Convert.ToInt32(TempS);

            //read length
            i = 0;
            TempByte = PGMReader.ReadByte();
            while (TempByte != NewLineAsciiCode)
            {
                TempArray[i++] = TempByte;
                TempByte = PGMReader.ReadByte();
            }

            TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
            this.mLength = Convert.ToInt32(TempS);

            //read color
            i = 0;
            TempByte = PGMReader.ReadByte();
            while (TempByte != NewLineAsciiCode)
            {
                TempArray[i++] = TempByte;
                TempByte = PGMReader.ReadByte();
            }

            TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
            this.mColor = Convert.ToInt32(TempS);

            //read image data
            byte[] PGMDataBuffer = new byte[this.mWidth * this.mLength];
            int k = 0;
            if (this.mType == "P5")
            {
                //If file is binary, read every byte
                byte[] ReadedByte = PGMReader.ReadBytes(PGMDataBuffer.Length);
                Array.Copy(ReadedByte, PGMDataBuffer, ReadedByte.Length);
            }
            else if (this.mType == "P2")
            {
                //If file is text based every pixel is distinguished by "space" and it has up to 3 chars(255)
                try
                {
                    TempByte = PGMReader.ReadByte();
                    while (TempByte != -1)
                    {
                        i = 0;
                        while (TempByte != NewLineAsciiCode && TempByte != SpaceAsciiCode)
                        {
                            TempArray[i++] = TempByte;
                            TempByte = PGMReader.ReadByte();
                        }

                        TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
                        i = 0;
                        //TempS contains, string representation of every pixel
                        PGMDataBuffer[k++] = Convert.ToByte(TempS);

                        TempByte = PGMReader.ReadByte();
                        if (TempByte == NewLineAsciiCode || TempByte == SpaceAsciiCode)
                        {
                            TempByte = PGMReader.ReadByte();
                        }
                    }
                }
                catch (Exception e)
                {
                    //Console.WriteLine(e.InnerException);
                    ;
                }
            }
            this.mData = PGMDataBuffer;

            PGMReader.Close();
            InputStream.Close();
        }
        private void WritePGM(string _filePath)
        {
            FileStream OutputStream = File.Create(_filePath);
            BinaryWriter PGMWriter = new BinaryWriter(OutputStream);

            string PGMInfo = this.Header;
            byte[] PGMInfoBuffer = System.Text.ASCIIEncoding.Default.GetBytes(PGMInfo);
            PGMWriter.Write(PGMInfoBuffer);
            if (this.mType == "P5")
            {
                //File is binary, write complete data
                PGMWriter.Write(this.mData);
            }
            else if (this.mType == "P2")
            {
                byte NewLineAsciiCode = 10;
                byte SpaceAsciiCode = 32;
                int Temp;

                for (