0

I'm trying to create a code to decompress an RLE Byte-Oriented image from a PostScript File I've already tried solutions found around the web and also tried to build my own ; but none of them produced the result i need.

After decompressing the rle image, i should have an RAW image i can open on photoshop (informing width, height and number of channels). However when i try to open the extracted image it doesn't work ; only a black output is show.

My inputs are an Binary ASCII Encoded file (encoded as a hexadecimal string) and a binary file ; both RLE Byte-Oriented compressed (in the hex file case, its just a question of converting it to bytes before trying the rle decompression).

https://drive.google.com/drive/u/0/folders/1Q476HB9SvOG_RDwK6J7PPycbw94zjPYU I've posted samples here.

WorkingSample.raw -> Image Sample i got using another software, and its dimensions as well.

MySample.raw -> Image sample i built using my code, and its dimensions as well.

OriginalFile.ppf -> File containing the original image data and everything else.

ExtractedBinary.bin -> Only a binary portion from OriginalFile.ppf - makes it easier to read and work with the data.

This code was provided by the user nyerguds, he's part of the SO Community. Original Source: http://www.shikadi.net/moddingwiki/RLE_Compression#Types_of_RLE Its the one i tried to use but the results weren't correct. And to be honest i had difficulties understanding his code (he told me to change a few things in order to get it working for my case but i was unable to).

And here's what i tried to do following the PostScript Red Book: Book: https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf The part: "The RunLengthEncode filter encodes data in a simple-byte oriented format based on run length. The compressed data format is a sequence of runs, where each run consists of a length byte followed by 1 to 128 bytes of data. If the length byte is in the range 0 to 127, the following length + 1 bytes (1 to 128 bytes) are to be copied literally upon decompression. If length is in the range of 129 to 255, the following single byte is to be replicated 257 - length times (2 to 128 times) upon decompression." Page 142, RunLengthEncode Filter.

List<byte> final = new List<byte>();
                var split01 = ArraySplit(bytefile, 2);
                foreach (var binPart in split01)
                {                    
                    try
                    {
                        if (binPart.ElementAt(0) <= 127)
                        {
                            int currLen = binPart[0] + 1;
                            for (int i = 0; i <= binPart[0]; i++)
                            {
                                final.Add(binPart[1]);
                                //Console.WriteLine(binPart[1]);
                            }
                        }
                        else if (binPart[0] >= 128)
                        {
                            int currLen = 257 - binPart[0];
                            for (int i = 0; i < currLen; i++)
                            {
                                final.Add(binPart[1]);
                                // Console.WriteLine(binPart[1]);
                            }
                        }
                    }
                    catch(Exception)
                    {
                        break;
                    }


                }

                File.WriteAllBytes(@"C:\test\again.raw", final.ToArray());

 private static IEnumerable<byte[]> ArraySplit(byte[] bArray, int intBufforLengt)
        {
            int bArrayLenght = bArray.Length;
            byte[] bReturn = null;

            int i = 0;
            for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
            {
                bReturn = new byte[intBufforLengt];
                Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
                yield return bReturn;
            }

            int intBufforLeft = bArrayLenght - i * intBufforLengt;
            if (intBufforLeft > 0)
            {
                bReturn = new byte[intBufforLeft];
                Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
                yield return bReturn;
            }
        }

  private static byte[] StringToByteArray(String hex)
        {
            int iValue = 0;
            int NumberChars = hex.Length;
            if (NumberChars % 2 != 0)
            {
                string m = string.Empty;
            }
            byte[] bytes = new byte[NumberChars / 2];
            try
            {

                for (int i = 0; i < NumberChars; i += 2)
                {
                    bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
                    iValue = i;
                }

            }
            catch (Exception e)
            {
                var value = iValue;
                Console.WriteLine(e.Message);
            }


            return bytes;
        }

The desired output would be an TIFF Grayscale. However, i can deal with PNG''s also. I've managed to extract uncompressed data from this kind of file already ; with Emgu(OpenCV Wrapper) i was able to create a viewable image and do my logic on it.

My actual results from RLE Compressed are only invalid RAW files that can't be viewed even on photoshop or IrfanViewer.

Any input is appreciated. Thanks.

EDIT1: stuck on this part

for(int i=0; i < bytefile.Length; i+=2)
            {
                try
                {
                    var lengthByte = bytefile[i];
                    if (lengthByte <= 127)
                    {
                        int currLen = lengthByte + 1;
                        for (int j = 0; j < currLen; j++)
                        {
                            final.Add(bytefile[i]);
                            i++;
                        }

                    }
                    if (bytefile[i] >= 128)
                    {
                        int currLen = 257 - bytefile[i];
                        for (int k = 0; k < currLen; k++)
                        {
                            final.Add(bytefile[i + 1]);
                        }
                    }
                }
                catch(Exception)
                {
                    break;
                }          
            }

This is the logic i'm following. Before it was raising an Exception but i figured it out (it was because i forgot to add the ending byte ; makes no difference in the final result).

paboobhzx
  • 109
  • 10
  • You are not copying the uncompressed bytes there, only `binPart[1]` - should that not be `binPart[i + 1]`, or something similar? – 500 - Internal Server Error Apr 11 '19 at 14:39
  • That was my understanding of the explanation ... maybe i failed in some english comprehension ? Dunno. I've a very good english but i truly got confused there... If the length byte is >= 128, i must replicate the following byte 257 - length times. This part i got very well. Perhaps i'm a bit confused on the first part (first conditional). Lemme try it here. – paboobhzx Apr 11 '19 at 14:42
  • Copied from above: `If the length byte is in the range 0 to 127, the FOLLOWING length + 1 BYTES (1 to 128 bytes) are to be copied literally upon decompression` - note my emphasis. – 500 - Internal Server Error Apr 11 '19 at 14:44
  • Considering the length byte is 5. I must copy the next six(5+1) bytes and then proceed to the next loop iteration ? – paboobhzx Apr 11 '19 at 14:50
  • Almost. Copy the next 5 bytes, [1] through [6], then set your next read index to 7 for the next loop iteration. – 500 - Internal Server Error Apr 11 '19 at 14:52
  • Sorry, my bad, you're right, if 5 is the value, then 6 bytes should be copied. – 500 - Internal Server Error Apr 11 '19 at 14:54
  • If so, first of all i must change the loop to a regular loop (instead of an foreach). Hold a second lemme try to make the changes – paboobhzx Apr 11 '19 at 14:54
  • I edited the question. I added where i got stuck for now.... can't seem how to add the next bytes without having some kind of RangeException. – paboobhzx Apr 11 '19 at 15:16

2 Answers2

1

Try this basic outline:

int i = 0;
while (i < bytefile.length)    
{
    var lengthByte = bytefile[i++];
    if (lengthByte <= 127)
    {
        int currLen = lengthByte + 1;
        for (int j = 0; j < currLen; j++)
            final.Add(bytefile[i++]);
    }
    else
    {
        int currLen = 257 - lengthByte;
        byte byteToCopy = bytefile[i++];
        for (int j = 0; j < currLen; j++)
            final.Add(byteToCopy);
    }
}

This is how I understand what's specified above, anyway.

  • Your second currlen is wrong i think. Its just 257 - lengthByte, nothing more. I changed this line and got the image working. I'll try more amples, but hey - thanks ! After 5 days i made some prrogress. Seems like i was getting close to this... – paboobhzx Apr 11 '19 at 16:32
  • just a question: I don’t see you updating the value of I anywhere. The code stops because I added an exception clause to break when it’s out of range . I gets its increment inside bytefile ? – paboobhzx Apr 11 '19 at 17:35
  • 1
    `i++` increments `i` (and returns its value before it was incremented). – 500 - Internal Server Error Apr 12 '19 at 11:30
0

Although not explicitly stated, I believe you are attempting to extract a RunLength Encoded image from a Postscript file and save that out as a grayscale TIFF.

As a starting point for something like this, have you tried simply saving out an uncompressed image from a Postscript file as a grayscale TIFF to ensure your application logic responsible for building up the TIFF image data indeed works as you expect it to? I'd caution that would a be a good first step before moving onto now supporting decompressing RLE data to then turn into a TIFF.

The reason I think that's important is because your problem may have nothing to do with how you're decompressing the RLE data but rather how you're creating your output TIFF from presumably correctly decoded data.

JosephA
  • 1,187
  • 3
  • 13
  • 27
  • Hello. Yes, i did. And it worked i was able to create an TIFF using Emgu(OpenCV Wrapper). I'll edit the question now and add the current progress. – paboobhzx Apr 11 '19 at 14:26
  • i edited the question and added information. Like i said the logic to create the image from uncompressed data is fine ; no issues about that. My problems are on the RLE compression. I've managed to extract only "portions" of the original image, but a part of it have only black blurs (like missing the data). Analyzing the file on a hex editor i can see lots of zeros also(where i should have some data). – paboobhzx Apr 11 '19 at 14:35