Advertisement
Guest User

Untitled

a guest
Jun 22nd, 2017
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.52 KB | None | 0 0
  1. /*
  2.  * Compressor to compress (and decompress) TGA image files using RLE compression.
  3.  * Only works for uncompressed RGB and RLE encoded RGB.
  4.  * Author: Wesley Stessens
  5.  */
  6.  
  7. #ifndef COMPRESSOR_H
  8. #define COMPRESSOR_H
  9.  
  10. #include <QString>
  11.  
  12. class Compressor
  13. {
  14. public:
  15.     enum DataType {UncompressedRGB = 2, RLECompressedRGB = 10};
  16.     static int compressOrDecompress(const QString &input, const QString &output);
  17.     static bool compress(const QString &input, const QString &output);
  18.     static bool decompress(const QString &input, const QString &output);
  19.     static QString getLastError() {return lastError;}
  20. private:
  21.     static QString lastError;
  22. };
  23.  
  24. #endif
  25.  
  26. /*
  27.  * Compressor to compress (and decompress) TGA image files using RLE compression.
  28.  * Only works for uncompressed RGB and RLE encoded RGB.
  29.  * Author: Wesley Stessens & Toon Cuyvers
  30.  */
  31.  
  32. #include "compressor.h"
  33. #include <QFile>
  34. #include <QtEndian>
  35.  
  36. QString Compressor::lastError = "Unknown";
  37.  
  38. // Returns -1 on error, 0 on successful compression, 1 on successful decompression
  39. int Compressor::compressOrDecompress(const QString &input, const QString &output)
  40. {
  41.     QFile file(input);
  42.     if (!file.open(QIODevice::ReadOnly)) {
  43.         lastError = QString("Could not open input file ") + input +  " for reading.";
  44.         return -1;
  45.     }
  46.  
  47.     QByteArray rawData = file.read(16);
  48.     int dataType = rawData[2];
  49.     if (dataType == UncompressedRGB) {
  50.         file.close();
  51.         return compress(input, output) ? 0 : -1;
  52.     } else if (dataType == RLECompressedRGB) {
  53.         file.close();
  54.         return decompress(input, output) ? 1 : -1;
  55.     } else {
  56.         file.close();
  57.         lastError = "Input file has unsupported data type.";
  58.         return false;
  59.     }
  60. }
  61.  
  62. // Author: Wesley Stessens
  63. bool Compressor::compress(const QString &input, const QString &output)
  64. {
  65.     QFile file(input);
  66.     if (!file.open(QIODevice::ReadOnly)) {
  67.         lastError = QString("Could not open input file ") + input +  " for reading.";
  68.         return false;
  69.     }
  70.  
  71.     QByteArray rawData;
  72.     int identFieldSize = file.peek(1)[0];
  73.     rawData = file.read(identFieldSize + 18);
  74.     int dataType = rawData[2];
  75.     if (dataType != UncompressedRGB) {
  76.         lastError = "Input file has unsupported data type (needs to be Uncompressed RGB).";
  77.         file.close();
  78.         return false;
  79.     }
  80.     rawData[2] = RLECompressedRGB;
  81.     int imagePixelSize = rawData[16];
  82.     int colorMapLength = qFromLittleEndian<qint16>(reinterpret_cast<const uchar*>(rawData.data()) + 5);
  83.     int colorMapEntrySize = rawData[7];
  84.     rawData.append(file.read(colorMapLength * colorMapEntrySize));
  85.  
  86.     QByteArray a = file.read(imagePixelSize >> 3);
  87.     QByteArray b = file.read(imagePixelSize >> 3);
  88.     while (!a.isEmpty()) {
  89.         int num;
  90.  
  91.         if (a != b) { // Raw packets
  92.             QByteArray colors;
  93.             num = 0;
  94.             while (a != b && num < 128) {
  95.                 ++num;
  96.                 colors.append(a);
  97.                 a = b;
  98.                 b = file.read(imagePixelSize >> 3);
  99.             }
  100.             rawData.append(num-1);
  101.             rawData.append(colors);
  102.         } else if (a == b) { // RLE encoded packets
  103.             QByteArray color = a;
  104.             num = 1;
  105.             while (a == b && num < 128) {
  106.                 ++num;
  107.                 a = b;
  108.                 b = file.read(imagePixelSize >> 3);
  109.             }
  110.             rawData.append(0x80 | (num-1));
  111.             rawData.append(color);
  112.             a = b;
  113.             b = file.read(imagePixelSize >> 3);
  114.         }
  115.     }
  116.     file.close();
  117.  
  118.     file.setFileName(output);
  119.     if (!file.open(QIODevice::WriteOnly)) {
  120.         lastError = QString("Could not open output file ") + output +  " for writing.";
  121.         return false;
  122.     } else {
  123.         file.write(rawData);
  124.         file.close();
  125.         return true;
  126.     }
  127. }
  128.  
  129. // Author: Wesley Stessens
  130. bool Compressor::decompress(const QString &input, const QString &output)
  131. {
  132.     QFile file(input);
  133.     if (!file.open(QIODevice::ReadOnly)) {
  134.         lastError = QString("Could not open input file ") + input +  " for reading.";
  135.         return false;
  136.     }
  137.  
  138.     QByteArray rawData;
  139.     int identFieldSize = file.peek(1)[0];
  140.     rawData = file.read(identFieldSize + 18);
  141.     int dataType = rawData[2];
  142.     if (dataType != RLECompressedRGB) {
  143.         lastError = "Input file has unsupported data type (needs to be RLE Compressed RGB).";
  144.         file.close();
  145.         return false;
  146.     }
  147.     rawData[2] = UncompressedRGB;
  148.     int imagePixelSize = rawData[16];
  149.     int colorMapLength = qFromLittleEndian<qint16>(reinterpret_cast<const uchar*>(rawData.data()) + 5);
  150.     int colorMapEntrySize = rawData[7];
  151.     rawData.append(file.read(colorMapLength * colorMapEntrySize));
  152.  
  153.     int num;
  154.     while (!file.atEnd()) {
  155.         QByteArray header = file.read(1);
  156.         quint8 headerInt = static_cast<quint8>(header[0]);
  157.         if ((headerInt & 0x80) == 0x80) { // RLE encoded packets
  158.             num = (headerInt ^ 0x80) + 1;
  159.             QByteArray color = file.read(imagePixelSize >> 3);
  160.             rawData.append(color.repeated(num));
  161.         } else { // Raw packets
  162.             num = headerInt + 1;
  163.             rawData.append(file.read(num * (imagePixelSize >> 3)));
  164.         }
  165.     }
  166.     file.close();
  167.  
  168.     file.setFileName(output);
  169.     if (!file.open(QIODevice::WriteOnly)) {
  170.         lastError = QString("Could not open output file ") + output +  " for writing.";
  171.         return false;
  172.     } else {
  173.         file.write(rawData);
  174.         file.close();
  175.         return true;
  176.     }
  177. }
  178.  
  179.  
  180. /*
  181.  * Main function.
  182.  * Author: Wesley Stessens
  183.  */
  184.  
  185. #include <QTextStream>
  186. #include "compressor.h"
  187.  
  188. int main(int argc, char **argv)
  189. {
  190.     QTextStream qout(stdout);
  191.     bool validArgs = false;
  192.     QString action;
  193.  
  194.     if (argc == 4) {
  195.         action = argv[1];
  196.         action = action.trimmed().toLower();
  197.         validArgs = action == "auto" || action == "compress" || action == "decompress";
  198.     }
  199.  
  200.     if (!validArgs) {
  201.         qout << "Usage: " << argv[0] << " <action> <input file> <output file>\n\taction: auto / compress / decompress\n\tinput file: TGA image to compress or decompress using RLE compression\n\toutput file: resulting TGA image after compression or decompression\n";
  202.     } else {
  203.         if (action == "auto") {
  204.             int result = Compressor::compressOrDecompress(argv[2], argv[3]);
  205.             switch (result) {
  206.             case -1:
  207.                 qout << "could not compress/decompress file.\n";
  208.                 qout << "ERROR: " << Compressor::getLastError() << "\n";
  209.                 break;
  210.             case 0:
  211.                 qout << "File was compressed successfully.\n";
  212.                 break;
  213.             case 1:
  214.                 qout << "File was decompressed successfully.\n";
  215.                 break;
  216.             }
  217.         } else if (action == "compress") {
  218.             bool ok = Compressor::compress(argv[2], argv[3]);
  219.             qout << (ok ? "File was compressed successfully.\n" :
  220.                           "Could not compress file.\n");
  221.             if (!ok)
  222.                 qout << "ERROR: " << Compressor::getLastError() << "\n";
  223.         } else if (action == "decompress") {
  224.             bool ok = Compressor::decompress(argv[2], argv[3]);
  225.             qout << (ok ? "File was decompressed successfully.\n" :
  226.                           "Could not decompress file.\n");
  227.             if (!ok)
  228.                 qout << "ERROR: " << Compressor::getLastError() << "\n";
  229.         }
  230.     }
  231.  
  232.     return 0;
  233. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement