Advertisement
Guest User

Untitled

a guest
Dec 12th, 2013
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 16.41 KB | None | 0 0
  1. module jpeg;
  2.  
  3. private
  4. {
  5.     import std.stdio;
  6.     import std.file;
  7.     import std.algorithm;
  8.     import std.conv;
  9.     import dlib.math.utils;
  10.     import bitio;
  11.     import huffman;
  12. }
  13.  
  14. T readNumeric(T) (File* f, Endian endian = Endian.Little) if (is(T == ubyte))
  15. {
  16.     ubyte[1] bytes;
  17.     f.rawRead(bytes);
  18.     return bytes[0];
  19. }
  20.  
  21. T readNumeric(T) (File* f, Endian endian = Endian.Little) if (is(T == ushort))
  22. {
  23.     union U16
  24.     {
  25.         ubyte[2] asBytes;
  26.         ushort asUshort;
  27.     };
  28.     U16 u16;
  29.     f.rawRead(u16.asBytes);
  30.     version(LittleEndian)
  31.     {
  32.         if (endian == Endian.Big)
  33.             return u16.asUshort.swapEndian16;
  34.         else
  35.             return u16.asUshort;
  36.     }
  37.     else
  38.     {
  39.         if (endian == Endian.Little)
  40.             return u16.asUshort.swapEndian16;
  41.         else
  42.             return u16.asUshort;
  43.     }
  44. }
  45.  
  46. char[Size] readChars(size_t Size) (File* f)
  47. {
  48.     char[Size] chars;
  49.     f.rawRead(chars);
  50.     return chars;
  51. }
  52.  
  53. /*
  54.     TODO:
  55.     1. Add JPEGImage class to store everything
  56.     (width, height, color depth, Huffman tables,
  57.     quantization matrices, image data etc.)
  58.     Pass this image when reading markers.
  59.     Get rid of the redundant JPEGMarker* objects -
  60.     readMarker function should return only
  61.     marker type and update JPEGImage.
  62.     This will greatly reduce amount of code.
  63.     2. Decode SOS compressed data using Huffman
  64.     tables. Learn how image channels (components)
  65.     are separated from each other.
  66. */
  67.  
  68. class JPEGImage
  69. {
  70.     struct JFIF
  71.     {
  72.         ubyte versionMajor;
  73.         ubyte versionMinor;
  74.         ubyte units;
  75.         ushort xdensity;
  76.         ushort ydensity;
  77.         ubyte thumbnailWidth;
  78.         ubyte thumbnailHeight;
  79.         ubyte[] thumbnail;
  80.     }
  81.  
  82.     struct DQT
  83.     {
  84.         ubyte precision;
  85.         ubyte tableId;
  86.         ubyte[] table;
  87.     }
  88.  
  89.     struct SOF0Component
  90.     {
  91.         ubyte hsubsamling;
  92.         ubyte vsubsamling;
  93.         ubyte tableId;
  94.     }
  95.  
  96.     struct SOF0
  97.     {
  98.         ubyte precision;
  99.         ushort height;
  100.         ushort width;
  101.         ubyte componentsNum;
  102.         SOF0Component[] components;
  103.     }
  104.  
  105.     struct DHT
  106.     {
  107.         ubyte clas;
  108.         ubyte tableId;
  109.         ubyte[HuffmanCode] huffmanTable;
  110.         HuffmanTreeNode* huffmanTree;
  111.     }
  112.  
  113.     struct SOSComponent
  114.     {
  115.         ubyte tableIdDC;
  116.         ubyte tableIdAC;
  117.     }
  118.  
  119.     struct SOS
  120.     {
  121.         ubyte componentsNum;
  122.         SOSComponent[] components;
  123.         ubyte spectralSelectionStart;
  124.         ubyte spectralSelectionEnd;
  125.         ubyte successiveApproximationBitHigh;
  126.         ubyte successiveApproximationBitLow;
  127.         ubyte[] encodedData;
  128.     }
  129.  
  130.     JFIF jfif;
  131.     DQT[] dqt;
  132.     SOF0 sof0;
  133.     DHT[] dht;
  134.     SOS sos;
  135.  
  136.     DQT* getQuantizationTable(ubyte id)
  137.     {
  138.         foreach(ref t; dqt)
  139.             if (t.tableId == id)
  140.                 return &t;
  141.         return null;
  142.     }
  143.    
  144.     DHT* getHuffmanTable(ubyte clas, ubyte id)
  145.     {
  146.         foreach(ref t; dht)
  147.             if (t.clas == clas &&
  148.                 t.tableId == id)
  149.                 return &t;
  150.         return null;
  151.     }
  152. }
  153.  
  154. enum JPEGMarkerType
  155. {
  156.     Unknown,
  157.     SOI,
  158.     SOF0,
  159.     SOF1,
  160.     SOF2,
  161.     DHT,
  162.     DQT,
  163.     DRI,
  164.     SOS,
  165.     RSTn,
  166.     APP0,
  167.     COM,
  168.     EOI
  169. }
  170.  
  171. void loadJPEG(string filename)
  172. {
  173.     auto jpg = new JPEGImage();
  174.     auto f = new File(filename, "r");
  175.    
  176.     while (!f.eof)
  177.     {
  178.         JPEGMarkerType mt = f.readMarker(jpg);
  179.     }
  180.  
  181.     f.close();
  182.    
  183.     decodeScanData(jpg);
  184. }
  185.  
  186. JPEGMarkerType readMarker(File* f, JPEGImage jpg)
  187. {
  188.     JPEGMarkerType mt;
  189.     ushort magic = f.readNumeric!ushort(Endian.Big);
  190.    
  191.     switch (magic)
  192.     {
  193.         case 0xFFD8:
  194.             mt = JPEGMarkerType.SOI;
  195.             break;
  196.            
  197.         case 0xFFE0:
  198.             mt = JPEGMarkerType.APP0;
  199.             readJFIF(f, jpg);
  200.             break;
  201.            
  202.         case 0xFFDB:
  203.             mt = JPEGMarkerType.DQT;
  204.             readDQT(f, jpg);
  205.             break;
  206.            
  207.         case 0xFFC0:
  208.             mt = JPEGMarkerType.SOF0;
  209.             readSOF0(f, jpg);
  210.             break;
  211.            
  212.         case 0xFFC4:
  213.             mt = JPEGMarkerType.DHT;
  214.             readDHT(f, jpg);
  215.             break;
  216.            
  217.         case 0xFFDA:
  218.             mt = JPEGMarkerType.SOS;
  219.             readSOS(f, jpg);
  220.             break;
  221.            
  222.         default:
  223.             break;
  224.     }
  225.    
  226.     return mt;
  227. }
  228.  
  229. void readJFIF(File* f, JPEGImage jpg)
  230. {
  231.     ushort jfif_length = f.readNumeric!ushort(Endian.Big);
  232.  
  233.     char[5] jfif_id = f.readChars!5;
  234.     assert(jfif_id == "JFIF\0");
  235.  
  236.     jpg.jfif.versionMajor = f.readNumeric!ubyte;
  237.     jpg.jfif.versionMinor = f.readNumeric!ubyte;
  238.     jpg.jfif.units = f.readNumeric!ubyte;
  239.     jpg.jfif.xdensity = f.readNumeric!ushort(Endian.Big);
  240.     jpg.jfif.ydensity = f.readNumeric!ushort(Endian.Big);
  241.     jpg.jfif.thumbnailWidth = f.readNumeric!ubyte;
  242.     jpg.jfif.thumbnailHeight = f.readNumeric!ubyte;
  243.    
  244.     uint jfif_thumb_length = jpg.jfif.thumbnailWidth * jpg.jfif.thumbnailHeight * 3;
  245.     if (jfif_thumb_length > 0)
  246.     {
  247.         jpg.jfif.thumbnail = new ubyte[jfif_thumb_length];
  248.         f.rawRead(jpg.jfif.thumbnail);
  249.     }
  250.  
  251.     writefln("APP0/JFIF length: %s", jfif_length);
  252.     writefln("APP0/JFIF identifier: %s", jfif_id);
  253.     writefln("APP0/JFIF version major: %s", jpg.jfif.versionMajor);
  254.     writefln("APP0/JFIF version minor: %s", jpg.jfif.versionMinor);
  255.     writefln("APP0/JFIF units: %s", jpg.jfif.units);
  256.     writefln("APP0/JFIF xdensity: %s", jpg.jfif.xdensity);
  257.     writefln("APP0/JFIF ydensity: %s", jpg.jfif.ydensity);
  258.     writefln("APP0/JFIF xthumbnail: %s", jpg.jfif.thumbnailWidth);
  259.     writefln("APP0/JFIF ythumbnail: %s", jpg.jfif.thumbnailHeight);
  260. }
  261.  
  262. void readDQT(File* f, JPEGImage jpg)
  263. {  
  264.     ushort dqt_length = f.readNumeric!ushort(Endian.Big);
  265.  
  266.     JPEGImage.DQT dqt;
  267.     jpg.dqt ~= dqt;
  268.    
  269.     ubyte bite = f.readNumeric!ubyte;
  270.     jpg.dqt[$-1].precision = bite.hiNibble;
  271.     jpg.dqt[$-1].tableId = bite.loNibble;
  272.  
  273.     if (jpg.dqt[$-1].precision == 0)
  274.         jpg.dqt[$-1].table = new ubyte[64];
  275.     else if (jpg.dqt[$-1].precision == 1)
  276.         jpg.dqt[$-1].table = new ubyte[64*2];
  277.     f.rawRead(jpg.dqt[$-1].table);
  278.    
  279.     writefln("DQT length: %s", dqt_length);
  280.     writefln("DQT precision: %s", jpg.dqt[$-1].precision);
  281.     writefln("DQT table id: %s", jpg.dqt[$-1].tableId);
  282.     writefln("DQT table: %s", jpg.dqt[$-1].table);
  283. }
  284.  
  285. void readSOF0(File* f, JPEGImage jpg)
  286. {  
  287.     ushort sof0_length = f.readNumeric!ushort(Endian.Big);
  288.     jpg.sof0.precision = f.readNumeric!ubyte;
  289.     jpg.sof0.height = f.readNumeric!ushort(Endian.Big);
  290.     jpg.sof0.width = f.readNumeric!ushort(Endian.Big);
  291.     jpg.sof0.componentsNum = f.readNumeric!ubyte;
  292.     assert(jpg.sof0.componentsNum == 3);
  293.    
  294.     writefln("SOF0 length: %s", sof0_length);
  295.     writefln("SOF0 precision: %s", jpg.sof0.precision);
  296.     writefln("SOF0 height: %s", jpg.sof0.height);
  297.     writefln("SOF0 width: %s", jpg.sof0.width);
  298.     writefln("SOF0 components: %s", jpg.sof0.componentsNum);
  299.    
  300.     jpg.sof0.components = new JPEGImage.SOF0Component[jpg.sof0.componentsNum];
  301.    
  302.     foreach(ref c; jpg.sof0.components)
  303.     {
  304.         ubyte c_id = f.readNumeric!ubyte;
  305.         ubyte bite = f.readNumeric!ubyte;
  306.         c.hsubsamling = bite.hiNibble;
  307.         c.vsubsamling = bite.loNibble;
  308.         c.tableId = f.readNumeric!ubyte;
  309.         writefln("SOF0 component id: %s", c_id);
  310.         writefln("SOF0 component %s hsubsamling: %s", c_id, c.hsubsamling);
  311.         writefln("SOF0 component %s vsubsamling: %s", c_id, c.vsubsamling);
  312.         writefln("SOF0 component %s table id: %s", c_id, c.tableId);
  313.     }
  314. }
  315.  
  316. void readDHT(File* f, JPEGImage jpg)
  317. {    
  318.     ushort dht_length = f.readNumeric!ushort(Endian.Big);    
  319.     dht_length -= 2;
  320.     writefln("DHT length: %s", dht_length);
  321.    
  322.     while(dht_length > 0)
  323.     {    
  324.     JPEGImage.DHT dht;
  325.     jpg.dht ~= dht;
  326.    
  327.     ubyte bite = f.readNumeric!ubyte;
  328.     dht_length--;
  329.     jpg.dht[$-1].clas = bite.hiNibble;
  330.     jpg.dht[$-1].tableId = bite.loNibble;
  331.  
  332.     ubyte[16] dht_code_lengths;
  333.     f.rawRead(dht_code_lengths);
  334.     dht_length -= 16;
  335.    
  336.     writefln("DHT class: %s (%s)", jpg.dht[$-1].clas, jpg.dht[$-1].clas? "AC":"DC"); // AC/DC :)
  337.     writefln("DHT tableId: %s", jpg.dht[$-1].tableId);
  338.     writefln("DHT Huffman code lengths: %s", dht_code_lengths);
  339.    
  340.     // Read Huffman table  
  341.     int totalCodes = reduce!("a + b")(0, dht_code_lengths);
  342.     int storedCodes = 0;
  343.     ubyte treeLevel = 0;
  344.     ushort bits = 0;
  345.    
  346.     while (storedCodes != totalCodes)
  347.     {
  348.         while (treeLevel < 15 &&
  349.                dht_code_lengths[treeLevel] == 0)
  350.         {
  351.             treeLevel++;
  352.             bits *= 2;
  353.         }
  354.  
  355.         if (treeLevel < 16)
  356.         {
  357.             uint bitsNum = treeLevel + 1;
  358.             HuffmanCode code = HuffmanCode(bits, bitsNum);
  359.             //ubyte symbol = f.readNumeric!ubyte;
  360.             jpg.dht[$-1].huffmanTable[code] = f.readNumeric!ubyte;
  361.             dht_length--;
  362.            
  363.             storedCodes++;
  364.             bits++;
  365.             dht_code_lengths[treeLevel]--;
  366.         }
  367.     }
  368.    
  369.     writeln("DHT Huffman table:\n", jpg.dht[$-1].huffmanTable);
  370.    
  371.     //writeln("DHT Huffman table:");
  372.     //foreach(i, v; jpg.dht[$-1].huffmanTable)
  373.     //    writefln("%s: %x", i, v);
  374.     auto huffmanSymbols = jpg.dht[$-1].huffmanTable.values;
  375.     huffmanSymbols.sort();
  376.     foreach(v; huffmanSymbols)
  377.         writef("%x ", v);
  378.     writef("\n");
  379.  
  380.     //auto tree = jpg.dht[$-1].huffmanTree;
  381.    
  382.     jpg.dht[$-1].huffmanTree = treeFromTable(jpg.dht[$-1].huffmanTable);
  383.     string[ubyte] table;
  384.     jpg.dht[$-1].huffmanTree.getCodes(table);
  385.     writeln(table);
  386.     }
  387. }
  388.  
  389. void readSOS(File* f, JPEGImage jpg)
  390. {  
  391.     ushort sos_length = f.readNumeric!ushort(Endian.Big);
  392.     jpg.sos.componentsNum = f.readNumeric!ubyte;
  393.    
  394.     writefln("SOS length: %s", sos_length);
  395.     writefln("SOS components: %s", jpg.sos.componentsNum);
  396.    
  397.     //assert(jpg.sos.componentsNum == 3);
  398.    
  399.     jpg.sos.components = new JPEGImage.SOSComponent[jpg.sos.componentsNum];
  400.    
  401.     foreach(ref c; jpg.sos.components)
  402.     {
  403.         ubyte c_id = f.readNumeric!ubyte;
  404.         ubyte bite = f.readNumeric!ubyte;
  405.         c.tableIdDC = bite.hiNibble;
  406.         c.tableIdAC = bite.loNibble;
  407.         writefln("SOS component id: %s", c_id);
  408.         writefln("SOS component %s DC table id: %s", c_id, c.tableIdDC);
  409.         writefln("SOS component %s AC table id: %s", c_id, c.tableIdAC);
  410.     }
  411.  
  412.     jpg.sos.spectralSelectionStart = f.readNumeric!ubyte;
  413.     jpg.sos.spectralSelectionEnd = f.readNumeric!ubyte;
  414.     ubyte bite = f.readNumeric!ubyte;
  415.     jpg.sos.successiveApproximationBitHigh = bite.hiNibble;
  416.     jpg.sos.successiveApproximationBitLow = bite.loNibble;
  417.    
  418.     writefln("SOS spectral selection start: %s", jpg.sos.spectralSelectionStart);
  419.     writefln("SOS spectral selection end: %s", jpg.sos.spectralSelectionEnd);
  420.     writefln("SOS successive approximation bit: %s", jpg.sos.successiveApproximationBitHigh);
  421.     writefln("SOS successive approximation bit low: %s", jpg.sos.successiveApproximationBitLow);
  422.    
  423.     uint bytesRead = 0;
  424.     ubyte prev = 0x00;
  425.     bool endMarkerFound = false;
  426.     while (!f.eof && !endMarkerFound)
  427.     {
  428.         bite = f.readNumeric!ubyte;
  429.         bytesRead++;
  430.  
  431.         endMarkerFound = (prev == 0xFF && bite == 0xD9);
  432.            
  433.         if (!endMarkerFound)
  434.         {
  435.             if (bite != 0xFF)
  436.             {
  437.                 ubyte datum = bite;
  438.  
  439.                 if (prev == 0xFF)
  440.                 {                  
  441.                     if (bite == 0x00)
  442.                         datum = 0xFF;
  443.                     else
  444.                     {
  445.                         writefln("Found marker: %X, %X", prev, bite);
  446.                         prev = 0x00;
  447.                         continue;
  448.                     }
  449.                 }
  450.  
  451.                 jpg.sos.encodedData ~= datum;
  452.             }
  453.            
  454.             prev = bite;
  455.         }
  456.     }
  457.    
  458.     writefln("Bytes read: %s", bytesRead);
  459.     writefln("SOS encoded data length: %s", jpg.sos.encodedData.length);
  460. }
  461.  
  462. void decodeScanData(JPEGImage jpg)
  463. {
  464.     assert(jpg.sos.encodedData.length);
  465.    
  466.     //foreach(b; jpg.sos.encodedData)
  467.     //    writef("%X ", b);
  468.     //write("\n");
  469.    
  470.     //foreach(ref c; jpg.sos.components)
  471.     //{
  472.         auto c = &jpg.sos.components[0];
  473.         auto tableDC = jpg.getHuffmanTable(0, c.tableIdDC);
  474.         auto tableAC = jpg.getHuffmanTable(1, c.tableIdAC);
  475.        
  476.         assert(tableDC !is null);
  477.         assert(tableAC !is null);
  478.              
  479.         uint bytePos = 0;
  480.         uint bitPos = 0;
  481.        
  482.         ubyte decodeByte(HuffmanTreeNode* node)
  483.         {
  484.             assert(node !is null);
  485.             while(!node.isLeaf)
  486.             {
  487.                 bool bit = getBit(jpg.sos.encodedData[bytePos], 7-bitPos);
  488.                 bitPos++;
  489.                 if (bitPos == 8)
  490.                 {
  491.                     bitPos = 0;
  492.                     bytePos++;
  493.                 }
  494.  
  495.                 if (bit) write("1");
  496.                 else write("0");
  497.            
  498.                 if (bit)
  499.                     node = node.right;
  500.                 else
  501.                     node = node.left;
  502.             }
  503.             writeln("");
  504.             assert(node !is null);
  505.             return node.ch;
  506.         }
  507.        
  508.         int decodeValue(ubyte len)
  509.         {
  510.             uint v = 0;
  511.  
  512.             uint i = 0;
  513.  
  514.             uint by = 0;
  515.             uint bi = 0;
  516.  
  517.             while (i < len)
  518.             {
  519.                 bool bit = getBit(jpg.sos.encodedData[bytePos], 7-bitPos);
  520.  
  521.                 // FIXME: fix data ordering
  522.                 v = setBit(v, (by * 8 + bi), bit);
  523.  
  524.                 bi++;
  525.                 if (bi == 8)
  526.                 {
  527.                     bi = 0;
  528.                     by++;
  529.                 }
  530.  
  531.                 i++;
  532.  
  533.                 bitPos++;
  534.                 if (bitPos == 8)
  535.                 {
  536.                     bitPos = 0;
  537.                     bytePos++;
  538.                 }
  539.                
  540.                 if (bit) write("1");
  541.                 else write("0");
  542.             }
  543.             writeln("");
  544.  
  545.             bool sign = getBit(v, 0);
  546.  
  547.             write("v:  ");
  548.             foreach(j; 0..uint.sizeof * 8)
  549.             {
  550.                 bool bit = getBit(v, j);
  551.                 if (bit) write("1");
  552.                 else write("0");
  553.             }
  554.             writeln("");
  555.  
  556.             auto offset = 2^^len;
  557.  
  558.             writefln("Sign: %s", sign);
  559.             writefln("Offset: %s", offset);
  560.             writefln("v: %s", v);
  561.  
  562.             if (sign)
  563.                 return v;
  564.             else
  565.                 return (-(offset-1) + v);
  566.         }
  567.        
  568.         int[8*8] block;
  569.  
  570.         // Read DC coefficient
  571.         ubyte dcCoefLen = decodeByte(tableDC.huffmanTree);
  572.         writefln("DC coefficient length in bits: %s", dcCoefLen);
  573.    
  574.         int dc = 0;    
  575.         if (dcCoefLen > 0)
  576.             dc = decodeValue(dcCoefLen);
  577.        
  578.         writefln("DC coefficient: %s", dc);
  579.         block[0] = dc;
  580.        
  581.         // Read AC coefficients
  582.         /*
  583.         uint i = 1;
  584.         bool eob = false;
  585.         while(!eob && i < 64)
  586.         {
  587.             ubyte code = decodeByte(tableAC.huffmanTree);
  588.             writefln("AC code: %X", code);
  589.            
  590.             if (code == 0x00)
  591.                 eob = true;
  592.             else
  593.             {
  594.                 //int ac = decodeValue(acCoefLen);
  595.                 //block[i] = ac;
  596.                 //writefln("AC coefficient: %s", ac);
  597.                 ubyte hi = hiNibble(code);
  598.                 ubyte lo = loNibble(code);
  599.                 writefln("AC code hi nibble: %X", hi);
  600.                 writefln("AC code lo nibble: %X", lo);
  601.                
  602.                 uint zeroes = hi;
  603.                 foreach(j; 0..zeroes)
  604.                 {
  605.                     block[i] = 0;
  606.                     i++;
  607.                 }
  608.                
  609.                 int ac = 0;    
  610.                 if (lo > 0)
  611.                     ac = decodeValue(lo);
  612.                    
  613.                 block[i] = ac;
  614.                 writefln("AC coefficient: %s", ac);
  615.                 i++;
  616.             }
  617.         }
  618.         */    
  619.     //}
  620. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement