├── .gitignore
├── Assets
├── JPEGEncoder.cs
├── JPEGEncoder.cs.meta
├── StreamingAssets.meta
├── StreamingAssets
│ ├── log.txt
│ └── log.txt.meta
├── UpLoaderDemo.cs
├── UpLoaderDemo.cs.meta
├── demo.unity
└── demo.unity.meta
├── PHP
└── upload.php
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | [Ll]ibrary/
2 | [Tt]emp/
3 | [Oo]bj/
4 | [Bb]uild/
5 | [Bb]uilds/
6 | Assets/AssetStoreTools*
7 |
8 | # Visual Studio cache directory
9 | .vs/
10 |
11 | # Autogenerated VS/MD/Consulo solution and project files
12 | ExportedObj/
13 | .consulo/
14 | *.csproj
15 | *.unityproj
16 | *.sln
17 | *.suo
18 | *.tmp
19 | *.user
20 | *.userprefs
21 | *.pidb
22 | *.booproj
23 | *.svd
24 | *.pdb
25 | *.opendb
26 |
27 | # Unity3D generated meta files
28 | *.pidb.meta
29 | *.pdb.meta
30 |
31 | # Unity3D Generated File On Crash Reports
32 | sysinfo.txt
33 |
34 | # Builds
35 | *.apk
36 | *.unitypackage
37 |
--------------------------------------------------------------------------------
/Assets/JPEGEncoder.cs:
--------------------------------------------------------------------------------
1 | #if !UNITY_FLASH
2 | using UnityEngine;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | //Copy from http://mcain.bluehoststaff.com/gamedesignftp/backup_Corey/Mega-Fiers/Scripts/MegaGrab/JPGEncoder.cs
7 | public class ByteArrayTool
8 | {
9 | private MemoryStream stream;
10 | private BinaryWriter writer;
11 |
12 | public ByteArrayTool()
13 | {
14 | stream = new MemoryStream();
15 | writer = new BinaryWriter(stream);
16 | }
17 |
18 | /**
19 | * Function from AS3--add a byte to our stream
20 | */
21 | public void writeByte(byte value)
22 | {
23 | writer.Write(value);
24 | }
25 |
26 | /**
27 | * Spit back all bytes--to either pass via WWW or save to disk
28 | */
29 | public byte[] GetAllBytes()
30 | {
31 | byte[] buffer = new byte[stream.Length];
32 | stream.Position = 0;
33 | stream.Read(buffer, 0, buffer.Length);
34 |
35 | return buffer;
36 | }
37 | }
38 |
39 | /**
40 | * This should really be a struct--if you care, declare it in C#
41 | */
42 | class BitString
43 | {
44 | public int len = 0;
45 | public int val = 0;
46 | }
47 |
48 | /**
49 | * Another flash class--emulating the stuff the encoder uses
50 | */
51 | public class BitmapData
52 | {
53 | public int height;
54 | public int width;
55 |
56 | private Color[] pixels;
57 |
58 | /**
59 | * Pull all of our pixels off the texture (Unity stuff isn't thread safe, and this is faster)
60 | */
61 | public BitmapData(Color[] _pixels, int _width, int _height)
62 | {
63 | height = _height;
64 | width = _width;
65 |
66 | pixels = _pixels;
67 | }
68 |
69 | public BitmapData(Texture2D texture)
70 | {
71 | height = texture.height;
72 | width = texture.width;
73 |
74 | pixels = texture.GetPixels();
75 | }
76 |
77 | /**
78 | * Mimic the flash function
79 | */
80 | public Color getPixelColor(int x, int y)
81 | {
82 | if (x >= width)
83 | x = width - 1;
84 |
85 | if (y >= height)
86 | y = height - 1;
87 |
88 | if (x < 0)
89 | x = 0;
90 |
91 | if (y < 0)
92 | y = 0;
93 |
94 | return pixels[y * width + x];
95 | }
96 | }
97 |
98 | /**
99 | * Class that converts BitmapData into a valid JPEG
100 | */
101 | public class JPGEncoder
102 | {
103 |
104 | // Static table initialization
105 |
106 | public int[] ZigZag = new int[64] {
107 | 0, 1, 5, 6,14,15,27,28,
108 | 2, 4, 7,13,16,26,29,42,
109 | 3, 8,12,17,25,30,41,43,
110 | 9,11,18,24,31,40,44,53,
111 | 10,19,23,32,39,45,52,54,
112 | 20,22,33,38,46,51,55,60,
113 | 21,34,37,47,50,56,59,61,
114 | 35,36,48,49,57,58,62,63
115 | };
116 |
117 | private int[] YTable = new int[64];
118 | private int[] UVTable = new int[64];
119 | private float[] fdtbl_Y = new float[64];
120 | private float[] fdtbl_UV = new float[64];
121 |
122 | private void initQuantTables(int sf)
123 | {
124 | int i;
125 | float t;
126 | int[] YQT = new int[64] {
127 | 16, 11, 10, 16, 24, 40, 51, 61,
128 | 12, 12, 14, 19, 26, 58, 60, 55,
129 | 14, 13, 16, 24, 40, 57, 69, 56,
130 | 14, 17, 22, 29, 51, 87, 80, 62,
131 | 18, 22, 37, 56, 68,109,103, 77,
132 | 24, 35, 55, 64, 81,104,113, 92,
133 | 49, 64, 78, 87,103,121,120,101,
134 | 72, 92, 95, 98,112,100,103, 99
135 | };
136 |
137 | for (i = 0; i < 64; i++)
138 | {
139 | t = Mathf.Floor((YQT[i] * sf + 50.0f) / 100.0f);
140 | if (t < 1.0f)
141 | {
142 | t = 1.0f;
143 | }
144 | else if (t > 255.0f)
145 | {
146 | t = 255.0f;
147 | }
148 | YTable[ZigZag[i]] = (int)t;
149 | }
150 |
151 | int[] UVQT = new int[64] {
152 | 17, 18, 24, 47, 99, 99, 99, 99,
153 | 18, 21, 26, 66, 99, 99, 99, 99,
154 | 24, 26, 56, 99, 99, 99, 99, 99,
155 | 47, 66, 99, 99, 99, 99, 99, 99,
156 | 99, 99, 99, 99, 99, 99, 99, 99,
157 | 99, 99, 99, 99, 99, 99, 99, 99,
158 | 99, 99, 99, 99, 99, 99, 99, 99,
159 | 99, 99, 99, 99, 99, 99, 99, 99
160 | };
161 |
162 | for (i = 0; i < 64; i++)
163 | {
164 | t = Mathf.Floor((UVQT[i] * sf + 50.0f) / 100.0f);
165 | if (t < 1.0f)
166 | {
167 | t = 1.0f;
168 | }
169 | else if (t > 255.0f)
170 | {
171 | t = 255.0f;
172 | }
173 | UVTable[ZigZag[i]] = (int)t;
174 | }
175 |
176 | float[] aasf = new float[8] {
177 | 1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
178 | 1.0f, 0.785694958f, 0.541196100f, 0.275899379f
179 | };
180 |
181 | i = 0;
182 | for (int row = 0; row < 8; row++)
183 | {
184 | for (int col = 0; col < 8; col++)
185 | {
186 | fdtbl_Y[i] = (1.0f / (YTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0f));
187 | fdtbl_UV[i] = (1.0f / (UVTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0f));
188 | i++;
189 | }
190 | }
191 | }
192 |
193 | private BitString[] YDC_HT;
194 | private BitString[] UVDC_HT;
195 | private BitString[] YAC_HT;
196 | private BitString[] UVAC_HT;
197 |
198 | private BitString[] computeHuffmanTbl(int[] nrcodes, int[] std_table)
199 | {
200 | int codevalue = 0;
201 | int pos_in_table = 0;
202 | BitString[] HT = new BitString[16 * 16];
203 | for (int k = 1; k <= 16; k++)
204 | {
205 | for (int j = 1; j <= nrcodes[k]; j++)
206 | {
207 | HT[std_table[pos_in_table]] = new BitString();
208 | HT[std_table[pos_in_table]].val = codevalue;
209 | HT[std_table[pos_in_table]].len = k;
210 | pos_in_table++;
211 | codevalue++;
212 | }
213 | codevalue *= 2;
214 | }
215 | return HT;
216 | }
217 |
218 | 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 };
219 | private int[] std_dc_luminance_values = new int[12] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
220 | 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 };
221 | private int[] std_ac_luminance_values = new int[162] {
222 | 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,
223 | 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
224 | 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
225 | 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
226 | 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,
227 | 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
228 | 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,
229 | 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
230 | 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
231 | 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
232 | 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
233 | 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
234 | 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
235 | 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
236 | 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
237 | 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
238 | 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,
239 | 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
240 | 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
241 | 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
242 | 0xf9,0xfa
243 | };
244 |
245 | 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 };
246 | private int[] std_dc_chrominance_values = new int[12] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
247 | 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 };
248 | private int[] std_ac_chrominance_values = new int[162] {
249 | 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,
250 | 0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
251 | 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
252 | 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
253 | 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,
254 | 0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
255 | 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,
256 | 0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
257 | 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
258 | 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,
259 | 0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,
260 | 0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
261 | 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,
262 | 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,
263 | 0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
264 | 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
265 | 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,
266 | 0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
267 | 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,
268 | 0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
269 | 0xf9,0xfa
270 | };
271 |
272 | private void initHuffmanTbl()
273 | {
274 | YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes, std_dc_luminance_values);
275 | UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes, std_dc_chrominance_values);
276 | YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes, std_ac_luminance_values);
277 | UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes, std_ac_chrominance_values);
278 | }
279 |
280 |
281 | private BitString[] bitcode = new BitString[65535];
282 | private int[] category = new int[65535];
283 |
284 | private void initCategoryfloat()
285 | {
286 | int nrlower = 1;
287 | int nrupper = 2;
288 | int nr;
289 | BitString bs;
290 |
291 | for (int cat = 1; cat <= 15; cat++)
292 | {
293 | //Positive numbers
294 | for (nr = nrlower; nr < nrupper; nr++)
295 | {
296 | category[32767 + nr] = cat;
297 |
298 | bs = new BitString();
299 | bs.len = cat;
300 | bs.val = nr;
301 | bitcode[32767 + nr] = bs;
302 | }
303 | //Negative numbers
304 | for (nr = -(nrupper - 1); nr <= -nrlower; nr++)
305 | {
306 | category[32767 + nr] = cat;
307 |
308 | bs = new BitString();
309 | bs.len = cat;
310 | bs.val = nrupper - 1 + nr;
311 | bitcode[32767 + nr] = bs;
312 | }
313 | nrlower <<= 1;
314 | nrupper <<= 1;
315 | }
316 | }
317 |
318 | // IO functions
319 | private int bytenew = 0;
320 | private int bytepos = 7;
321 | public ByteArrayTool byteout = new ByteArrayTool();
322 |
323 | /**
324 | * Get the result
325 | */
326 | public byte[] GetBytes()
327 | {
328 | if (!isDone)
329 | {
330 | Debug.LogError("JPEGEncoder not complete, cannot get bytes!");
331 | return new byte[1];
332 | }
333 |
334 | return byteout.GetAllBytes();
335 | }
336 |
337 | private void writeBits(BitString bs)
338 | {
339 | int value = bs.val;
340 | int posval = bs.len - 1;
341 | while (posval >= 0)
342 | {
343 | if (((uint)value & System.Convert.ToUInt32(1 << posval)) != 0)
344 | {
345 | bytenew |= (int)(System.Convert.ToUInt32(1 << bytepos));
346 | }
347 | posval--;
348 | bytepos--;
349 | if (bytepos < 0)
350 | {
351 | if (bytenew == 0xFF)
352 | {
353 | writeByte(0xFF);
354 | writeByte(0);
355 | }
356 | else
357 | {
358 | writeByte((byte)bytenew);
359 | }
360 | bytepos = 7;
361 | bytenew = 0;
362 | }
363 | }
364 | }
365 |
366 | private void writeByte(byte value)
367 | {
368 | byteout.writeByte(value);
369 | }
370 |
371 | private void writeWord(int value)
372 | {
373 | writeByte((byte)((value >> 8) & 0xFF));
374 | writeByte((byte)((value) & 0xFF));
375 | }
376 |
377 | // DCT & quantization core
378 |
379 | private float[] fDCTQuant(float[] data, float[] fdtbl)
380 | {
381 | float tmp0; float tmp1; float tmp2; float tmp3; float tmp4; float tmp5; float tmp6; float tmp7;
382 | float tmp10; float tmp11; float tmp12; float tmp13;
383 |
384 | float z1; float z2; float z3; float z4; float z5; float z11; float z13;
385 |
386 | int i;
387 |
388 | /* Pass 1: process rows. */
389 | int dataOff = 0;
390 | for (i = 0; i < 8; i++)
391 | {
392 | tmp0 = data[dataOff + 0] + data[dataOff + 7];
393 | tmp7 = data[dataOff + 0] - data[dataOff + 7];
394 | tmp1 = data[dataOff + 1] + data[dataOff + 6];
395 | tmp6 = data[dataOff + 1] - data[dataOff + 6];
396 | tmp2 = data[dataOff + 2] + data[dataOff + 5];
397 | tmp5 = data[dataOff + 2] - data[dataOff + 5];
398 | tmp3 = data[dataOff + 3] + data[dataOff + 4];
399 | tmp4 = data[dataOff + 3] - data[dataOff + 4];
400 |
401 | /* Even part */
402 | tmp10 = tmp0 + tmp3; /* phase 2 */
403 | tmp13 = tmp0 - tmp3;
404 | tmp11 = tmp1 + tmp2;
405 | tmp12 = tmp1 - tmp2;
406 |
407 | data[dataOff + 0] = tmp10 + tmp11; /* phase 3 */
408 | data[dataOff + 4] = tmp10 - tmp11;
409 |
410 | z1 = (tmp12 + tmp13) * 0.707106781f; /* c4 */
411 | data[dataOff + 2] = tmp13 + z1; /* phase 5 */
412 | data[dataOff + 6] = tmp13 - z1;
413 |
414 | /* Odd part */
415 | tmp10 = tmp4 + tmp5; /* phase 2 */
416 | tmp11 = tmp5 + tmp6;
417 | tmp12 = tmp6 + tmp7;
418 |
419 | /* The rotator is modified from fig 4-8 to avoid extra negations. */
420 | z5 = (tmp10 - tmp12) * 0.382683433f; /* c6 */
421 | z2 = 0.541196100f * tmp10 + z5; /* c2-c6 */
422 | z4 = 1.306562965f * tmp12 + z5; /* c2+c6 */
423 | z3 = tmp11 * 0.707106781f; /* c4 */
424 |
425 | z11 = tmp7 + z3; /* phase 5 */
426 | z13 = tmp7 - z3;
427 |
428 | data[dataOff + 5] = z13 + z2; /* phase 6 */
429 | data[dataOff + 3] = z13 - z2;
430 | data[dataOff + 1] = z11 + z4;
431 | data[dataOff + 7] = z11 - z4;
432 |
433 | dataOff += 8; /* advance pointer to next row */
434 | }
435 |
436 | /* Pass 2: process columns. */
437 | dataOff = 0;
438 | for (i = 0; i < 8; i++)
439 | {
440 | tmp0 = data[dataOff + 0] + data[dataOff + 56];
441 | tmp7 = data[dataOff + 0] - data[dataOff + 56];
442 | tmp1 = data[dataOff + 8] + data[dataOff + 48];
443 | tmp6 = data[dataOff + 8] - data[dataOff + 48];
444 | tmp2 = data[dataOff + 16] + data[dataOff + 40];
445 | tmp5 = data[dataOff + 16] - data[dataOff + 40];
446 | tmp3 = data[dataOff + 24] + data[dataOff + 32];
447 | tmp4 = data[dataOff + 24] - data[dataOff + 32];
448 |
449 | /* Even part */
450 | tmp10 = tmp0 + tmp3; /* phase 2 */
451 | tmp13 = tmp0 - tmp3;
452 | tmp11 = tmp1 + tmp2;
453 | tmp12 = tmp1 - tmp2;
454 |
455 | data[dataOff + 0] = tmp10 + tmp11; /* phase 3 */
456 | data[dataOff + 32] = tmp10 - tmp11;
457 |
458 | z1 = (tmp12 + tmp13) * 0.707106781f; /* c4 */
459 | data[dataOff + 16] = tmp13 + z1; /* phase 5 */
460 | data[dataOff + 48] = tmp13 - z1;
461 |
462 | /* Odd part */
463 | tmp10 = tmp4 + tmp5; /* phase 2 */
464 | tmp11 = tmp5 + tmp6;
465 | tmp12 = tmp6 + tmp7;
466 |
467 | /* The rotator is modified from fig 4-8 to avoid extra negations. */
468 | z5 = (tmp10 - tmp12) * 0.382683433f; /* c6 */
469 | z2 = 0.541196100f * tmp10 + z5; /* c2-c6 */
470 | z4 = 1.306562965f * tmp12 + z5; /* c2+c6 */
471 | z3 = tmp11 * 0.707106781f; /* c4 */
472 |
473 | z11 = tmp7 + z3; /* phase 5 */
474 | z13 = tmp7 - z3;
475 |
476 | data[dataOff + 40] = z13 + z2; /* phase 6 */
477 | data[dataOff + 24] = z13 - z2;
478 | data[dataOff + 8] = z11 + z4;
479 | data[dataOff + 56] = z11 - z4;
480 |
481 | dataOff++; /* advance pointer to next column */
482 | }
483 |
484 | // Quantize/descale the coefficients
485 | for (i = 0; i < 64; i++)
486 | {
487 | // Apply the quantization and scaling factor & Round to nearest integer
488 | data[i] = Mathf.Round((data[i] * fdtbl[i]));
489 | }
490 | return data;
491 | }
492 |
493 | // Chunk writing
494 |
495 | private void writeAPP0()
496 | {
497 | writeWord(0xFFE0); // marker
498 | writeWord(16); // length
499 | writeByte(0x4A); // J
500 | writeByte(0x46); // F
501 | writeByte(0x49); // I
502 | writeByte(0x46); // F
503 | writeByte(0); // = "JFIF",'\0'
504 | writeByte(1); // versionhi
505 | writeByte(1); // versionlo
506 | writeByte(0); // xyunits
507 | writeWord(1); // xdensity
508 | writeWord(1); // ydensity
509 | writeByte(0); // thumbnwidth
510 | writeByte(0); // thumbnheight
511 | }
512 |
513 | private void writeSOF0(int width, int height)
514 | {
515 | writeWord(0xFFC0); // marker
516 | writeWord(17); // length, truecolor YUV JPG
517 | writeByte(8); // precision
518 | writeWord(height);
519 | writeWord(width);
520 | writeByte(3); // nrofcomponents
521 | writeByte(1); // IdY
522 | writeByte(0x11); // HVY
523 | writeByte(0); // QTY
524 | writeByte(2); // IdU
525 | writeByte(0x11); // HVU
526 | writeByte(1); // QTU
527 | writeByte(3); // IdV
528 | writeByte(0x11); // HVV
529 | writeByte(1); // QTV
530 | }
531 |
532 | private void writeDQT()
533 | {
534 | writeWord(0xFFDB); // marker
535 | writeWord(132); // length
536 | writeByte(0);
537 | int i;
538 | for (i = 0; i < 64; i++)
539 | {
540 | writeByte((byte)(YTable[i]));
541 | }
542 | writeByte(1);
543 | for (i = 0; i < 64; i++)
544 | {
545 | writeByte((byte)(UVTable[i]));
546 | }
547 | }
548 |
549 | private void writeDHT()
550 | {
551 | writeWord(0xFFC4); // marker
552 | writeWord(0x01A2); // length
553 | int i;
554 |
555 | writeByte(0); // HTYDCinfo
556 | for (i = 0; i < 16; i++)
557 | {
558 | writeByte((byte)(std_dc_luminance_nrcodes[i + 1]));
559 | }
560 | for (i = 0; i <= 11; i++)
561 | {
562 | writeByte((byte)(std_dc_luminance_values[i]));
563 | }
564 |
565 | writeByte(0x10); // HTYACinfo
566 | for (i = 0; i < 16; i++)
567 | {
568 | writeByte((byte)(std_ac_luminance_nrcodes[i + 1]));
569 | }
570 | for (i = 0; i <= 161; i++)
571 | {
572 | writeByte((byte)(std_ac_luminance_values[i]));
573 | }
574 |
575 | writeByte(1); // HTUDCinfo
576 | for (i = 0; i < 16; i++)
577 | {
578 | writeByte((byte)(std_dc_chrominance_nrcodes[i + 1]));
579 | }
580 | for (i = 0; i <= 11; i++)
581 | {
582 | writeByte((byte)(std_dc_chrominance_values[i]));
583 | }
584 |
585 | writeByte(0x11); // HTUACinfo
586 | for (i = 0; i < 16; i++)
587 | {
588 | writeByte((byte)(std_ac_chrominance_nrcodes[i + 1]));
589 | }
590 | for (i = 0; i <= 161; i++)
591 | {
592 | writeByte((byte)(std_ac_chrominance_values[i]));
593 | }
594 | }
595 |
596 | private void writeSOS()
597 | {
598 | writeWord(0xFFDA); // marker
599 | writeWord(12); // length
600 | writeByte(3); // nrofcomponents
601 | writeByte(1); // IdY
602 | writeByte(0); // HTY
603 | writeByte(2); // IdU
604 | writeByte(0x11); // HTU
605 | writeByte(3); // IdV
606 | writeByte(0x11); // HTV
607 | writeByte(0); // Ss
608 | writeByte(0x3f); // Se
609 | writeByte(0); // Bf
610 | }
611 |
612 | // Core processing
613 | private int[] DU = new int[64];
614 |
615 | private float processDU(float[] CDU, float[] fdtbl, float DC, BitString[] HTDC, BitString[] HTAC)
616 | {
617 | BitString EOB = HTAC[0x00];
618 | BitString M16zeroes = HTAC[0xF0];
619 | int i;
620 |
621 | float[] DU_DCT = fDCTQuant(CDU, fdtbl);
622 |
623 | //ZigZag reorder
624 | for (i = 0; i < 64; i++)
625 | {
626 | DU[ZigZag[i]] = (int)(DU_DCT[i]);
627 | }
628 | int Diff = (int)(DU[0] - DC);
629 | DC = DU[0];
630 |
631 | //Encode DC
632 | if (Diff == 0)
633 | {
634 | writeBits(HTDC[0]); // Diff might be 0
635 | }
636 | else
637 | {
638 | writeBits(HTDC[category[32767 + Diff]]);
639 | writeBits(bitcode[32767 + Diff]);
640 | }
641 | //Encode ACs
642 | int end0pos = 63;
643 | for (; (end0pos > 0) && (DU[end0pos] == 0); end0pos--)
644 | {
645 | };
646 | //end0pos = first element in reverse order !=0
647 | if (end0pos == 0)
648 | {
649 | writeBits(EOB);
650 | return DC;
651 | }
652 | i = 1;
653 | while (i <= end0pos)
654 | {
655 | int startpos = i;
656 | for (; (DU[i] == 0) && (i <= end0pos); i++)
657 | {
658 | }
659 | int nrzeroes = i - startpos;
660 | if (nrzeroes >= 16)
661 | {
662 | for (int nrmarker = 1; nrmarker <= nrzeroes / 16; nrmarker++)
663 | {
664 | writeBits(M16zeroes);
665 | }
666 | nrzeroes = (nrzeroes & 0xF);
667 | }
668 | writeBits(HTAC[nrzeroes * 16 + category[32767 + DU[i]]]);
669 | writeBits(bitcode[32767 + DU[i]]);
670 | i++;
671 | }
672 | if (end0pos != 63)
673 | {
674 | writeBits(EOB);
675 | }
676 | return DC;
677 | }
678 |
679 | private float[] YDU = new float[64];
680 | private float[] UDU = new float[64];
681 | private float[] VDU = new float[64];
682 |
683 | private void RGB2YUV(BitmapData img, int xpos, int ypos)
684 | {
685 | int pos = 0;
686 | for (int y = 0; y < 8; y++)
687 | {
688 | for (int x = 0; x < 8; x++)
689 | {
690 | Color C = img.getPixelColor(xpos + x, img.height - (ypos + y));
691 | float R = C.r * 255.0f;
692 | float G = C.g * 255.0f;
693 | float B = C.b * 255.0f;
694 | YDU[pos] = (((0.29900f) * R + (0.58700f) * G + (0.11400f) * B)) - 128.0f;
695 | UDU[pos] = (((-0.16874f) * R + (-0.33126f) * G + (0.50000f) * B));
696 | VDU[pos] = (((0.50000f) * R + (-0.41869f) * G + (-0.08131f) * B));
697 | pos++;
698 | }
699 | }
700 | }
701 |
702 | /**
703 | * Constructor for JPEGEncoder class
704 | *
705 | * @param quality The quality level between 1 and 100 that detrmines the
706 | * level of compression used in the generated JPEG
707 | * @langversion ActionScript 3.0
708 | * @playerversion Flash 9.0
709 | * @tiptext
710 | */
711 |
712 | // public flag--other scripts must watch this to know when they can safely get data out
713 | public bool isDone = false;
714 | private BitmapData image;
715 | private int sf = 0;
716 |
717 | public JPGEncoder(Color[] pixels, int width, int height, float quality)
718 | {
719 | // save out texture data to our own data structure
720 | image = new BitmapData(pixels, width, height);
721 |
722 | if (quality <= 0.0f)
723 | quality = 1.0f;
724 |
725 | if (quality > 100.0f)
726 | quality = 100.0f;
727 |
728 | if (quality < 50.0f)
729 | sf = (int)(5000.0f / quality);
730 | else
731 | sf = (int)(200.0f - quality * 2.0f);
732 | }
733 |
734 | public JPGEncoder(Texture2D texture, float quality)
735 | {
736 | // save out texture data to our own data structure
737 | image = new BitmapData(texture);
738 |
739 | if (quality <= 0.0f)
740 | quality = 1.0f;
741 |
742 | if (quality > 100.0f)
743 | quality = 100.0f;
744 |
745 | if (quality < 50.0f)
746 | sf = (int)(5000.0f / quality);
747 | else
748 | sf = (int)(200.0f - quality * 2.0f);
749 | }
750 |
751 |
752 |
753 | /**
754 | * Handle our initialization and encoding
755 | */
756 | public void doEncoding()
757 | {
758 | isDone = false;
759 |
760 | // Create tables -- technically we could only do this once for multiple encodes
761 | initHuffmanTbl();
762 | initCategoryfloat();
763 | initQuantTables(sf);
764 |
765 | // Do actual encoding
766 | encode();
767 |
768 | // signal that our data is ok to use now
769 | isDone = true;
770 |
771 | // tell the thread to stop--not sure if this is actually needed
772 | image = null;
773 | }
774 |
775 | /**
776 | * Created a JPEG image from the specified BitmapData
777 | *
778 | * @param image The BitmapData that will be converted into the JPEG format.
779 | * @return a ByteArrayTool representing the JPEG encoded image data.
780 | * @langversion ActionScript 3.0
781 | * @playerversion Flash 9.0
782 | * @tiptext
783 | */
784 | private void encode()
785 | {
786 | // Initialize bit writer
787 | byteout = new ByteArrayTool();
788 | bytenew = 0;
789 | bytepos = 7;
790 |
791 | // Add JPEG headers
792 | writeWord(0xFFD8); // SOI
793 | writeAPP0();
794 | writeDQT();
795 | writeSOF0(image.width, image.height);
796 | writeDHT();
797 | writeSOS();
798 |
799 | // Encode 8x8 macroblocks
800 | float DCY = 0.0f;
801 | float DCU = 0.0f;
802 | float DCV = 0.0f;
803 | bytenew = 0;
804 | bytepos = 7;
805 | for (int ypos = 0; ypos < image.height; ypos += 8)
806 | {
807 | for (int xpos = 0; xpos < image.width; xpos += 8)
808 | {
809 | RGB2YUV(image, xpos, ypos);
810 | DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
811 | DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
812 | DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
813 |
814 | // let other threads do stuff too
815 | //Thread.Sleep(0);
816 | }
817 | }
818 |
819 | // Do the bit alignment of the EOI marker
820 | if (bytepos >= 0)
821 | {
822 | BitString fillbits = new BitString();
823 | fillbits.len = bytepos + 1;
824 | fillbits.val = (1 << (bytepos + 1)) - 1;
825 | writeBits(fillbits);
826 | }
827 |
828 | writeWord(0xFFD9); //EOI
829 | //return byteout;
830 | isDone = true;
831 | }
832 | }
833 |
834 | /*
835 | * Ported to UnityScript by Matthew Wegner, Flashbang Studios
836 | *
837 | * Original code is from as3corelib, found here:
838 | * http://code.google.com/p/as3corelib/source/browse/trunk/src/com/adobe/images/JPGEncoder.as
839 | *
840 | * Original copyright notice is below:
841 | */
842 |
843 | /*
844 | * Ported to C# by Tony McBride
845 | *
846 | * C# version isnt threaded so just call like this:
847 | * JPGEncoder NewEncoder = new JPGEncoder( MyTexture , 75.0f );
848 | * NewEncoder.doEncoding();
849 | * byte[] TexData = NewEncoder.GetBytes();
850 | */
851 | #endif
852 |
853 |
--------------------------------------------------------------------------------
/Assets/JPEGEncoder.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 85d2f3d5db3c6df4fa21e4a6bd212968
3 | timeCreated: 1534926757
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/Assets/StreamingAssets.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3863f1e23e99fb74b9db29a22809d118
3 | folderAsset: yes
4 | timeCreated: 1534925481
5 | licenseType: Free
6 | DefaultImporter:
7 | externalObjects: {}
8 | userData:
9 | assetBundleName:
10 | assetBundleVariant:
11 |
--------------------------------------------------------------------------------
/Assets/StreamingAssets/log.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/U3DC/Unity_UpLoader/b1097461944cd142d42cee96002f3914166288ee/Assets/StreamingAssets/log.txt
--------------------------------------------------------------------------------
/Assets/StreamingAssets/log.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ef7157620d65b464e919d48721dc393b
3 | timeCreated: 1534925499
4 | licenseType: Free
5 | DefaultImporter:
6 | externalObjects: {}
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Assets/UpLoaderDemo.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.IO;
4 | using System.Runtime.Serialization.Formatters.Binary;
5 |
6 | namespace U3DC.Extents
7 | {
8 | public class UpLoaderDemo : MonoBehaviour
9 | {
10 | private Camera CutFrameCamer;
11 | private Rect _canvas;
12 | private readonly string m_URL = "http://www.u3dc.com/appupload/upload.php";
13 |
14 | private void Awake()
15 | {
16 | CutFrameCamer = Camera.main;
17 | }
18 |
19 | private string GetInfo()
20 | {
21 |
22 | var systemInfo = "\tTitle:Current System Back Info:\nDeviceModel:" + SystemInfo.deviceModel + "\nDeviceName:" + SystemInfo.deviceName + "\nDeviceType:" + SystemInfo.deviceType +
23 | "\nDeviceUniqueIdentifier:" + SystemInfo.deviceUniqueIdentifier + "\nGraphicsDeviceID:" + SystemInfo.graphicsDeviceID +
24 | "\nGraphicsDeviceName:" + SystemInfo.graphicsDeviceName + "\nGraphicsDeviceVendor:" + SystemInfo.graphicsDeviceVendor +
25 | "\nGraphicsDeviceVendorID:" + SystemInfo.graphicsDeviceVendorID + "\nGraphicsDeviceVersion:" + SystemInfo.graphicsDeviceVersion +
26 | "\nGraphicsMemorySize(M):" + SystemInfo.graphicsMemorySize +
27 | "\nGraphicsShaderLevel:" + SystemInfo.graphicsShaderLevel + "\nMaxTextureSize:" + SystemInfo.maxTextureSize +
28 | "\nnpotSupport:" + SystemInfo.npotSupport + "\nOperatingSystem:" + SystemInfo.operatingSystem +
29 | "\nProcessorCount:" + SystemInfo.processorCount + "\nProcessorType:" + SystemInfo.processorType +
30 | "\nsupportedRenderTargetCount:" + SystemInfo.supportedRenderTargetCount + "\nsupports3DTextures:" + SystemInfo.supports3DTextures +
31 | "\nsupportsAccelerometer:" + SystemInfo.supportsAccelerometer + "\nsupportsComputeShaders:" + SystemInfo.supportsComputeShaders +
32 | "\nsupportsGyroscope:" + SystemInfo.supportsGyroscope + "\nsupportsImageEffects:" + SystemInfo.supportsImageEffects +
33 | "\nsupportsInstancing:" + SystemInfo.supportsInstancing + "\nsupportsLocationService:" + SystemInfo.supportsLocationService +
34 | "\nsupportsRenderToCubemap:" + SystemInfo.supportsRenderToCubemap +
35 | "\nsupportsShadows:" + SystemInfo.supportsShadows + "\nsupportsSparseTextures:" + SystemInfo.supportsSparseTextures +
36 | "\nsupportsVibration:" + SystemInfo.supportsVibration + "\nSystemMemorySize:" + SystemInfo.systemMemorySize;
37 | return systemInfo;
38 |
39 | }
40 |
41 |
42 |
43 | public void UpLoadLogInfo()
44 | {
45 | SaveStringToBinary(GetInfo());
46 | StartCoroutine(UploadLogFile(m_URL));
47 | }
48 |
49 | public void UpLoadSreenShot()
50 | {
51 | _canvas.Set(0, 0, Screen.width, Screen.height); //设置画布大小等于当前屏幕的宽和高。
52 | CaptureScreen(CutFrameCamer, _canvas);
53 |
54 | }
55 |
56 |
57 | ///
58 | /// 截图上传到服务器
59 | ///
60 | ///
61 | ///
62 | ///
63 | public void CaptureScreen(Camera c, Rect r)
64 | {
65 | //捕抓摄像机图像并转换成字符数组
66 | var rt = new RenderTexture((int)r.width, (int)r.height, 0);
67 | c.targetTexture = rt;
68 | c.Render();
69 |
70 | RenderTexture.active = rt;
71 | var screenShot = new Texture2D((int)r.width, (int)r.height, TextureFormat.RGB24, false);
72 | screenShot.ReadPixels(r, 0, 0);
73 | screenShot.Apply();
74 |
75 | c.targetTexture = null;
76 | RenderTexture.active = null;
77 | GameObject.Destroy(rt);
78 |
79 | StartCoroutine(UploadTexture(screenShot, m_URL));
80 |
81 | }
82 |
83 | private IEnumerator UploadTexture(Texture2D screenShot, string Url)
84 | {
85 | //var encoder = new JPGEncoder(screenShot, 20);//质量1~100
86 | //encoder.doEncoding();
87 | //while (!encoder.isDone)
88 | // yield return null;
89 | //var bytes = encoder.GetBytes();
90 |
91 | var bytes = screenShot.EncodeToJPG();
92 | var form = new WWWForm();
93 | // form.AddBinaryData("file", bytes); //把图片流上传
94 | form.AddBinaryData("file", bytes, "screenShot.jpg", "image/jpeg");
95 | var www = new WWW(Url, form);
96 | yield return www;
97 | if (www.error == null)
98 | Debug.Log("upload done :" + www.text);
99 | else
100 | Debug.Log("Error during upload: " + www.error);
101 | StartCoroutine(PostData(www)); //启动子线程
102 | Destroy(screenShot); //销毁
103 | }
104 |
105 | ///
106 | /// 上传log到服务器
107 | ///
108 | ///
109 | private void SaveStringToBinary(string str)
110 | {
111 | //序列化过程(将Save对象转换为字节流)
112 | //创建Save对象并保存当前游戏状态
113 | //创建一个二进制格式化程序
114 | var bf = new BinaryFormatter();
115 | //创建一个文件流
116 | var fileStream = File.Create(Application.streamingAssetsPath + "/log.txt");
117 | //用二进制格式化程序的序列化方法来序列化Save对象,参数:创建的文件流和需要序列化的对象
118 | bf.Serialize(fileStream, str);
119 | //关闭流
120 | fileStream.Close();
121 |
122 | //如果文件存在,则显示保存成功
123 | if (File.Exists(Application.streamingAssetsPath + "/log.txt"))
124 | {
125 | Debug.Log("保存成功~");
126 | }
127 | }
128 |
129 | IEnumerator UploadLogFile(string url)
130 | {
131 | var localFile = new WWW(Application.streamingAssetsPath + "/log.txt");
132 | yield return localFile;
133 | if (localFile.error == null)
134 | Debug.Log("Loaded file successfully");
135 | else
136 | {
137 | Debug.Log("Open file error: " + localFile.error);
138 | yield break; // stop the coroutine here
139 | }
140 | var postForm = new WWWForm();
141 | // version 1 上传一个二进制文件 .dat
142 | postForm.AddBinaryData("file", localFile.bytes);
143 | // version 2
144 | //上传一个原格式的文件 源文件后缀
145 | //postForm.AddBinaryData("file", localFile.bytes,"log.txt", "text/plain");
146 | var upload = new WWW(url, postForm);
147 | yield return upload;
148 | if (upload.error == null)
149 | Debug.Log("upload done :" + upload.text);
150 | else
151 | Debug.Log("Error during upload: " + upload.error);
152 | }
153 |
154 | IEnumerator PostData(WWW www)
155 | {
156 | yield return www;
157 | Debug.Log(www.text); //输出服务器返回结果。
158 | }
159 |
160 |
161 | }
162 | }
--------------------------------------------------------------------------------
/Assets/UpLoaderDemo.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e086337a30a074596b9c2444a10fc048
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Assets/demo.unity:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/U3DC/Unity_UpLoader/b1097461944cd142d42cee96002f3914166288ee/Assets/demo.unity
--------------------------------------------------------------------------------
/Assets/demo.unity.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 38fada7f556a1314ebf5a50a77f49278
3 | timeCreated: 1534925859
4 | licenseType: Free
5 | DefaultImporter:
6 | externalObjects: {}
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/PHP/upload.php:
--------------------------------------------------------------------------------
1 | 0)
18 | {
19 | echo "错误:: " . $_FILES["file"]["error"] . "
";
20 | }
21 | else
22 | {
23 | echo "上传文件名: " . $_FILES["file"]["name"] . "
";
24 | echo "文件类型: " . $_FILES["file"]["type"] . "
";
25 | echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB
";
26 | echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"] . "
";
27 |
28 |
29 | //移动上传文件到uploads目录
30 | if(file_exists($newname ))
31 | {echo "
您上传文件的已经在本地保存过";}
32 | else
33 | {
34 | //文件以时间戳 重命名
35 | date_default_timezone_set('PRC');//中国时区
36 | $D=date("YmdHis");//时间戳
37 | $filetype=substr(strrchr($_FILES['file']['name'],"."),1);//获取文件后缀名
38 | $newname=$D.".".$filetype; //文件新名字
39 | //echo "
新文件名:".$newname;
40 |
41 | move_uploaded_file($_FILES['file']['tmp_name'], "upload/".$newname);//移动文件到指定文件夹uploads;
42 | echo "
上传文件本地保存路径:"."./upload/".$newname;
43 |
44 | }
45 |
46 | /* // 判断当期目录下的 upload 目录是否存在该文件
47 | // 如果没有 upload 目录,你需要创建它,upload 目录权限为 777
48 | if (file_exists("upload/" . $_FILES["file"]["name"]))
49 | {
50 | echo $_FILES["file"]["name"] . " 文件已经存在。 ";
51 | }
52 | else
53 | {
54 | // 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
55 | move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
56 | echo "文件存储在: " . "upload/" . $_FILES["file"]["name"];
57 | } */
58 | }
59 | /* }
60 | else
61 | {
62 | echo "非法的文件格式";
63 | } */
64 | ?>
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unity_UpLoader
2 |
3 |
4 | **En:**
5 |
6 | A solution for UpLoad data(TXT,ScreenShot) to server,Contact with PHP.
7 |
8 |
9 | How to use it:
10 |
11 | 1. put the 'upload.php' page on your webside or server.
12 | 2. change the demo url for your url.
13 | 3. SaveStringToBinary(string str),use this funtion for convert string to a file.
14 | 4. CaptureScreen(),use this funtion for take a screenShot.
15 | 5. UploadLogFile(),use this funtion for upload file.
16 | 6. UploadTexture(),use this funtion for upload screenShot.
17 | 7. JPGEncoder is a class for compress pic
18 | 8. enjoy it!
19 |
20 | **CH:**
21 |
22 |
23 | 数据上传解决方案,比如上传log信息,上传屏幕截图,PHP后端交互存储文件
24 |
25 | 如何使用:
26 |
27 | 1. 上传upload.php页面到服务端。
28 | 2. 在demo中更改url即可直接体验到上传效果。
29 | 3. 使用SaveStringToBinary函数来将string字符串转为二进制文件。
30 | 4. CaptureScreen函数用来截图。
31 | 5. UploadLogFile用来上传日志。
32 | 6. UploadTexture用来上传贴图。
33 | 7. JPGEncoder是一个用于压缩图片的类
34 | 8. 动手试一下呗~
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------