JPGEncoder.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. 
  2. #if !UNITY_FLASH && !UNITY_METRO && !UNITY_WP8
  3. using UnityEngine;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. public class ByteArray
  8. {
  9. private MemoryStream stream;
  10. private BinaryWriter writer;
  11. public ByteArray()
  12. {
  13. stream = new MemoryStream();
  14. writer = new BinaryWriter(stream);
  15. }
  16. /**
  17. * Function from AS3--add a byte to our stream
  18. */
  19. public void writeByte(byte value)
  20. {
  21. writer.Write(value);
  22. }
  23. /**
  24. * Spit back all bytes--to either pass via WWW or save to disk
  25. */
  26. public byte[] GetAllBytes()
  27. {
  28. byte[] buffer = new byte[stream.Length];
  29. stream.Position = 0;
  30. stream.Read(buffer, 0, buffer.Length);
  31. return buffer;
  32. }
  33. }
  34. /**
  35. * This should really be a struct--if you care, declare it in C#
  36. */
  37. class BitString
  38. {
  39. public int len = 0;
  40. public int val = 0;
  41. }
  42. /**
  43. * Another flash class--emulating the stuff the encoder uses
  44. */
  45. public class BitmapData
  46. {
  47. public int height;
  48. public int width;
  49. private Color[] pixels;
  50. /**
  51. * Pull all of our pixels off the texture (Unity stuff isn't thread safe, and this is faster)
  52. */
  53. public BitmapData(Color[] _pixels, int _width, int _height)
  54. {
  55. height = _height;
  56. width = _width;
  57. pixels = _pixels;
  58. }
  59. public BitmapData(Texture2D texture)
  60. {
  61. height = texture.height;
  62. width = texture.width;
  63. pixels = texture.GetPixels();
  64. }
  65. /**
  66. * Mimic the flash function
  67. */
  68. public Color getPixelColor(int x, int y)
  69. {
  70. if ( x >= width )
  71. x = width - 1;
  72. if ( y >= height )
  73. y = height - 1;
  74. if ( x < 0 )
  75. x = 0;
  76. if ( y < 0 )
  77. y = 0;
  78. return pixels[y * width + x];
  79. }
  80. }
  81. /**
  82. * Class that converts BitmapData into a valid JPEG
  83. */
  84. public class JPGEncoder
  85. {
  86. // Static table initialization
  87. public int[] ZigZag = new int[64] {
  88. 0, 1, 5, 6,14,15,27,28,
  89. 2, 4, 7,13,16,26,29,42,
  90. 3, 8,12,17,25,30,41,43,
  91. 9,11,18,24,31,40,44,53,
  92. 10,19,23,32,39,45,52,54,
  93. 20,22,33,38,46,51,55,60,
  94. 21,34,37,47,50,56,59,61,
  95. 35,36,48,49,57,58,62,63
  96. };
  97. private int[] YTable = new int[64];
  98. private int[] UVTable = new int[64];
  99. private float[] fdtbl_Y = new float[64];
  100. private float[] fdtbl_UV = new float[64];
  101. private void initQuantTables(int sf)
  102. {
  103. int i;
  104. float t;
  105. int[] YQT = new int[64] {
  106. 16, 11, 10, 16, 24, 40, 51, 61,
  107. 12, 12, 14, 19, 26, 58, 60, 55,
  108. 14, 13, 16, 24, 40, 57, 69, 56,
  109. 14, 17, 22, 29, 51, 87, 80, 62,
  110. 18, 22, 37, 56, 68,109,103, 77,
  111. 24, 35, 55, 64, 81,104,113, 92,
  112. 49, 64, 78, 87,103,121,120,101,
  113. 72, 92, 95, 98,112,100,103, 99
  114. };
  115. for ( i = 0; i < 64; i++ )
  116. {
  117. t = Mathf.Floor((YQT[i] * sf + 50.0f) / 100.0f);
  118. if ( t < 1.0f )
  119. {
  120. t = 1.0f;
  121. }
  122. else if ( t > 255.0f )
  123. {
  124. t = 255.0f;
  125. }
  126. YTable[ZigZag[i]] = (int)t;
  127. }
  128. int[] UVQT = new int[64] {
  129. 17, 18, 24, 47, 99, 99, 99, 99,
  130. 18, 21, 26, 66, 99, 99, 99, 99,
  131. 24, 26, 56, 99, 99, 99, 99, 99,
  132. 47, 66, 99, 99, 99, 99, 99, 99,
  133. 99, 99, 99, 99, 99, 99, 99, 99,
  134. 99, 99, 99, 99, 99, 99, 99, 99,
  135. 99, 99, 99, 99, 99, 99, 99, 99,
  136. 99, 99, 99, 99, 99, 99, 99, 99
  137. };
  138. for ( i = 0; i < 64; i++ )
  139. {
  140. t = Mathf.Floor((UVQT[i] * sf + 50.0f) / 100.0f);
  141. if ( t < 1.0f )
  142. {
  143. t = 1.0f;
  144. }
  145. else if ( t > 255.0f )
  146. {
  147. t = 255.0f;
  148. }
  149. UVTable[ZigZag[i]] = (int)t;
  150. }
  151. float[] aasf = new float[8] {
  152. 1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
  153. 1.0f, 0.785694958f, 0.541196100f, 0.275899379f
  154. };
  155. i = 0;
  156. for ( int row = 0; row < 8; row++ )
  157. {
  158. for ( int col = 0; col < 8; col++ )
  159. {
  160. fdtbl_Y[i] = (1.0f / (YTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0f));
  161. fdtbl_UV[i] = (1.0f / (UVTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0f));
  162. i++;
  163. }
  164. }
  165. }
  166. private BitString[] YDC_HT;
  167. private BitString[] UVDC_HT;
  168. private BitString[] YAC_HT;
  169. private BitString[] UVAC_HT;
  170. private BitString[] computeHuffmanTbl(int[] nrcodes, int[] std_table)
  171. {
  172. int codevalue = 0;
  173. int pos_in_table = 0;
  174. BitString[] HT = new BitString[16 * 16];
  175. for ( int k = 1; k <= 16; k++ )
  176. {
  177. for ( int j = 1; j <= nrcodes[k]; j++ )
  178. {
  179. HT[std_table[pos_in_table]] = new BitString();
  180. HT[std_table[pos_in_table]].val = codevalue;
  181. HT[std_table[pos_in_table]].len = k;
  182. pos_in_table++;
  183. codevalue++;
  184. }
  185. codevalue *= 2;
  186. }
  187. return HT;
  188. }
  189. private int[] std_dc_luminance_nrcodes = new int[17] { 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
  190. private int[] std_dc_luminance_values = new int[12] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
  191. private int[] std_ac_luminance_nrcodes = new int[17] { 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
  192. private int[] std_ac_luminance_values = new int[162] {
  193. 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,
  194. 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
  195. 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
  196. 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
  197. 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,
  198. 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
  199. 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,
  200. 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
  201. 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
  202. 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
  203. 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
  204. 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
  205. 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
  206. 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
  207. 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
  208. 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
  209. 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,
  210. 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
  211. 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
  212. 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
  213. 0xf9,0xfa
  214. };
  215. private int[] std_dc_chrominance_nrcodes = new int[17] { 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
  216. private int[] std_dc_chrominance_values = new int[12] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
  217. private int[] std_ac_chrominance_nrcodes = new int[17] { 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
  218. private int[] std_ac_chrominance_values = new int[162] {
  219. 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,
  220. 0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
  221. 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
  222. 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
  223. 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,
  224. 0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
  225. 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,
  226. 0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
  227. 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
  228. 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,
  229. 0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,
  230. 0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
  231. 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,
  232. 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,
  233. 0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
  234. 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
  235. 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,
  236. 0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
  237. 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,
  238. 0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
  239. 0xf9,0xfa
  240. };
  241. private void initHuffmanTbl()
  242. {
  243. YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes, std_dc_luminance_values);
  244. UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes, std_dc_chrominance_values);
  245. YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes, std_ac_luminance_values);
  246. UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes, std_ac_chrominance_values);
  247. }
  248. private BitString[] bitcode = new BitString[65535];
  249. private int[] category = new int[65535];
  250. private void initCategoryfloat()
  251. {
  252. int nrlower = 1;
  253. int nrupper = 2;
  254. int nr;
  255. BitString bs;
  256. for ( int cat = 1; cat <= 15; cat++ )
  257. {
  258. //Positive numbers
  259. for ( nr = nrlower; nr < nrupper; nr++ )
  260. {
  261. category[32767 + nr] = cat;
  262. bs = new BitString();
  263. bs.len = cat;
  264. bs.val = nr;
  265. bitcode[32767 + nr] = bs;
  266. }
  267. //Negative numbers
  268. for ( nr = -(nrupper - 1); nr <= -nrlower; nr++ )
  269. {
  270. category[32767 + nr] = cat;
  271. bs = new BitString();
  272. bs.len = cat;
  273. bs.val = nrupper - 1 + nr;
  274. bitcode[32767 + nr] = bs;
  275. }
  276. nrlower <<= 1;
  277. nrupper <<= 1;
  278. }
  279. }
  280. // IO functions
  281. private int bytenew = 0;
  282. private int bytepos = 7;
  283. public ByteArray byteout = new ByteArray();
  284. /**
  285. * Get the result
  286. */
  287. public byte[] GetBytes()
  288. {
  289. if ( !isDone )
  290. {
  291. Debug.LogError("JPEGEncoder not complete, cannot get bytes!");
  292. return new byte[1];
  293. }
  294. return byteout.GetAllBytes();
  295. }
  296. private void writeBits(BitString bs)
  297. {
  298. int value = bs.val;
  299. int posval = bs.len - 1;
  300. while ( posval >= 0 )
  301. {
  302. if ( ((uint)value & System.Convert.ToUInt32(1 << posval)) != 0 )
  303. {
  304. bytenew |= (int)(System.Convert.ToUInt32(1 << bytepos));
  305. }
  306. posval--;
  307. bytepos--;
  308. if ( bytepos < 0 )
  309. {
  310. if ( bytenew == 0xFF )
  311. {
  312. writeByte(0xFF);
  313. writeByte(0);
  314. }
  315. else
  316. {
  317. writeByte((byte)bytenew);
  318. }
  319. bytepos = 7;
  320. bytenew = 0;
  321. }
  322. }
  323. }
  324. private void writeByte(byte value)
  325. {
  326. byteout.writeByte(value);
  327. }
  328. private void writeWord(int value)
  329. {
  330. writeByte((byte)((value >> 8) & 0xFF));
  331. writeByte((byte)((value) & 0xFF));
  332. }
  333. // DCT & quantization core
  334. private float[] fDCTQuant(float[] data, float[] fdtbl)
  335. {
  336. float tmp0; float tmp1; float tmp2; float tmp3; float tmp4; float tmp5; float tmp6; float tmp7;
  337. float tmp10; float tmp11; float tmp12; float tmp13;
  338. float z1; float z2; float z3; float z4; float z5; float z11; float z13;
  339. int i;
  340. /* Pass 1: process rows. */
  341. int dataOff = 0;
  342. for ( i = 0; i < 8; i++ )
  343. {
  344. tmp0 = data[dataOff + 0] + data[dataOff + 7];
  345. tmp7 = data[dataOff + 0] - data[dataOff + 7];
  346. tmp1 = data[dataOff + 1] + data[dataOff + 6];
  347. tmp6 = data[dataOff + 1] - data[dataOff + 6];
  348. tmp2 = data[dataOff + 2] + data[dataOff + 5];
  349. tmp5 = data[dataOff + 2] - data[dataOff + 5];
  350. tmp3 = data[dataOff + 3] + data[dataOff + 4];
  351. tmp4 = data[dataOff + 3] - data[dataOff + 4];
  352. /* Even part */
  353. tmp10 = tmp0 + tmp3; /* phase 2 */
  354. tmp13 = tmp0 - tmp3;
  355. tmp11 = tmp1 + tmp2;
  356. tmp12 = tmp1 - tmp2;
  357. data[dataOff + 0] = tmp10 + tmp11; /* phase 3 */
  358. data[dataOff + 4] = tmp10 - tmp11;
  359. z1 = (tmp12 + tmp13) * 0.707106781f; /* c4 */
  360. data[dataOff + 2] = tmp13 + z1; /* phase 5 */
  361. data[dataOff + 6] = tmp13 - z1;
  362. /* Odd part */
  363. tmp10 = tmp4 + tmp5; /* phase 2 */
  364. tmp11 = tmp5 + tmp6;
  365. tmp12 = tmp6 + tmp7;
  366. /* The rotator is modified from fig 4-8 to avoid extra negations. */
  367. z5 = (tmp10 - tmp12) * 0.382683433f; /* c6 */
  368. z2 = 0.541196100f * tmp10 + z5; /* c2-c6 */
  369. z4 = 1.306562965f * tmp12 + z5; /* c2+c6 */
  370. z3 = tmp11 * 0.707106781f; /* c4 */
  371. z11 = tmp7 + z3; /* phase 5 */
  372. z13 = tmp7 - z3;
  373. data[dataOff + 5] = z13 + z2; /* phase 6 */
  374. data[dataOff + 3] = z13 - z2;
  375. data[dataOff + 1] = z11 + z4;
  376. data[dataOff + 7] = z11 - z4;
  377. dataOff += 8; /* advance pointer to next row */
  378. }
  379. /* Pass 2: process columns. */
  380. dataOff = 0;
  381. for ( i = 0; i < 8; i++ )
  382. {
  383. tmp0 = data[dataOff + 0] + data[dataOff + 56];
  384. tmp7 = data[dataOff + 0] - data[dataOff + 56];
  385. tmp1 = data[dataOff + 8] + data[dataOff + 48];
  386. tmp6 = data[dataOff + 8] - data[dataOff + 48];
  387. tmp2 = data[dataOff + 16] + data[dataOff + 40];
  388. tmp5 = data[dataOff + 16] - data[dataOff + 40];
  389. tmp3 = data[dataOff + 24] + data[dataOff + 32];
  390. tmp4 = data[dataOff + 24] - data[dataOff + 32];
  391. /* Even part */
  392. tmp10 = tmp0 + tmp3; /* phase 2 */
  393. tmp13 = tmp0 - tmp3;
  394. tmp11 = tmp1 + tmp2;
  395. tmp12 = tmp1 - tmp2;
  396. data[dataOff + 0] = tmp10 + tmp11; /* phase 3 */
  397. data[dataOff + 32] = tmp10 - tmp11;
  398. z1 = (tmp12 + tmp13) * 0.707106781f; /* c4 */
  399. data[dataOff + 16] = tmp13 + z1; /* phase 5 */
  400. data[dataOff + 48] = tmp13 - z1;
  401. /* Odd part */
  402. tmp10 = tmp4 + tmp5; /* phase 2 */
  403. tmp11 = tmp5 + tmp6;
  404. tmp12 = tmp6 + tmp7;
  405. /* The rotator is modified from fig 4-8 to avoid extra negations. */
  406. z5 = (tmp10 - tmp12) * 0.382683433f; /* c6 */
  407. z2 = 0.541196100f * tmp10 + z5; /* c2-c6 */
  408. z4 = 1.306562965f * tmp12 + z5; /* c2+c6 */
  409. z3 = tmp11 * 0.707106781f; /* c4 */
  410. z11 = tmp7 + z3; /* phase 5 */
  411. z13 = tmp7 - z3;
  412. data[dataOff + 40] = z13 + z2; /* phase 6 */
  413. data[dataOff + 24] = z13 - z2;
  414. data[dataOff + 8] = z11 + z4;
  415. data[dataOff + 56] = z11 - z4;
  416. dataOff++; /* advance pointer to next column */
  417. }
  418. // Quantize/descale the coefficients
  419. for ( i = 0; i < 64; i++ )
  420. {
  421. // Apply the quantization and scaling factor & Round to nearest integer
  422. data[i] = Mathf.Round((data[i] * fdtbl[i]));
  423. }
  424. return data;
  425. }
  426. // Chunk writing
  427. private void writeAPP0()
  428. {
  429. writeWord(0xFFE0); // marker
  430. writeWord(16); // length
  431. writeByte(0x4A); // J
  432. writeByte(0x46); // F
  433. writeByte(0x49); // I
  434. writeByte(0x46); // F
  435. writeByte(0); // = "JFIF",'\0'
  436. writeByte(1); // versionhi
  437. writeByte(1); // versionlo
  438. writeByte(0); // xyunits
  439. writeWord(1); // xdensity
  440. writeWord(1); // ydensity
  441. writeByte(0); // thumbnwidth
  442. writeByte(0); // thumbnheight
  443. }
  444. private void writeSOF0(int width, int height)
  445. {
  446. writeWord(0xFFC0); // marker
  447. writeWord(17); // length, truecolor YUV JPG
  448. writeByte(8); // precision
  449. writeWord(height);
  450. writeWord(width);
  451. writeByte(3); // nrofcomponents
  452. writeByte(1); // IdY
  453. writeByte(0x11); // HVY
  454. writeByte(0); // QTY
  455. writeByte(2); // IdU
  456. writeByte(0x11); // HVU
  457. writeByte(1); // QTU
  458. writeByte(3); // IdV
  459. writeByte(0x11); // HVV
  460. writeByte(1); // QTV
  461. }
  462. private void writeDQT()
  463. {
  464. writeWord(0xFFDB); // marker
  465. writeWord(132); // length
  466. writeByte(0);
  467. int i;
  468. for ( i = 0; i < 64; i++ )
  469. {
  470. writeByte((byte)(YTable[i]));
  471. }
  472. writeByte(1);
  473. for ( i = 0; i < 64; i++ )
  474. {
  475. writeByte((byte)(UVTable[i]));
  476. }
  477. }
  478. private void writeDHT()
  479. {
  480. writeWord(0xFFC4); // marker
  481. writeWord(0x01A2); // length
  482. int i;
  483. writeByte(0); // HTYDCinfo
  484. for ( i = 0; i < 16; i++ )
  485. {
  486. writeByte((byte)(std_dc_luminance_nrcodes[i + 1]));
  487. }
  488. for ( i = 0; i <= 11; i++ )
  489. {
  490. writeByte((byte)(std_dc_luminance_values[i]));
  491. }
  492. writeByte(0x10); // HTYACinfo
  493. for ( i = 0; i < 16; i++ )
  494. {
  495. writeByte((byte)(std_ac_luminance_nrcodes[i + 1]));
  496. }
  497. for ( i = 0; i <= 161; i++ )
  498. {
  499. writeByte((byte)(std_ac_luminance_values[i]));
  500. }
  501. writeByte(1); // HTUDCinfo
  502. for ( i = 0; i < 16; i++ )
  503. {
  504. writeByte((byte)(std_dc_chrominance_nrcodes[i + 1]));
  505. }
  506. for ( i = 0; i <= 11; i++ )
  507. {
  508. writeByte((byte)(std_dc_chrominance_values[i]));
  509. }
  510. writeByte(0x11); // HTUACinfo
  511. for ( i = 0; i < 16; i++ )
  512. {
  513. writeByte((byte)(std_ac_chrominance_nrcodes[i + 1]));
  514. }
  515. for ( i = 0; i <= 161; i++ )
  516. {
  517. writeByte((byte)(std_ac_chrominance_values[i]));
  518. }
  519. }
  520. private void writeSOS()
  521. {
  522. writeWord(0xFFDA); // marker
  523. writeWord(12); // length
  524. writeByte(3); // nrofcomponents
  525. writeByte(1); // IdY
  526. writeByte(0); // HTY
  527. writeByte(2); // IdU
  528. writeByte(0x11); // HTU
  529. writeByte(3); // IdV
  530. writeByte(0x11); // HTV
  531. writeByte(0); // Ss
  532. writeByte(0x3f); // Se
  533. writeByte(0); // Bf
  534. }
  535. // Core processing
  536. private int[] DU = new int[64];
  537. private float processDU(float[] CDU, float[] fdtbl, float DC, BitString[] HTDC, BitString[] HTAC)
  538. {
  539. BitString EOB = HTAC[0x00];
  540. BitString M16zeroes = HTAC[0xF0];
  541. int i;
  542. float[] DU_DCT = fDCTQuant(CDU, fdtbl);
  543. //ZigZag reorder
  544. for ( i = 0; i < 64; i++ )
  545. {
  546. DU[ZigZag[i]] = (int)(DU_DCT[i]);
  547. }
  548. int Diff = (int)(DU[0] - DC);
  549. DC = DU[0];
  550. //Encode DC
  551. if ( Diff == 0 )
  552. {
  553. writeBits(HTDC[0]); // Diff might be 0
  554. }
  555. else
  556. {
  557. writeBits(HTDC[category[32767 + Diff]]);
  558. writeBits(bitcode[32767 + Diff]);
  559. }
  560. //Encode ACs
  561. int end0pos = 63;
  562. for ( ; (end0pos > 0) && (DU[end0pos] == 0); end0pos-- )
  563. {
  564. };
  565. //end0pos = first element in reverse order !=0
  566. if ( end0pos == 0 )
  567. {
  568. writeBits(EOB);
  569. return DC;
  570. }
  571. i = 1;
  572. while ( i <= end0pos )
  573. {
  574. int startpos = i;
  575. for ( ; (DU[i] == 0) && (i <= end0pos); i++ )
  576. {
  577. }
  578. int nrzeroes = i - startpos;
  579. if ( nrzeroes >= 16 )
  580. {
  581. for ( int nrmarker =1; nrmarker <= nrzeroes / 16; nrmarker++ )
  582. {
  583. writeBits(M16zeroes);
  584. }
  585. nrzeroes = (nrzeroes & 0xF);
  586. }
  587. writeBits(HTAC[nrzeroes * 16 + category[32767 + DU[i]]]);
  588. writeBits(bitcode[32767 + DU[i]]);
  589. i++;
  590. }
  591. if ( end0pos != 63 )
  592. {
  593. writeBits(EOB);
  594. }
  595. return DC;
  596. }
  597. private float[] YDU = new float[64];
  598. private float[] UDU = new float[64];
  599. private float[] VDU = new float[64];
  600. private void RGB2YUV(BitmapData img, int xpos, int ypos)
  601. {
  602. int pos = 0;
  603. for ( int y=0; y < 8; y++ )
  604. {
  605. for ( int x=0; x < 8; x++ )
  606. {
  607. Color C = img.getPixelColor(xpos + x, img.height - (ypos + y));
  608. float R = C.r * 255.0f;
  609. float G = C.g * 255.0f;
  610. float B = C.b * 255.0f;
  611. YDU[pos] = (((0.29900f) * R + (0.58700f) * G + (0.11400f) * B)) - 128.0f;
  612. UDU[pos] = (((-0.16874f) * R + (-0.33126f) * G + (0.50000f) * B));
  613. VDU[pos] = (((0.50000f) * R + (-0.41869f) * G + (-0.08131f) * B));
  614. pos++;
  615. }
  616. }
  617. }
  618. /**
  619. * Constructor for JPEGEncoder class
  620. *
  621. * @param quality The quality level between 1 and 100 that detrmines the
  622. * level of compression used in the generated JPEG
  623. * @langversion ActionScript 3.0
  624. * @playerversion Flash 9.0
  625. * @tiptext
  626. */
  627. // public flag--other scripts must watch this to know when they can safely get data out
  628. public bool isDone = false;
  629. private BitmapData image;
  630. private int sf = 0;
  631. public JPGEncoder(Color[] pixels, int width, int height, float quality)
  632. {
  633. // save out texture data to our own data structure
  634. image = new BitmapData(pixels, width, height);
  635. if ( quality <= 0.0f )
  636. quality = 1.0f;
  637. if ( quality > 100.0f )
  638. quality = 100.0f;
  639. if ( quality < 50.0f )
  640. sf = (int)(5000.0f / quality);
  641. else
  642. sf = (int)(200.0f - quality * 2.0f);
  643. }
  644. /**
  645. * Handle our initialization and encoding
  646. */
  647. public void doEncoding()
  648. {
  649. isDone = false;
  650. // Create tables -- technically we could only do this once for multiple encodes
  651. initHuffmanTbl();
  652. initCategoryfloat();
  653. initQuantTables(sf);
  654. // Do actual encoding
  655. encode();
  656. // signal that our data is ok to use now
  657. isDone = true;
  658. // tell the thread to stop--not sure if this is actually needed
  659. image = null;
  660. }
  661. /**
  662. * Created a JPEG image from the specified BitmapData
  663. *
  664. * @param image The BitmapData that will be converted into the JPEG format.
  665. * @return a ByteArray representing the JPEG encoded image data.
  666. * @langversion ActionScript 3.0
  667. * @playerversion Flash 9.0
  668. * @tiptext
  669. */
  670. private void encode()
  671. {
  672. // Initialize bit writer
  673. byteout = new ByteArray();
  674. bytenew = 0;
  675. bytepos = 7;
  676. // Add JPEG headers
  677. writeWord(0xFFD8); // SOI
  678. writeAPP0();
  679. writeDQT();
  680. writeSOF0(image.width, image.height);
  681. writeDHT();
  682. writeSOS();
  683. // Encode 8x8 macroblocks
  684. float DCY =0.0f;
  685. float DCU =0.0f;
  686. float DCV =0.0f;
  687. bytenew = 0;
  688. bytepos = 7;
  689. for ( int ypos=0; ypos < image.height; ypos += 8 )
  690. {
  691. for ( int xpos =0; xpos < image.width; xpos += 8 )
  692. {
  693. RGB2YUV(image, xpos, ypos);
  694. DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
  695. DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
  696. DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
  697. // let other threads do stuff too
  698. //Thread.Sleep(0);
  699. }
  700. }
  701. // Do the bit alignment of the EOI marker
  702. if ( bytepos >= 0 )
  703. {
  704. BitString fillbits = new BitString();
  705. fillbits.len = bytepos + 1;
  706. fillbits.val = (1 << (bytepos + 1)) - 1;
  707. writeBits(fillbits);
  708. }
  709. writeWord(0xFFD9); //EOI
  710. //return byteout;
  711. isDone = true;
  712. }
  713. }
  714. /*
  715. * Ported to UnityScript by Matthew Wegner, Flashbang Studios
  716. *
  717. * Original code is from as3corelib, found here:
  718. * http://code.google.com/p/as3corelib/source/browse/trunk/src/com/adobe/images/JPGEncoder.as
  719. *
  720. * Original copyright notice is below:
  721. */
  722. /*
  723. * Ported to C# by Tony McBride
  724. *
  725. * C# version isnt threaded so just call like this:
  726. * JPGEncoder NewEncoder = new JPGEncoder( MyTexture , 75.0f );
  727. * NewEncoder.doEncoding();
  728. * byte[] TexData = NewEncoder.GetBytes();
  729. */
  730. #endif