先上代码:
1 using System.Threading;
2 using UnityEngine;
3 using System.IO;
4 using System.Collections;
5
6 public class TextureUtility
7 {
8 public class ThreadData
9 {
10 public int start;
11 public int end;
12 public ThreadData (int s, int e) {
13 start = s;
14 end = e;
15 }
16 }
17
18 private static Color[] texColors;
19 private static Color[] newColors;
20 private static int w;
21 private static float ratioX;
22 private static float ratioY;
23 private static int w2;
24 private static int finishCount;
25 private static Mutex mutex;
26
27 public static void ScalePoint (Texture2D tex, int newWidth, int newHeight)
28 {
29 ThreadedScale (tex, newWidth, newHeight, false);
30 }
31
32 public static void ScaleBilinear (Texture2D tex, int newWidth, int newHeight)
33 {
34 ThreadedScale (tex, newWidth, newHeight, true);
35 }
36
37 private static void ThreadedScale (Texture2D tex, int newWidth, int newHeight, bool useBilinear)
38 {
39 texColors = tex.GetPixels();
40 newColors = new Color[newWidth * newHeight];
41 if (useBilinear)
42 {
43 ratioX = 1.0f / ((float)newWidth / (tex.width-1));
44 ratioY = 1.0f / ((float)newHeight / (tex.height-1));
45 }
46 else {
47 ratioX = ((float)tex.width) / newWidth;
48 ratioY = ((float)tex.height) / newHeight;
49 }
50 w = tex.width;
51 w2 = newWidth;
52 var cores = Mathf.Min(SystemInfo.processorCount, newHeight);
53 var slice = newHeight/cores;
54
55 finishCount = 0;
56 if (mutex == null) {
57 mutex = new Mutex(false);
58 }
59 if (cores > 1)
60 {
61 int i = 0;
62 ThreadData threadData;
63 for (i = 0; i < cores-1; i++) {
64 threadData = new ThreadData(slice * i, slice * (i + 1));
65 ParameterizedThreadStart ts = useBilinear ? new ParameterizedThreadStart(BilinearScale) : new ParameterizedThreadStart(PointScale);
66 Thread thread = new Thread(ts);
67 thread.Start(threadData);
68 }
69 threadData = new ThreadData(slice*i, newHeight);
70 if (useBilinear)
71 {
72 BilinearScale(threadData);
73 }
74 else
75 {
76 PointScale(threadData);
77 }
78 while (finishCount < cores)
79 {
80 Thread.Sleep(1);
81 }
82 }
83 else
84 {
85 ThreadData threadData = new ThreadData(0, newHeight);
86 if (useBilinear)
87 {
88 BilinearScale(threadData);
89 }
90 else
91 {
92 PointScale(threadData);
93 }
94 }
95
96 tex.Resize(newWidth, newHeight);
97 tex.SetPixels(newColors);
98 tex.Apply();
99 }
100
101 public static void BilinearScale (System.Object obj)
102 {
103 ThreadData threadData = (ThreadData) obj;
104 for (var y = threadData.start; y < threadData.end; y++)
105 {
106 int yFloor = (int)Mathf.Floor(y * ratioY);
107 var y1 = yFloor * w;
108 var y2 = (yFloor+1) * w;
109 var yw = y * w2;
110
111 for (var x = 0; x < w2; x++) {
112 int xFloor = (int)Mathf.Floor(x * ratioX);
113 var xLerp = x * ratioX-xFloor;
114 newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor+1], xLerp),
115 ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor+1], xLerp),
116 y*ratioY-yFloor);
117 }
118 }
119
120 mutex.WaitOne();
121 finishCount++;
122 mutex.ReleaseMutex();
123 }
124
125 public static void PointScale (System.Object obj)
126 {
127 ThreadData threadData = (ThreadData) obj;
128 for (var y = threadData.start; y < threadData.end; y++)
129 {
130 var thisY = (int)(ratioY * y) * w;
131 var yw = y * w2;
132 for (var x = 0; x < w2; x++) {
133 newColors[yw + x] = texColors[(int)(thisY + ratioX*x)];
134 }
135 }
136
137 mutex.WaitOne();
138 finishCount++;
139 mutex.ReleaseMutex();
140 }
141
142 private static Color ColorLerpUnclamped (Color c1, Color c2, float value)
143 {
144 return new Color (c1.r + (c2.r - c1.r)*value,
145 c1.g + (c2.g - c1.g)*value,
146 c1.b + (c2.b - c1.b)*value,
147 c1.a + (c2.a - c1.a)*value);
148 }
149
150 public static Texture2D LoadTexture(string filePath) {
151 Texture2D tex = null;
152 byte[] fileData;
153
154 if (File.Exists(filePath)) {
155 fileData = File.ReadAllBytes(filePath);
156 tex = new Texture2D(2, 2,TextureFormat.ARGB32,false);
157 tex.LoadImage(fileData);
158 }
159 return tex;
160 }
161
162 // Save ScreenShot
163
164 public static void SaveScreenShotAsync(string path, Vector2 size)
165 {
166 SWMain.sharedSWMain.StartCoroutine(TextureUtility.SaveScreenShot(path, size));
167 }
168
169 public static void SaveScreenShotAsync(string path, Rect rect, Vector2 size)
170 {
171 SWMain.sharedSWMain.StartCoroutine(TextureUtility.SaveScreenShot(path, rect, size));
172 }
173
174 public static IEnumerator SaveScreenShot(string path, Vector2 size)
175 {
176 Rect rect = new Rect (0, 0, Screen.width, Screen.height);
177 yield return SWMain.sharedSWMain.StartCoroutine(TextureUtility.SaveScreenShot(path,rect, size));
178 }
179
180 public static IEnumerator SaveScreenShot(string path, Rect rect, Vector2 size = default(Vector2))
181 {
182 // We should only read the screen bufferafter rendering is complete
183 yield return new WaitForEndOfFrame();
184 // 要保存图片的大小
185 Texture2D tex = new Texture2D ((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
186 // 截取的区域
187 tex.ReadPixels(rect, 0, 0);
188 tex.Apply();
189 // 把图片数据转换为byte数组
190 if (size != default(Vector2))
191 {
192 ScaleBilinear(tex, (int)size.x, (int)size.y);
193 }
194
195 byte[] buffer = tex.EncodeToJPG (100);
196 Object.Destroy(tex);
197 // 然后保存为图片
198 File.WriteAllBytes(path, buffer);
199 }
200
201 public static Texture2D Copy(Texture2D tex)
202 {
203 return new Texture2D(tex.width, tex.height, tex.format, false);
204 }
205
206 /// <summary>
207 /// Applies sepia effect to the texture.
208 /// </summary>
209 /// <param name="tex"> Texture to process.</param>
210 public static Texture2D SetSepia(Texture2D tex)
211 {
212 Texture2D t = Copy(tex);
213 Color[] colors = tex.GetPixels();
214
215 for (int i = 0; i < colors.Length; i++)
216 {
217 float alpha = colors[i].a;
218 float grayScale = ((colors[i].r * .299f) + (colors[i].g * .587f) + (colors[i].b * .114f));
219 Color c = new Color(grayScale, grayScale, grayScale);
220 colors[i] = new Color(c.r * 1, c.g * 0.95f, c.b * 0.82f, alpha);
221 }
222 t.SetPixels(colors);
223 t.Apply();
224 return t;
225 }
226
227 /// <summary>
228 /// Applies grayscale effect to the texture and changes colors to grayscale.
229 /// </summary>
230 /// <param name="tex"> Texture to process.</param>
231 public static Texture2D SetGrayscale(Texture2D tex)
232 {
233 Texture2D t = Copy(tex);
234
235 Color[] colors = tex.GetPixels();
236 for (int i = 0; i < colors.Length; i++)
237 {
238 float val = (colors [i].r + colors [i].g + colors [i].b) / 3;
239 colors [i] = new Color(val, val, val);
240 }
241 t.SetPixels(colors);
242 t.Apply();
243 return t;
244 }
245
246 /// <summary>
247 /// Pixelates the texture.
248 /// </summary>
249 /// <param name="tex"> Texture to process.</param>
250 /// <param name="size"> Size of the pixel.</param>
251 public static Texture2D SetPixelate(Texture2D tex, int size)
252 {
253 Texture2D t = Copy(tex);
254 Rect rectangle = new Rect(0, 0, tex.width, tex.height);
255 for (int xx = (int)rectangle.x; xx < rectangle.x + rectangle.width && xx < tex.width; xx += size)
256 {
257 for (int yy = (int)rectangle.y; yy < rectangle.y + rectangle.height && yy < tex.height; yy += size)
258 {
259 int offsetX = size / 2;
260 int offsetY = size / 2;
261 while (xx + offsetX >= tex.width) offsetX--;
262 while (yy + offsetY >= tex.height) offsetY--;
263 Color pixel = tex.GetPixel(xx + offsetX, yy + offsetY);
264 for (int x = xx; x < xx + size && x < tex.width; x++)
265 for (int y = yy; y < yy + size && y < tex.height; y++)
266 t.SetPixel(x, y, pixel);
267 }
268 }
269
270 t.Apply();
271 return t;
272 }
273
274 /// <summary>
275 /// Inverts colors of the texture.
276 /// </summary>
277 /// <param name="tex"> Texture to process.</param>
278 public static Texture2D SetNegative(Texture2D tex)
279 {
280 Texture2D t = Copy(tex);
281 Color[] colors = tex.GetPixels();
282 Color pixel;
283
284 for (int i = 0; i < colors.Length; i++)
285 {
286 pixel = colors[i];
287 colors[i] = new Color(1 - pixel.r, 1 - pixel.g, 1 - pixel.b);
288 }
289 t.SetPixels(colors);
290 t.Apply();
291 return t;
292 }
293
294 /// <summary>
295 /// Sets the foggy effect.雾化效果
296 /// </summary>
297 /// <returns>texture processed.</returns>
298 /// <param name="tex">texture to process.</param>
299 public static Texture2D SetFoggy(Texture2D tex)
300 {
301 Texture2D t = Copy(tex);
302 Color pixel;
303
304 for (int x = 1; x < tex.width - 1; x++)
305 for (int y = 1; y < tex.height - 1; y++)
306 {
307 int k = UnityEngine.Random.Range(0, 123456);
308 //像素块大小
309 int dx = x + k % 19;
310 int dy = y + k % 19;
311 if (dx >= tex.width)
312 dx = tex.width - 1;
313 if (dy >= tex.height)
314 dy = tex.height - 1;
315 pixel = tex.GetPixel(dx, dy);
316 t.SetPixel(x, y, pixel);
317 }
318
319 t.Apply();
320
321 return t;
322 }
323
324 /// <summary>
325 /// Sets the soft effect.柔化效果
326 /// </summary>
327 /// <returns>texture processed.</returns>
328 /// <param name="tex">texture to process.</param>
329 public static Texture2D SetSoft(Texture2D tex)
330 {
331 Texture2D t = Copy(tex);
332 int[] Gauss = { 1, 2, 1, 2, 4, 2, 1, 2, 1 };
333 for (int x = 1; x < tex.width - 1; x++)
334 for (int y = 1; y < tex.height - 1; y++)
335 {
336 float r = 0, g = 0, b = 0;
337 int Index = 0;
338 for (int col = -1; col <= 1; col++)
339 for (int row = -1; row <= 1; row++)
340 {
341 Color pixel = tex.GetPixel(x + row, y + col);
342 r += pixel.r * Gauss[Index];
343 g += pixel.g * Gauss[Index];
344 b += pixel.b * Gauss[Index];
345 Index++;
346 }
347 r /= 16;
348 g /= 16;
349 b /= 16;
350 //处理颜色值溢出
351 r = r > 1 ? 1 : r;
352 r = r < 0 ? 0 : r;
353 g = g > 1 ? 1 : g;
354 g = g < 0 ? 0 : g;
355 b = b > 1 ? 1 : b;
356 b = b < 0 ? 0 : b;
357 t.SetPixel(x - 1, y - 1, new Color(r, g, b));
358 }
359
360 t.Apply();
361
362 return t;
363 }
364
365 /// <summary>
366 /// Sets the sharp.锐化效果
367 /// </summary>
368 /// <returns>The sharp.</returns>
369 /// <param name="tex">Tex.</param>
370 public static Texture2D SetSharp(Texture2D tex)
371 {
372 Texture2D t = Copy(tex);
373 Color pixel;
374 //拉普拉斯模板
375 int[] Laplacian ={ -1, -1, -1, -1, 9, -1, -1, -1, -1 };
376 for (int x = 1; x < tex.width - 1; x++)
377 for (int y = 1; y < tex.height - 1; y++)
378 {
379 float r = 0, g = 0, b = 0;
380 int index = 0;
381 for (int col = -1; col <= 1; col++)
382 for (int row = -1; row <= 1; row++)
383 {
384 pixel = tex.GetPixel(x + row, y + col); r += pixel.r * Laplacian[index];
385 g += pixel.g * Laplacian[index];
386 b += pixel.b * Laplacian[index];
387 index++;
388 }
389 //处理颜色值溢出
390 r = r > 1 ? 1 : r;
391 r = r < 0 ? 0 : r;
392 g = g > 1 ? 1 : g;
393 g = g < 0 ? 0 : g;
394 b = b > 1 ? 1 : b;
395 b = b < 0 ? 0 : b;
396 t.SetPixel(x - 1, y - 1, new Color(r, g, b));
397 }
398
399 t.Apply();
400 return t;
401 }
402
403 /// <summary>
404 /// Sets the relief.浮雕效果
405 /// </summary>
406 /// <returns>The relief.</returns>
407 /// <param name="tex">Tex.</param>
408 public static Texture2D SetRelief(Texture2D tex)
409 {
410 Texture2D t = Copy(tex);
411
412 for (int x = 0; x < tex.width - 1; x++)
413 {
414 for (int y = 0; y < tex.height - 1; y++)
415 {
416 float r = 0, g = 0, b = 0;
417 Color pixel1 = tex.GetPixel(x, y);
418 Color pixel2 = tex.GetPixel(x + 1, y + 1);
419 r = Mathf.Abs(pixel1.r - pixel2.r + 0.5f);
420 g = Mathf.Abs(pixel1.g - pixel2.g + 0.5f);
421 b = Mathf.Abs(pixel1.b - pixel2.b + 0.5f);
422 if (r > 1)
423 r = 1;
424 if (r < 0)
425 r = 0;
426 if (g > 1)
427 g = 1;
428 if (g < 0)
429 g = 0;
430 if (b > 1)
431 b = 1;
432 if (b < 0)
433 b = 0;
434 t.SetPixel(x, y, new Color(r, g, b));
435 }
436 }
437
438 t.Apply();
439 return t;
440 }
441
442 }
如何调用:
1. 压缩图片:
TextureUtility.ScalePoint(Texture2D tex, int newWidth, int newHeight),第一个参数是要传入的Texture2D, 第二个参数是新的图片的宽度,第三个参数则是新的图片的高度。也可以调用TextureUtility.ScaleBilinear(Texture2D tex, int newWidth, int newHeight)。
2. 截屏:
yield return StartCoroutine(TextureUtility.SaveScreenShot(string path, Vector2 size, Vector2 size = default(Vector2)))
或者调用异步方法TextureUtility.SaveScreenShotAsync(string path, Rect rect, Vector2 size)
3. 图片滤镜:
如灰阶滤镜:TextureUtility.SetGrayscale(Texture2D tex);
底片滤镜:TextureUtility.SetNegative(Texture2D tex)等。