Jypeli 10
The simple game programming library
Image.cs
Siirry tämän tiedoston dokumentaatioon.
1using Microsoft.Xna.Framework.Graphics;
2using Microsoft.Xna.Framework;
3using System;
4using System.IO;
5using System.ComponentModel;
6using System.Diagnostics;
7using System.Net;
8
9using XnaRectangle = Microsoft.Xna.Framework.Rectangle;
10using XnaV2 = Microsoft.Xna.Framework.Vector2;
11using XnaColor = Microsoft.Xna.Framework.Color;
13using FontStashSharp;
14
15#if WINDOWS_STOREAPP
17using XnaColorConverter = Jypeli.ListHelpers.Converter<Microsoft.Xna.Framework.Color, Microsoft.Xna.Framework.Color>;
18#else
20using XnaColorConverter = System.Converter<Microsoft.Xna.Framework.Color, Microsoft.Xna.Framework.Color>;
21#endif
22
23
24namespace Jypeli
25{
29 public class Image
30 {
31
32 private static int MONOGETDATAMUL = 1;
33 private static int MONOGETDATAINC = 0;
34 // private static const int MONOGETDATAMUL = 1;
35 // private static const int MONOGETDATAINC = 0; // tavallinen
36
39
40 private string assetName;
41 private Texture2D xnaTexture;
42
43 private event Action InitDimensions;
44 private event Action InitTexture;
45
46 int _width = -1;
47 int _height = -1;
48
49 private static string[] imageExtensions = { ".png", ".jpg", ".xnb"};
50
55 public static void SetLineCorrection(int n)
56 {
57 if ( n == 1 )
58 {
61 return;
62 }
63 if (n == 0)
64 {
67 return;
68 }
69 }
70
71 internal Texture2D XNATexture
72 {
73 get { DoInitTexture(); return xnaTexture; }
74 }
75
82 public Color this[int row, int col]
83 {
84 get
85 {
87
88 Color[] buffer = new Color[1];
89 XnaRectangle rect = new XnaRectangle( col, row, 1, 1 );
90 xnaTexture.GetData<Color>( 0, rect, buffer, 0, 1 );
91 return buffer[0];
92 }
93 set
94 {
97
98 if ( row < 0 || row >= xnaTexture.Height ) throw new IndexOutOfRangeException( "row" );
99 if ( col < 0 || col >= XNATexture.Width ) throw new IndexOutOfRangeException( "col" );
100
101 Color[] buffer = new Color[1] { value };
102 XnaRectangle rect = new XnaRectangle( col, row, 1, 1 );
103
104 xnaTexture.SetData<Color>( 0, rect, buffer, 0, 1 );
106 }
107 }
108
109
118 public Color[,] GetData( int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
119 {
120 int ny = Height;
121 if ( h < ny ) ny = h;
122 if ( Height < ny + oy ) ny = Height - oy;
123 int nx = Width;
124 if ( w < nx ) nx = w;
125 if ( Width < nx + ox ) nx = Width - ox;
126 if ( nx <= 0 || ny <= 0 ) return new Color[0, 0];
127
129 Color[,] bmp = new Color[ny, nx];
130
131 XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
132 Color[] buffer = new Color[ny * nx * MONOGETDATAMUL];
133 xnaTexture.GetData<Color>( 0, rect, buffer, 0, buffer.Length );
134 int i = 0;
135 for (int iy = 0; iy < ny; iy++)
136 {
137 for (int ix = 0; ix < nx; ix++)
138 bmp[iy, ix] = buffer[i++];
139 i += nx * MONOGETDATAINC;
140 }
141 return bmp;
142 }
143
144
154 public void SetData( Color[,] bmp, int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
155 {
158 int ny = bmp.GetLength( 0 );
159 int nx = bmp.GetLength( 1 );
160 if ( ny > Height ) ny = Height;
161 if ( nx > Width ) nx = Height;
162 if ( ny > h ) ny = h;
163 if ( nx > w ) nx = w;
164 if ( Height < ny + oy ) ny = Height - oy;
165 if ( Width < nx + ox ) nx = Width - ox;
166 if ( nx <= 0 || ny <= 0 ) return;
167
168 XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
169 Color[] buffer = new Color[ny * nx];
170 int i = 0;
171 for ( int iy = 0; iy < ny; iy++ )
172 for ( int ix = 0; ix < nx; ix++ )
173 buffer[i++] = bmp[iy, ix];
174
175 xnaTexture.SetData<Color>( 0, rect, buffer, 0, buffer.Length );
177 }
178
187 public void SetData(byte[] byteArr, int height, int width)
188 {
189 Color[,] newColor = new Color[height, width];
190
191 for (int i = 0; i < height; i++)
192 {
193 for (int j = 0; j < width; j++)
194 {
195 int r = byteArr[4 * (i * width + j) + 0];
196 int g = byteArr[4 * (i * width + j) + 1];
197 int b = byteArr[4 * (i * width + j) + 2];
198 int a = byteArr[4 * (i * width + j) + 3];
199 newColor[i, j] = new Color(r, g, b, a);
200 }
201 }
202 this.SetData(newColor);
203 }
204
211 public void SetData(byte[] byteArr)
212 {
213 SetData(byteArr, this.Height, this.Width);
214 }
215
221 public byte[] GetByteArray()
222 {
224 byte[] buffer = new byte[4 * Width * Height];
225 xnaTexture.GetData<byte>( buffer );
226 return buffer;
227 }
228
237 public uint[,] GetDataUInt( int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
238 {
239 int ny = Height;
240 if ( h < ny ) ny = h;
241 if ( Height < ny + oy ) ny = Height - oy;
242 int nx = Width;
243 if ( w < nx ) nx = w;
244 if ( Width < nx + ox ) nx = Width - ox;
245 if ( nx <= 0 || ny <= 0 ) return new uint[0, 0];
246
248 uint[,] bmp = new uint[ny, nx];
249
250 XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
251 Color[] buffer = new Color[ny * nx * MONOGETDATAMUL];
252 xnaTexture.GetData<Color>( 0, rect, buffer, 0, buffer.Length );
253 int i = 0;
254 for (int iy = 0; iy < ny; iy++)
255 {
256 for (int ix = 0; ix < nx; ix++)
257 bmp[iy, ix] = buffer[i++].ToUInt();
258 i += nx * MONOGETDATAINC;
259 }
260 return bmp;
261 }
262
263
272 public uint[][] GetDataUIntAA( int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
273 {
274 int ny = Height;
275 if ( h < ny ) ny = h;
276 if ( Height < ny + oy ) ny = Height - oy;
277 int nx = Width;
278 if ( w < nx ) nx = w;
279 if ( Width < nx + ox ) nx = Width - ox;
280 if ( nx <= 0 || ny <= 0 ) return new uint[0][];
281
283 uint[][] bmp = new uint[ny][];
284
285 XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
286 Color[] buffer = new Color[ny * nx * MONOGETDATAMUL];
287 xnaTexture.GetData<Color>( 0, rect, buffer, 0, buffer.Length );
288 int i = 0;
289 for ( int iy = 0; iy < ny; iy++ )
290 {
291 uint[] row = new uint[nx];
292 bmp[iy] = row;
293 for ( int ix = 0; ix < nx; ix++ )
294 row[ix] = buffer[i++].ToUInt();
295 i += nx * MONOGETDATAINC;
296 }
297 return bmp;
298 }
299
300
309 public void SetData( uint[,] bmp, int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
310 {
313 int ny = bmp.GetLength( 0 );
314 int nx = bmp.GetLength( 1 );
315 if ( ny > Height ) ny = Height;
316 if ( nx > Width ) nx = Width;
317 if ( ny > h ) ny = h;
318 if ( nx > w ) nx = w;
319 if ( Height < ny + oy ) ny = Height - oy;
320 if ( Width < nx + ox ) nx = Width - ox;
321
322 if ( nx <= 0 || ny <= 0 ) return;
323
324 XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
325 Color[] buffer = new Color[ny * nx];
326 int i = 0;
327 for ( int iy = 0; iy < ny; iy++ )
328 for ( int ix = 0; ix < nx; ix++ )
329 buffer[i++] = Jypeli.Color.UIntToColor( bmp[iy, ix] );
330 // foreach (int c in bmp) buffer[i++] = Jypeli.Color.IntToColor(c);
331
332 xnaTexture.SetData<Color>( 0, rect, buffer, 0, buffer.Length );
334 }
335
336
345 public void SetData( uint[][] bmp, int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
346 {
349 int ny = bmp.Length;
350 int nx = bmp[0].Length;
351 if ( ny > Height ) ny = Height;
352 if ( nx > Width ) nx = Width;
353 if ( ny > h ) ny = h;
354 if ( nx > w ) nx = w;
355 if ( nx <= 0 || ny <= 0 ) return;
356
357 XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
358 Color[] buffer = new Color[ny * nx];
359 int i = 0;
360 for ( int iy = 0; iy < ny; iy++ )
361 for ( int ix = 0; ix < nx; ix++ )
362 buffer[i++] = Jypeli.Color.UIntToColor( bmp[iy][ix] );
363 // foreach (int c in bmp) buffer[i++] = Jypeli.Color.IntToColor(c);
364
365 xnaTexture.SetData<Color>( 0, rect, buffer, 0, buffer.Length );
367 }
368
369
373 public int Width
374 {
375 get { DoInitDimensions(); return _width; }
376 }
377
381 public int Height
382 {
383 get { DoInitDimensions(); return _height; }
384 }
385
389 public string Name
390 {
391 get { DoInitTexture(); return xnaTexture.Name; }
392 }
393
394 internal Image( int width, int height )
395 {
396 AssertDimensions( width, height );
397 this._width = width;
398 this._height = height;
399 this.InitTexture += CreateNewTexture;
400 }
401
402 internal Image( string assetName )
403 {
404 this.assetName = assetName;
405 this.InitDimensions += LoadContentTexture;
406 }
407
412 [EditorBrowsable( EditorBrowsableState.Never )]
413 public Image( Microsoft.Xna.Framework.Graphics.Texture2D texture )
414 {
415 AssertDimensions( texture.Width, texture.Height );
416 this.xnaTexture = texture;
417 this._width = texture.Width;
418 this._height = texture.Height;
419 }
420
427 public Image( int width, int height, Color backColor )
428 {
429 AssertDimensions( width, height );
430 assetName = null;
431 this._width = width;
432 this._height = height;
433 this.InitTexture += CreateNewTexture;
434 this.InitTexture += delegate { this.Fill( backColor ); };
435 }
436
443 public Image( double width, double height, Color backColor )
444 : this( (int)Math.Round( width ), (int)Math.Round( height ), backColor )
445 {
446 }
447
448 private void AssertDimensions(int width, int height)
449 {
450 if ( width < 1 || height < 1 )
451 throw new ArgumentException( String.Format( "Image dimensions must be at least 1 x 1! (given: {0} x {1}", width, height ) );
452 }
453
454 private void DoInitDimensions()
455 {
456 if ( _width > 0 && _height > 0 )
457 return;
458
459 if ( InitDimensions != null )
461 else
462 throw new InvalidOperationException( "Cannot initialize dimensions for image!" );
463 }
464
465 private void DoInitTexture()
466 {
468 AssertDimensions( this.Width, this.Height );
469
470 if ( xnaTexture != null )
471 return;
472
473 if ( InitTexture != null )
474 InitTexture();
475 else
476 throw new InvalidOperationException( "Cannot initialize texture for image!" );
477 }
478
479 private void LoadContentTexture()
480 {
481 // Some duct tape around the fact that in XNA,
482 // content can not be loaded before LoadContent().
483 Debug.Assert( assetName != null );
485 _width = xnaTexture.Width;
486 _height = xnaTexture.Height;
487
488 }
489 // TODO: Why is this path not used???
490 private Texture2D LoadFile(string path)
491 {
493 FileStream fileStream = new FileStream(assetName, FileMode.Open);
494 Texture2D texture = Texture2D.FromStream(Game.GraphicsDevice, fileStream);
495 fileStream.Dispose();
496
497 return texture;
498 }
499
500 private void CreateNewTexture()
501 {
502 this.xnaTexture = new Texture2D( Game.GraphicsDevice, Width, Height );
503 }
504
509 public Image Clone()
510 {
511 Image copy;
512
513 if ( assetName != null )
514 {
515 copy = new Image( assetName );
516 }
517 else
518 {
519 copy = new Image( this.Width, this.Height );
520 copy.InitTexture += delegate { CopyData( copy, this ); };
521 }
522
523 return copy;
524 }
525
526 private static void CopyData( Image dest, Image src )
527 {
528 src.DoInitTexture();
529
530 int w = src.Width;
531 int h = src.Height;
532 XnaRectangle rect = new XnaRectangle( 0, 0, w, 1 );
533 Color[] scanline = new Color[w];
534
535 for ( rect.Y = 0; rect.Y < h; rect.Y++ )
536 {
537 src.xnaTexture.GetData<Color>( 0, rect, scanline, 0, w );
538 dest.xnaTexture.SetData<Color>( 0, rect, scanline, 0, w );
539 }
540 }
541
542 private static void CopyData( Texture2D dest, Texture2D src )
543 {
544 int w = src.Width;
545 int h = src.Height;
546 XnaRectangle rect = new XnaRectangle( 0, 0, w, 1 );
547 Color[] scanline = new Color[w];
548
549 for ( rect.Y = 0; rect.Y < h; rect.Y++ )
550 {
551 src.GetData<Color>( 0, rect, scanline, 0, w );
552 dest.SetData<Color>( 0, rect, scanline, 0, w );
553 }
554 }
555
556 private static void CopyData( Image dest, Image src, XnaRectangle destRect, XnaRectangle srcRect )
557 {
558 src.DoInitTexture();
559
560 int w = srcRect.Width;
561 int h = srcRect.Height;
562 XnaRectangle srcScan = new XnaRectangle( srcRect.X, srcRect.Y, w, 1 );
563 XnaRectangle destScan = new XnaRectangle( destRect.X, destRect.Y, w, 1 );
564 Color[] scanline = new Color[w];
565
566 for ( int i = 0; i < h; i++ )
567 {
568 src.xnaTexture.GetData<Color>( 0, srcScan, scanline, 0, w );
569 dest.xnaTexture.SetData<Color>( 0, destScan, scanline, 0, w );
570 srcScan.Y += MONOGETDATAINC;
571 destScan.Y += MONOGETDATAINC;
572 }
573 }
574
579 public void ApplyPixelOperation( ColorConverter operation )
580 {
581 XnaColorConverter newOp = delegate( XnaColor c )
582 {
583 return operation( new Color( c ) ).AsXnaColor();
584 };
585
586 ApplyPixelOperation( newOp );
587 }
588
593 internal void ApplyPixelOperation( XnaColorConverter operation )
594 {
597
598 XnaRectangle scanRect = new XnaRectangle( 0, 0, xnaTexture.Width, 1 );
599 XnaColor[] scanline = new XnaColor[xnaTexture.Width];
600
601 for ( scanRect.Y = 0; scanRect.Y < xnaTexture.Height; scanRect.Y++ )
602 {
603 xnaTexture.GetData<XnaColor>( 0, scanRect, scanline, 0, xnaTexture.Width );
604
605 for ( int j = 0; j < xnaTexture.Width; j++ )
606 {
607 scanline[j] = operation( scanline[j] );
608 }
609
610 xnaTexture.SetData<XnaColor>( 0, scanRect, scanline, 0, xnaTexture.Width );
611 }
612
614 }
615
621 private void InvalidateAsset()
622 {
623 if ( assetName == null )
624 return;
625
626 Texture2D oldTex = xnaTexture;
628 CopyData( xnaTexture, oldTex );
629 assetName = null;
630 }
631
632 private void UpdateTexture()
633 {
635 }
636
637 private void DoUpdateTexture()
638 {
639 if ( parentImage != null )
640 {
641 XnaRectangle srcRect = new XnaRectangle( 0, 0, Width, Height );
642 CopyData( parentImage, this, parentRectangle, srcRect );
644 }
645 }
646
647 #region static methods
648
649#if !WINDOWS_STOREAPP
655 public static Image FromFile( string path )
656 {
657 StreamReader sr = new StreamReader( path );
658 Image img = new Image( Texture2D.FromStream( Game.GraphicsDevice, sr.BaseStream ) );
659 return img;
660 }
661#endif
662
668 //public static Image FromFile( StorageFile file )
669 //{
670 // return FromStream( file.Stream );
671 //}
672
678 public static Image FromStream( Stream stream )
679 {
680 return new Image( Texture2D.FromStream( Game.GraphicsDevice, stream ) );
681 }
682
683#if WINDOWS
689 public static Image FromURL( string url )
690 {
691 HttpWebRequest request = (HttpWebRequest)WebRequest.Create( url );
692 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
693 Stream resStream = response.GetResponseStream();
694
695 MemoryStream memStream = new MemoryStream();
696 resStream.CopyTo( memStream );
697
698 Image img = new Image( Texture2D.FromStream( Game.GraphicsDevice, memStream ) );
699 return img;
700 }
701#endif
702
711 public static Image CreateStarSky( int width, int height, int stars, bool transparent = false)
712 {
713 XnaColor[] textureColors = new XnaColor[width * height];
714
715 // Background, black or transparent
716 int i = 0;
717 for ( int ver = 0; ver < height; ver++ )
718 {
719 for ( int hor = 0; hor < width; hor++ )
720 {
721 if (transparent) textureColors[i++] = XnaColor.Transparent;
722 else textureColors[i++] = XnaColor.Black;
723 }
724 }
725
726 // Random stars
727 for ( int j = 0; j < stars; j++ )
728 {
729 int star = RandomGen.NextInt( 0, width * height );
730 int size = RandomGen.NextInt( 1, 5 );
731
732 for ( int k = 0; k < size / 2; k++ )
733 {
734 XnaColor starcolor = RandomGen.NextColor( Jypeli.Color.White, new Color( 192, 192, 192, 255 ) ).AsXnaColor();
735
736 if ( star + k < textureColors.Length )
737 textureColors[star + k] = starcolor;
738
739 if ( size % 2 != 0 || size == 2 )
740 continue;
741
742 int nextStar = star + k + width;
743
744 if ( nextStar < ( width * height ) )
745 {
746 textureColors[nextStar] = starcolor;
747 }
748 }
749 }
750
751 //Texture2D newTexture = new Texture2D( Game.GraphicsDevice, width, height, 1, TextureUsage.None, SurfaceFormat.Color );
752 Texture2D newTexture = new Texture2D( Game.GraphicsDevice, width, height, false, SurfaceFormat.Color );
753 newTexture.SetData<XnaColor>( textureColors );
754
755 return new Image( newTexture );
756 }
757
766 public static Image FromText( string text, Font font, Color textColor, Color backgroundColor )
767 {
768 if ( text == null )
769 text = "";
770
771 var spriteBatch = new SpriteBatch( Game.GraphicsDevice );
772 var device = spriteBatch.GraphicsDevice;
773
774 XnaV2 textDims = font.XnaFont.MeasureString( text );
775 int textw = ( textDims.X > 1 ) ? Convert.ToInt32( textDims.X ) : 1;
776 int texth = ( textDims.Y > 1 ) ? Convert.ToInt32( textDims.Y ) : 1;
777
778 //RenderTarget2D rt = new RenderTarget2D( device, textw, texth, 1, device.DisplayMode.Format );
779 RenderTarget2D rt = new RenderTarget2D( device, textw, texth, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8 );
780
781 //device.SetRenderTarget( 0, rt );
782 device.SetRenderTarget( rt );
783 device.Clear( ClearOptions.Target | ClearOptions.DepthBuffer, backgroundColor.AsXnaColor(), 1.0f, 0 );
784
785 spriteBatch.Begin();
786 font.XnaFont.DrawText(Graphics.FontRenderer, text, XnaV2.Zero.ToSystemNumerics(), textColor.AsXnaColor().ToSystemDrawing());
787 spriteBatch.End();
788
789 //device.SetRenderTarget( 0, null );
790 device.SetRenderTarget( null );
791
792 //return new Image( rt.GetTexture() );
793 return new Image( rt );
794 }
795
806 public static Image DrawTextOnImage( Image img, string text, Vector position, Font font, Color textColor, Color backgroundColor )
807 {
808 if ( text == null )
809 text = "";
810
811 var spriteBatch = new SpriteBatch( Game.GraphicsDevice );
812 var device = spriteBatch.GraphicsDevice;
813
814 XnaV2 textDims = font.XnaFont.MeasureString( text );
815 int textw = ( textDims.X > 1 ) ? Convert.ToInt32( textDims.X ) : 1;
816 int texth = ( textDims.Y > 1 ) ? Convert.ToInt32( textDims.Y ) : 1;
817
818 //RenderTarget2D rt = new RenderTarget2D( device, textw, texth, 1, device.DisplayMode.Format );
819 RenderTarget2D rt = new RenderTarget2D( device, img.Width, img.Height, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8 );
820
821 //device.SetRenderTarget( 0, rt );
822 device.SetRenderTarget( rt );
823 device.Clear( ClearOptions.Target | ClearOptions.DepthBuffer, backgroundColor.AsXnaColor(), 1.0f, 0 );
824
825 float xpos = 0.5f * ( img.Width - textw ) + (float)position.X;
826 float ypos = 0.5f * ( img.Height - texth ) - (float)position.Y;
827
828 spriteBatch.Begin();
829 spriteBatch.Draw( img.XNATexture, rt.Bounds, XnaColor.White );
830 font.XnaFont.DrawText(Graphics.FontRenderer, text, (new XnaV2(xpos, ypos)).ToSystemNumerics(), textColor.AsXnaColor().ToSystemDrawing());
831 spriteBatch.End();
832
833 //device.SetRenderTarget( 0, null );
834 device.SetRenderTarget( null );
835
836
837 //return new Image( rt.GetTexture() );
838 return new Image( rt );
839 }
840
849 public static Image DrawTextOnImage( Image img, string text, Font font, Color textColor )
850 {
851 return DrawTextOnImage( img, text, Vector.Zero, font, textColor, Jypeli.Color.Transparent );
852 }
853
862 public static Image FromGradient( int imageWidth, int imageHeight, Color lowerColor, Color upperColor )
863 {
864 XnaColor lower = lowerColor.AsXnaColor();
865 XnaColor upper = upperColor.AsXnaColor();
866 XnaColor[] textureColors = new XnaColor[imageWidth * imageHeight];
867 int i = 0;
868
869 for ( int ver = 0; ver < imageHeight; ver++ )
870 {
871 for ( int hor = 0; hor < imageWidth; hor++ )
872 {
873 textureColors[i++] = XnaColor.Lerp( upper, lower, ( (float)ver / (float)imageHeight ) );
874 }
875 }
876
877 Texture2D newTexture = new Texture2D( Game.GraphicsDevice, imageWidth, imageHeight, false, SurfaceFormat.Color );
878 newTexture.SetData<XnaColor>( textureColors );
879 return new Image( newTexture );
880 }
881
889 public static Image FromColor( int imageWidth, int imageHeight, Color color )
890 {
891 return Image.FromGradient( imageWidth, imageHeight, color, color );
892 }
893
894 private static XnaColor[] MirrorLine( XnaColor[] scanline, int width )
895 {
896 XnaColor[] res = new XnaColor[width];
897 int l = 0;
898 int r = width - 1;
899
900 while ( l < r )
901 {
902 res[l] = scanline[r];
903 res[r] = scanline[l];
904 l++; r--;
905 }
906
907 if ( l == r )
908 {
909 // Center pixel
910 res[l] = scanline[l];
911 }
912
913 return res;
914 }
915
921 public static Image Mirror( Image image )
922 {
923 Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
924 XnaColor[] scanline = new XnaColor[image.Width];
925 var scanRect = new XnaRectangle( 0, 0, image.Width, 1 );
926
927 for ( scanRect.Y = 0; scanRect.Y < image.Height; scanRect.Y++ )
928 {
929 image.XNATexture.GetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
930 scanline = MirrorLine( scanline, image.Width );
931 newTex.SetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
932 }
933
934 return new Image( newTex );
935 }
936
942 public static Image[] Mirror( Image[] images )
943 {
944 Image[] result = new Image[images.Length];
945 for ( int i = 0; i < images.Length; i++ )
946 result[i] = Mirror( images[i] );
947 return result;
948 }
949
955 public static Image Flip( Image image )
956 {
957 Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
958 XnaColor[] scanlineUpper = new XnaColor[image.Width];
959 XnaColor[] scanlineLower = new XnaColor[image.Width];
960 var scanRectUpper = new XnaRectangle( 0, 0, image.Width, 1 );
961 var scanRectLower = new XnaRectangle( 0, 0, image.Width, 1 );
962
963 for ( int i = 0; i < image.Height / 2; i++ )
964 {
965 scanRectUpper.Y = i;
966 scanRectLower.Y = image.Height - 1 - i;
967
968 image.XNATexture.GetData<XnaColor>( 0, scanRectUpper, scanlineUpper, 0, image.Width );
969 image.XNATexture.GetData<XnaColor>( 0, scanRectLower, scanlineLower, 0, image.Width );
970
971 newTex.SetData<XnaColor>( 0, scanRectUpper, scanlineLower, 0, image.Width );
972 newTex.SetData<XnaColor>( 0, scanRectLower, scanlineUpper, 0, image.Width );
973 }
974
975 if ( image.Height % 2 == 1 )
976 {
977 // Center line
978 scanRectUpper.Y = image.Height / 2;
979 image.XNATexture.GetData<XnaColor>( 0, scanRectUpper, scanlineUpper, 0, image.Width );
980 newTex.SetData<XnaColor>( 0, scanRectUpper, scanlineUpper, 0, image.Width );
981 }
982
983 return new Image( newTex );
984 }
985
991 public static Image[] Flip( Image[] images )
992 {
993 Image[] result = new Image[images.Length];
994 for ( int i = 0; i < images.Length; i++ )
995 result[i] = Flip( images[i] );
996 return result;
997 }
998
1005 public static Image Color( Image image, Color color )
1006 {
1007 Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
1008 XnaColor[] scanline = new XnaColor[image.Width];
1009 var scanRect = new XnaRectangle( 0, 0, image.Width, 1 );
1010 XnaColor xnaColor = color.AsXnaColor();
1011
1012 for ( scanRect.Y = 0; scanRect.Y < image.Height; scanRect.Y++ )
1013 {
1014 image.XNATexture.GetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
1015
1016 for ( int i = 0; i < image.Width; i++ )
1017 {
1018 if ( scanline[i].A < 255 )
1019 {
1020 scanline[i].R = (byte)( ( 255 - scanline[i].A ) * xnaColor.R + scanline[i].A * scanline[i].R );
1021 scanline[i].G = (byte)( ( 255 - scanline[i].A ) * xnaColor.G + scanline[i].A * scanline[i].G );
1022 scanline[i].B = (byte)( ( 255 - scanline[i].A ) * xnaColor.B + scanline[i].A * scanline[i].B );
1023
1024 if ( scanline[i].A > 10 )
1025 {
1026 scanline[i].A = color.AlphaComponent;
1027 }
1028 }
1029 }
1030
1031 newTex.SetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
1032 }
1033
1034 return new Image( newTex );
1035 }
1036
1043 public static Image[] Color( Image[] images, Color color )
1044 {
1045 Image[] result = new Image[images.Length];
1046 for ( int i = 0; i < images.Length; i++ )
1047 result[i] = Color( images[i], color );
1048 return result;
1049 }
1050
1051 // TODO: On hyvin hämäävä nimi...
1058 public static Image Color( Image image, byte alpha )
1059 {
1060 Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
1061 XnaColor[] scanline = new XnaColor[image.Width];
1062 var scanRect = new XnaRectangle( 0, 0, image.Width, 1 );
1063
1064 for ( scanRect.Y = 0; scanRect.Y < image.Height; scanRect.Y++ )
1065 {
1066 image.XNATexture.GetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
1067 for ( int i = 0; i < image.Width; i++ )
1068 {
1069 scanline[i].A = alpha;
1070 }
1071 newTex.SetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
1072 }
1073 return new Image( newTex );
1074 }
1075
1082 public static Image TileHorizontal( Image left, Image right )
1083 {
1084 if ( left.Height != right.Height ) throw new InvalidOperationException( "Cannot tile two images with different height" );
1085
1086 left.DoInitTexture();
1087 right.DoInitTexture();
1088
1089 XnaRectangle leftRect = new XnaRectangle( 0, 0, left.Width, left.Height );
1090 XnaRectangle rightSrc = new XnaRectangle( 0, 0, right.Width, right.Height );
1091 XnaRectangle rightDest = new XnaRectangle( left.Width, 0, right.Width, right.Height );
1092
1093 Image tiled = new Image( left.Width + right.Width, left.Height );
1094 tiled.InitTexture += delegate { CopyData( tiled, left, leftRect, leftRect ); };
1095 tiled.InitTexture += delegate { CopyData( tiled, right, rightDest, rightSrc ); };
1096
1097 return tiled;
1098 }
1099
1106 public static Image TileVertical( Image top, Image bottom )
1107 {
1108 if ( top.Width != bottom.Width ) throw new InvalidOperationException( "Cannot tile two images with different width" );
1109
1110 top.DoInitTexture();
1111 bottom.DoInitTexture();
1112
1113 XnaRectangle topRect = new XnaRectangle( 0, 0, top.Width, top.Height );
1114 XnaRectangle botSrc = new XnaRectangle( 0, 0, bottom.Width, bottom.Height );
1115 XnaRectangle botDest = new XnaRectangle( 0, top.Height, bottom.Width, bottom.Height );
1116
1117 Image tiled = new Image( top.Width, top.Height + bottom.Height );
1118 tiled.InitTexture += delegate { CopyData( tiled, top, topRect, topRect ); };
1119 tiled.InitTexture += delegate { CopyData( tiled, bottom, botDest, botSrc ); };
1120
1121 return tiled;
1122 }
1123
1124 #endregion
1125
1134 public Image Area( int left, int top, int right, int bottom )
1135 {
1136 int width = right - left;
1137 int height = bottom - top;
1138
1139 if ( width <= 0 ) throw new ArgumentException( "Left coordinate must be less than right coordinate" );
1140 if ( height <= 0 ) throw new ArgumentException( "Top coordinate must be less than bottom coordinate" );
1141
1142 XnaRectangle srcRect = new XnaRectangle( left, top, width, height );
1143 XnaRectangle destRect = new XnaRectangle( 0, 0, width, height );
1144
1145 Image areaImage = new Image( width, height );
1146 areaImage.parentImage = this;
1147 areaImage.parentRectangle = srcRect;
1148 areaImage.InitTexture += delegate { CopyData( areaImage, this, destRect, srcRect ); };
1149 return areaImage;
1150 }
1151
1156 public void Fill( Color backColor )
1157 {
1158 DoInitTexture();
1160
1161 XnaRectangle rect = new XnaRectangle( 0, 0, xnaTexture.Width, 1 );
1162 Color[] scanline = new Color[xnaTexture.Width];
1163
1164 for ( int i = 0; i < xnaTexture.Width; i++ )
1165 scanline[i] = backColor;
1166
1167 for ( rect.Y = 0; rect.Y < xnaTexture.Height; rect.Y++ )
1168 xnaTexture.SetData<Color>( 0, rect, scanline, 0, xnaTexture.Width );
1169
1170 UpdateTexture();
1171 }
1172
1181 public void ReplaceColor( Color src, Color dest, double tolerance, bool blend, bool exactAlpha = false )
1182 {
1183 XnaColor srcColor = src.AsXnaColor();
1184 XnaColor destColor = dest.AsXnaColor();
1185 XnaColorConverter op = delegate( XnaColor c )
1186 {
1187 if ( exactAlpha && c.A != srcColor.A )
1188 return c;
1189
1190 if ( JyColor.Distance( c, srcColor ) <= tolerance )
1191 {
1192 if ( !blend ) return destColor;
1193 Vector3 srcDist = new Vector3( c.R - srcColor.R, c.G - srcColor.G, c.B - srcColor.B );
1194 return new XnaColor( destColor.ToVector3() + srcDist );
1195 }
1196
1197 return c;
1198 };
1199
1200 ApplyPixelOperation( op );
1201 }
1202
1208 public void ReplaceColor( Color src, Color dest )
1209 {
1210 XnaColor srcColor = src.AsXnaColor();
1211 XnaColor destColor = dest.AsXnaColor();
1212 XnaColorConverter op = delegate( XnaColor c )
1213 {
1214 return c == srcColor ? destColor : c;
1215 };
1216
1217 ApplyPixelOperation( op );
1218 }
1219
1225 public Stream AsJpeg()
1226 {
1227 DoInitTexture();
1228 MemoryStream jpegStream = new MemoryStream();
1229 XNATexture.SaveAsJpeg( jpegStream, Width, Height );
1230 jpegStream.Seek( 0, SeekOrigin.Begin );
1231 return jpegStream;
1232 }
1233
1239 public Stream AsPng()
1240 {
1241 DoInitTexture();
1242 MemoryStream pngStream = new MemoryStream();
1243 XNATexture.SaveAsPng( pngStream, Width, Height );
1244 pngStream.Seek( 0, SeekOrigin.Begin );
1245 return pngStream;
1246 }
1247 }
1248}
1249
Microsoft.Xna.Framework.Vector2 XnaV2
Definition: Font.cs:4
System.Converter< Microsoft.Xna.Framework.Color, Microsoft.Xna.Framework.Color > XnaColorConverter
Definition: Image.cs:20
Jypeli.Color JyColor
Definition: Image.cs:12
Microsoft.Xna.Framework.Rectangle XnaRectangle
Definition: Image.cs:9
System.Converter< Jypeli.Color, Jypeli.Color > ColorConverter
Definition: Image.cs:19
Microsoft.Xna.Framework.Color XnaColor
Definition: Image.cs:11
Microsoft.Xna.Framework.Rectangle XnaRectangle
Microsoft.Xna.Framework.Color XnaColor
Fontti.
Definition: Font.cs:24
DynamicSpriteFont XnaFont
Definition: Font.cs:50
static new GraphicsDevice GraphicsDevice
XNA:n grafiikkakortti.
Definition: Graphics.cs:49
static void DoNextUpdate(Action action)
Suorittaa aliohjelman seuraavalla päivityksellä.
static string FileExtensionCheck(string file, string[] extensions)
Etsii millä päätteellä annettu tiedosto löytyy
Definition: Content.cs:200
Contains graphics resources.
Definition: Graphics.cs:36
static FontStashSharp.Renderer FontRenderer
Definition: Graphics.cs:42
Kuva.
Definition: Image.cs:30
static string[] imageExtensions
Definition: Image.cs:49
void DoUpdateTexture()
Definition: Image.cs:637
Image(int width, int height, Color backColor)
Luo uuden kuvan.
Definition: Image.cs:427
static int MONOGETDATAINC
Definition: Image.cs:33
static void CopyData(Texture2D dest, Texture2D src)
Definition: Image.cs:542
static Image[] Color(Image[] images, Color color)
Värittää kuvat.
Definition: Image.cs:1043
void DoInitTexture()
Definition: Image.cs:465
static Image TileVertical(Image top, Image bottom)
Yhdistää kaksi kuvaa olemaan päällekkäin uudessa kuvassa
Definition: Image.cs:1106
static Image[] Flip(Image[] images)
Peilaa kuvat Y-suunnassa.
Definition: Image.cs:991
uint[,] GetDataUInt(int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Palalutetaan kuvan pikselit ARGB-uint[,] -taulukkona
Definition: Image.cs:237
Color[,] GetData(int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Kuvan pikselit Color-taulukkona
Definition: Image.cs:118
Texture2D LoadFile(string path)
Definition: Image.cs:490
static Image DrawTextOnImage(Image img, string text, Vector position, Font font, Color textColor, Color backgroundColor)
Piirtää tekstiä kuvan päälle.
Definition: Image.cs:806
int _width
Definition: Image.cs:46
uint[][] GetDataUIntAA(int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Palalutetaan kuvan pikselit ARGB-uint[][] -taulukkona
Definition: Image.cs:272
Image Area(int left, int top, int right, int bottom)
Leikkaa kuvasta palan ja palauttaa sen uutena kuvana
Definition: Image.cs:1134
void CreateNewTexture()
Definition: Image.cs:500
Stream AsJpeg()
Palauttaa kuvan jpeg-muodossa, jossa se voidaan esimerkiksi tallentaa DataStorage....
Definition: Image.cs:1225
static Image Mirror(Image image)
Peilaa kuvan X-suunnassa.
Definition: Image.cs:921
Texture2D XNATexture
Definition: Image.cs:72
static Image DrawTextOnImage(Image img, string text, Font font, Color textColor)
Piirtää tekstiä kuvan päälle keskelle kuvaa.
Definition: Image.cs:849
Image Clone()
Luo kopion kuvasta
Definition: Image.cs:509
static Image FromFile(string path)
Lataa kuvan tiedostosta. Kuvan ei tarvitse olla lisättynä Content-projektiin.
Definition: Image.cs:655
Stream AsPng()
Palauttaa kuvan png-muodossa, jossa se voidaan esimerkiksi tallentaa DataStorage.Export -metodilla.
Definition: Image.cs:1239
int _height
Definition: Image.cs:47
void SetData(byte[] byteArr)
Asettaa kuvan pikselit annetun tavutaulukon mukaan.
Definition: Image.cs:211
void DoInitDimensions()
Definition: Image.cs:454
void ApplyPixelOperation(ColorConverter operation)
Suorittaa annetun pikselioperaation koko kuvalle.
Definition: Image.cs:579
void ReplaceColor(Color src, Color dest, double tolerance, bool blend, bool exactAlpha=false)
Korvaa värin toisella värillä.
Definition: Image.cs:1181
string assetName
Definition: Image.cs:40
XnaRectangle parentRectangle
Definition: Image.cs:38
static Image[] Mirror(Image[] images)
Peilaa kuvat X-suunnassa.
Definition: Image.cs:942
void SetData(uint[][] bmp, int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Asetetaan kuvan pikselit ARGB-uint taulukosta
Definition: Image.cs:345
int Width
Leveys pikseleinä.
Definition: Image.cs:374
void AssertDimensions(int width, int height)
Definition: Image.cs:448
void SetData(byte[] byteArr, int height, int width)
Asettaa kuvan pikselit annetun tavutaulukon mukaan.
Definition: Image.cs:187
void InvalidateAsset()
Tekee uuden lokaalin instanssin kuvan tekstuurista ja poistaa viitteen assettiin josta kuva on luotu....
Definition: Image.cs:621
void LoadContentTexture()
Definition: Image.cs:479
Image(string assetName)
Definition: Image.cs:402
static XnaColor[] MirrorLine(XnaColor[] scanline, int width)
Definition: Image.cs:894
static void SetLineCorrection(int n)
Asetetaan bitmapin rivikorjaus Mono:n bugin (???) takia
Definition: Image.cs:55
void SetData(uint[,] bmp, int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Asetetaan kuvan pikselit ARGB-uint taulukosta
Definition: Image.cs:309
void ApplyPixelOperation(XnaColorConverter operation)
Suorittaa annetun pikselioperaation koko kuvalle.
Definition: Image.cs:593
static void CopyData(Image dest, Image src)
Definition: Image.cs:526
Action InitDimensions
Definition: Image.cs:43
static int MONOGETDATAMUL
Definition: Image.cs:32
Image parentImage
Definition: Image.cs:37
Action InitTexture
Definition: Image.cs:44
Image(int width, int height)
Definition: Image.cs:394
static Image Color(Image image, byte alpha)
Muuttaa kuvan jokaisen pikselin alpha-arvon vastaamaan annettua.
Definition: Image.cs:1058
static Image CreateStarSky(int width, int height, int stars, bool transparent=false)
Luo tähtitaivaskuvan.
Definition: Image.cs:711
static Image Color(Image image, Color color)
Värittää kuvan.
Definition: Image.cs:1005
static Image Flip(Image image)
Peilaa kuvan Y-suunnassa.
Definition: Image.cs:955
Image(double width, double height, Color backColor)
Luo uuden kuvan.
Definition: Image.cs:443
static Image TileHorizontal(Image left, Image right)
Yhditää kaksi kuvaa olemaan vierekkäin uudessa kuvassa.
Definition: Image.cs:1082
Texture2D xnaTexture
Definition: Image.cs:41
static Image FromGradient(int imageWidth, int imageHeight, Color lowerColor, Color upperColor)
Luo pystysuuntaisen liukuväritetyn kuvan.
Definition: Image.cs:862
string Name
Nimi.
Definition: Image.cs:390
void Fill(Color backColor)
Täyttää kuvan värillä
Definition: Image.cs:1156
byte[] GetByteArray()
Kuvan pikselit byte-taulukkona. Tavut ovat järjestyksessä punainen, vihreä, sininen,...
Definition: Image.cs:221
void UpdateTexture()
Definition: Image.cs:632
Image(Microsoft.Xna.Framework.Graphics.Texture2D texture)
Kuva MonoGamen Texture2D oliosta
Definition: Image.cs:413
static Image FromText(string text, Font font, Color textColor, Color backgroundColor)
Luo kuvan tekstistä.
Definition: Image.cs:766
int Height
Korkeus pikseleinä.
Definition: Image.cs:382
static Image FromColor(int imageWidth, int imageHeight, Color color)
Luo yksivärisen kuvan.
Definition: Image.cs:889
void SetData(Color[,] bmp, int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Asettaa kuvan pikselit Color-taulukosta
Definition: Image.cs:154
static Image FromStream(Stream stream)
Lataa kuvan tiedostovirrasta.
Definition: Image.cs:678
void ReplaceColor(Color src, Color dest)
Korvaa värin toisella värillä.
Definition: Image.cs:1208
static void CopyData(Image dest, Image src, XnaRectangle destRect, XnaRectangle srcRect)
Definition: Image.cs:556
Apufunktioita listojen ja muiden tietorakenteiden käyttöön.
Definition: ListHelpers.cs:11
Satunnaisgeneraattori. Luo satunnaisia arvoja, mm. lukuja, vektoreita sekä kulmia.
Definition: RandomGen.cs:39
static Color NextColor()
Palauttaa satunnaisen värin.
Definition: RandomGen.cs:154
static int NextInt(int maxValue)
Palauttaa satunnaisen kokonaisluvun, joka on vähintään 0 ja pienempi kuin
Definition: RandomGen.cs:54
Microsoft.Xna.Framework.Vector2 XnaV2
Definition: Mouse.cs:37
Väri.
Definition: Color.cs:13
static readonly Color White
Valkoinen.
Definition: Color.cs:956
static Color UIntToColor(uint c)
Tekee kokonaisluvusta värin
Definition: Color.cs:306
static readonly Color Transparent
Läpinäkyvä väri.
Definition: Color.cs:931
byte AlphaComponent
Läpinäkymättömyys välillä 0-255
Definition: Color.cs:36
XnaColor AsXnaColor()
Definition: Color.cs:46
2D-vektori.
Definition: Vector.cs:67
double Y
Vektorin Y-komponentti
Definition: Vector.cs:339
static readonly Vector Zero
Nollavektori.
Definition: Vector.cs:71
double X
Vektorin X-komponentti.
Definition: Vector.cs:334