One of the first things would be converting from RGB to YUV, or YCrCb, or something in that order. By doing this, you can usually get away with a sub-sample of the U and V channels (or Cr / Cb) up to half the resolution. This is quite common in most types of images (for example, JPEG and MPEG, and they do this, as well as sensors in most digital cameras).
In reality, starting with just 800 bytes of data, most other forms of compression will be a waste of time and effort. You will need to do a lot of work before you do a lot (and keeping it fast enough on the Arduino will also not be trivial).
Edit: itโs good if you are absolutely sure that you cannot change the data at all, everything becomes more complicated very quickly. The real question at this point is what you are facing. Others have already mentioned the possibility of something of the order of predictive delta compression, for example, based on previous pixels, to predict what will happen next, and then encode only the difference between the prediction and the actual value. However, as a rule, this requires the execution of the result using some kind of entropy algorithm, such as Shannon-Fanno or Huffman compression. Those, unfortunately, are usually not the fastest to unpack.
If your data is things like charts or graphs where you can expect that you have large areas of the same pixels, the length encoding (or run-end) can work very well. The advantage of this is that it is really trivial to unpack.
I doubt that LZ-based compression will work so well. LZ-based compression works (in general) by creating a dictionary of byte strings that have been noticed, and when / if the same byte string is displayed again, passing the code assigned to the previous instance instead of retransmitting the entire string. The problem is that you cannot transmit uncompressed bytes - you start by sending a codeword that represents that byte in the dictionary. In your case, you can use (for example) a 10-bit codeword. This means that the first time you send a special character, you need to send it as 10 bits, not just 8. You only begin to receive compression when you can create several longer (double-byte, three-byte, etc.) strings in your dictionary and find the corresponding line later in the tab.
This means that LZ-based compression usually gets quite low compression for the first few hundred bytes or so, and then breaks even for a while, and only after it has been working on some input for a while does it really start well shrink, Working for only 800 bytes at a time, I'm not at all sure that you will ever see much compression - in fact, working in such small blocks, it would not be surprising to see that the data expands fairly regularly (especially if it very random).