public Graphic SwapChannelsToGRB() { if(channelFormat!=Format.RGB) return this.ConvertToRGB().SwapChannelsToBRG(); Graphic ret=new Graphic(width, height, Format.RGB); if(ret.imageData==null) return ret; uint count=width*height; byte[] src=imageData; uint ind=0; byte[] dst=ret.imageData; uint inds=0; //Channel Swap RGB for(uint i=0; i<count; i++) { byte r=src[inds++]; byte g=src[inds++]; byte b=src[inds++]; dst[ind++]=g; dst[ind++]=r; dst[ind++]=b; } return ret; }
/// <summary> /// Applies an edge filter to the bitmap. /// </summary> /// <param name="bitmap">A bitmap.</param> /// <returns>Edge bitmap.</returns> public static Graphic DetectEdges(Graphic bitmap) { Graphic grayscaleMap=bitmap.ConvertToGray(); Graphic edgeMap=new Graphic(grayscaleMap.Width, grayscaleMap.Height, Format.RGB); for(int y=1; y<edgeMap.Height-1; y++) { for(int x=1; x<edgeMap.Width-1; x++) { int sum=System.Math.Abs(grayscaleMap.GetPixel(x-1, y-1).R+grayscaleMap.GetPixel(x, y-1).R+grayscaleMap.GetPixel(x+1, y-1).R -grayscaleMap.GetPixel(x-1, y+1).R-grayscaleMap.GetPixel(x, y+1).R-grayscaleMap.GetPixel(x+1, y+1).R); System.Drawing.Color z1=grayscaleMap.GetPixel(x-1, y-1); System.Drawing.Color z2=grayscaleMap.GetPixel(x, y-1); System.Drawing.Color z3=grayscaleMap.GetPixel(x+1, y-1); System.Drawing.Color z4=grayscaleMap.GetPixel(x-1, y+1); System.Drawing.Color z5=grayscaleMap.GetPixel(x, y+1); System.Drawing.Color z6=grayscaleMap.GetPixel(x+1, y+1); int foo=z1.R+z2.R+z3.R-z4.R-z5.R-z6.R; if(sum>255) sum=255; sum=255-sum; edgeMap.SetPixel(x, y, System.Drawing.Color.FromArgb(255, sum, sum, sum)); } } return edgeMap; }
public static Graphic FromStream(Stream stream) { Image img=Image.FromStream(stream); uint width=(uint)img.Size.Width; uint height=(uint)img.Size.Height; Graphic ret=null; if ((img.PixelFormat&PixelFormat.Alpha)==PixelFormat.Alpha) { ret=new Graphic(width, height, Format.RGBA); Bitmap bmp=new Bitmap(img); BitmapData data=bmp.LockBits(new Rectangle(0, 0, (int)width, (int)height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); Marshal.Copy(data.Scan0, ret.imageData, 0, (int)(width*height*4)); bmp.UnlockBits(data); } else { ret=new Graphic(width, height, Format.RGB); Bitmap bmp=new Bitmap(img); BitmapData data=bmp.LockBits(new Rectangle(0, 0, (int)width, (int)height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); if (((int)width*3)==data.Stride) { Marshal.Copy(data.Scan0, ret.imageData, 0, (int)(width*height*3)); } else { if (IntPtr.Size==4) { for (uint i=0; i<height; i++) { Marshal.Copy((IntPtr)(data.Scan0.ToInt32()+(int)(i*data.Stride)), ret.imageData, (int)(width*3*i), (int)(width*3)); } } else if (IntPtr.Size==8) { for (uint i=0; i<height; i++) { Marshal.Copy((IntPtr)(data.Scan0.ToInt64()+(long)(i*data.Stride)), ret.imageData, (int)(width*3*i), (int)(width*3)); } } } bmp.UnlockBits(data); data=null; bmp.Dispose(); bmp=null; } img.Dispose(); img=null; return ret; }
/// <summary> /// Computes the difference between to different bitmap regions. /// </summary> /// <param name="grayscaleBitmapA">First bitmap.</param> /// <param name="compareRectA">First bitmap region.</param> /// <param name="grayscaleBitmapB">Secound bitmap</param> /// <param name="compareRectB">Secound bitmap region.</param> /// <returns></returns> public static int ComputeDistance(Graphic grayscaleBitmapA, System.Drawing.Rectangle compareRectA, Graphic grayscaleBitmapB, System.Drawing.Rectangle compareRectB) { int averageA=GetAvarageGrayscale(grayscaleBitmapA, compareRectA); int averageB=GetAvarageGrayscale(grayscaleBitmapB, compareRectB); return System.Math.Abs(averageA-averageB); }
Graphic NearestPixelResizeV(uint h) { double delta=(double)height/h; Graphic ret=new Graphic(width, h, channelFormat); if(ret.imageData==null) return ret; uint bpp=BytePerPixel; uint bw=width*bpp; uint dst=0; for(uint y=0; y<h; y++) { uint src=((uint)(y*delta+delta/2))*bw; for(uint i=0; i<bw; i++) ret.imageData[dst++]=imageData[src++]; } return ret; }
/// <summary> /// Computes the avarange grayscale value of a certain bitmap region. /// </summary> /// <param name="grayscaleBitmap">A grayscale bitmap.</param> /// <param name="rectangle">Defines a region.</param> /// <returns></returns> public static int GetAvarageGrayscale(Graphic grayscaleBitmap, System.Drawing.Rectangle rectangle) { int average=0; try { for(int y=rectangle.Y; y<rectangle.Bottom; y++) for(int x=rectangle.X; x<rectangle.Right; x++) { average+=grayscaleBitmap.GetPixel(x, y).R; } } catch(System.Exception ex) { return 128; } return average/(rectangle.Width*rectangle.Height); }
public void Display() { CSCL.Imaging.Graphic image=new CSCL.Imaging.Graphic((uint)width, (uint)height, Format.RGB); for(Int64 i=Constants.GraphicMemoryDisplayAdressStart; i<width*height; i++) { Int64 x=i%width; Int64 y=i/width; byte r=data[i+0]; byte g=data[i+1]; byte b=data[i+2]; byte a=data[i+3]; image.SetPixel((int)x, (int)y, Color.FromArgb(a, r, g, b)); } image.SaveToPNG("display.png"); }
public Graphic ConvertToGray() { if(channelFormat==Format.GRAY) return this; Graphic ret=new Graphic(width, height, Format.GRAY); if(ret.imageData==null) return ret; uint count=width*height; byte[] src=imageData; uint ind=0; byte[] dst=ret.imageData; uint inds=0; switch(channelFormat) { case Format.GRAYAlpha: { for(uint i=0; i<count; i++) { dst[ind++]=src[inds++]; inds++; } break; } case Format.BGR: { for(uint i=0; i<count; i++) { byte r=src[inds++]; byte g=src[inds++]; byte b=src[inds++]; dst[ind++]=(byte)(0.299*r+0.587*g+0.114*b); } break; } case Format.RGB: { for(uint i=0; i<count; i++) { byte b=src[inds++]; byte g=src[inds++]; byte r=src[inds++]; dst[ind++]=(byte)(0.299*r+0.587*g+0.114*b); } break; } case Format.BGRA: { for(uint i=0; i<count; i++) { byte r=src[inds++]; byte g=src[inds++]; byte b=src[inds++]; inds++; dst[ind++]=(byte)(0.299*r+0.587*g+0.114*b); } break; } case Format.RGBA: { for(uint i=0; i<count; i++) { byte b=src[inds++]; byte g=src[inds++]; byte r=src[inds++]; inds++; dst[ind++]=(byte)(0.299*r+0.587*g+0.114*b); } break; } } return ret; }
public Graphic ToFlippedHorizontal() { Graphic ret=new Graphic(width, height, channelFormat); if(ret.imageData==null) return ret; uint bw=width*BytePerPixel; uint src=0; uint dst=height*bw; for(uint y=0; y<height; y++) { dst-=bw; for(uint x=0; x<bw; x++) ret.imageData[dst++]=imageData[src++]; dst-=bw; } return ret; }
/// <summary> /// Gibt ein Bitmap zurück /// </summary> /// <returns></returns> public CSCL.Imaging.Graphic GetImage(string dmttable, int sitenumber) { CSCL.Imaging.Graphic ret=new CSCL.Imaging.Graphic(); try { string sqlCommand=String.Format("SELECT DmtSiteNumber, DmtFileType, DmtData FROM \"{0}\"", dmttable); DataTable tmpDT=Globals.InstSQLite.ExecuteQuery(sqlCommand); string fileType=tmpDT.Rows[0]["DmtFileType"].ToString(); MemoryStream ms=new MemoryStream((byte[])tmpDT.Rows[0]["DmtData"]); switch(fileType) { case "odt": { //TextDocument odtDocument=new TextDocument(); //odtDocument.Load break; } default: { ret=new CSCL.Imaging.Graphic(400, 800, Format.RGB); ret.FillWithMandelbrot(); break; } } //ret=gtImage.FromStream(ms); ms.Close(); } catch { throw new Exception(); } return ret; }
public Graphic ToRot90() { Graphic ret=new Graphic(height, width, channelFormat); if(ret.imageData==null) return ret; uint bpp=BytePerPixel; uint bw=height*bpp; uint src=0; uint dst_=(width-1)*bw; for(uint y=0; y<height; y++) { uint dst=dst_; for(uint x=0; x<width; x++) { for(uint i=0; i<bpp; i++) ret.imageData[dst++]=imageData[src++]; dst-=bw+bpp; } dst_+=bpp; } return ret; }
public Graphic ToFlippedVertical() { Graphic ret=new Graphic(width, height, channelFormat); if(ret.imageData==null) return ret; uint bpp=BytePerPixel; uint bw=width*bpp; uint src=0; uint dst=bw; dst-=bpp; for(uint y=0; y<height; y++) { for(uint x=0; x<width; x++) { for(uint i=0; i<bpp; i++) ret.imageData[dst++]=imageData[src++]; dst-=2*bpp; } dst+=2*bw; } return ret; }
public void Draw(int x, int y, Graphic source) { if(x>=width||y>=height) throw new ArgumentOutOfRangeException("x or y", "Out of image."); if(x+source.width<0||y+source.height<0) throw new ArgumentOutOfRangeException("x or y", "Out of image."); Graphic srcimg=source.ConvertTo(channelFormat); if(srcimg==null) return; uint bpp=ConvertToBytePerPixel(channelFormat); unsafe { fixed(byte* src_=srcimg.imageData, dst_=imageData) { uint start=(uint)System.Math.Max(-x, 0)*bpp; uint end=(uint)System.Math.Min(source.width, width-x)*bpp; uint jstart=(uint)System.Math.Max(-y, 0); uint jend=(uint)System.Math.Min(source.height, height-y); byte* src__=src_+start; byte* dst__=dst_+x*bpp+start; uint sw=source.width*bpp; uint dw=width*bpp; for(uint j=jstart; j<jend; j++) { byte* src=src__+sw*j; byte* dst=dst__+dw*(y+j); for(uint i=start; i<end; i++) *dst++=*src++; } } } }
Graphic NearestPixelResizeVH(uint w, uint h) { double deltah=(double)height/h; double deltaw=(double)width/w; uint bpp=BytePerPixel; uint[] dx=new uint[w]; for(uint x=0; x<w; x++) dx[x]=(uint)(x*deltaw+deltaw/2); if(bpp==1) { Graphic ret=new Graphic(w, h, channelFormat); if(ret.imageData==null) return ret; uint dst=0; for(uint y=0; y<h; y++) { uint src=(uint)(y*deltah+deltah/2)*width; for(uint x=0; x<w; x++) ret.imageData[dst++]=imageData[src+dx[x]]; } return ret; } if(bpp==4) { Graphic ret=new Graphic(w, h, channelFormat); if(ret.imageData==null) return ret; uint dst=0; uint w4=width*4; for(uint y=0; y<h; y++) { uint src=(uint)(y*deltah+deltah/2)*w4; for(uint x=0; x<w; x++) { uint s=src+dx[x]*4; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s]; } } return ret; } if(bpp==3) { Graphic ret=new Graphic(w, h, channelFormat); if(ret.imageData==null) return ret; uint dst=0; uint w3=width*3; for(uint y=0; y<h; y++) { uint src=(uint)(y*deltah+deltah/2)*w3; for(uint x=0; x<w; x++) { uint s=src+dx[x]*3; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s]; } } return ret; } if(bpp==2) { Graphic ret=new Graphic(w, h, channelFormat); if(ret.imageData==null) return ret; uint dst=0; uint w2=width*2; for(uint y=0; y<h; y++) { uint src=(uint)(y*deltah+deltah/2)*w2; for(uint x=0; x<w; x++) { uint s=src+dx[x]*2; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s]; } } return ret; } return new Graphic(0, 0, channelFormat); }
/// <summary> /// Speichert eine Karte welche je nach Monsterstärke eingefärbt wird /// </summary> /// <param name="filename"></param> /// <param name="img"></param> /// <param name="map"></param> public static void SaveFeatureMapMonsterSpreading(string clientdata, string filename, Graphic img, TMX map) { //Farben Color green=Color.FromArgb(128, 0, 255, 0); Color yellow=Color.FromArgb(128, 255, 255, 0); Color red=Color.FromArgb(128, 255, 0, 0); Color blue=Color.FromArgb(128, 0, 0, 255); //Images Graphic tmpImage=img.GetImage(); Graphic tmpDraw=new Graphic(tmpImage.Width, tmpImage.Height, tmpImage.ChannelFormat); //Ermittlung der Durchschnittswerte string fnMonsterXml=clientdata+"monsters.xml"; List<Monster> monsters=Monster.GetMonstersFromMonsterXml(fnMonsterXml); monsters.Sort(); Int64 minFightingStrength=999999999999; Int64 maxFightingStrength=-999999999999; Int64 medianFightingStrength=0; Dictionary<int, Int64> MonsterIDsAndFightingStrength=new Dictionary<int, Int64>(); foreach(Monster monster in monsters) { if(monster.ID==1) continue; //Killermade ignorieren if(monster.ID==31) continue; //Seraphim Nex ignorieren if(monster.ID>9999) continue; //Experimentelle Monster ignorieren Int64 fightingStrength=monster.FightingStrength; if(fightingStrength<minFightingStrength) minFightingStrength=fightingStrength; if(fightingStrength>maxFightingStrength) maxFightingStrength=fightingStrength; MonsterIDsAndFightingStrength.Add(monster.ID, fightingStrength); } medianFightingStrength=(maxFightingStrength+minFightingStrength)/2; //Monster der Karte ermitteln List<MonsterSpawn> mSpawns=Monsters.GetMonsterSpawnFromMap(map); if(mSpawns.Count>0) { Int64 fss=0; foreach(MonsterSpawn spawn in mSpawns) { if(spawn.MonsterID==1) continue; //Killermade ignorieren if(spawn.MonsterID==31) continue; //Seraphim Nex ignorieren if(spawn.MonsterID>=10000) continue; //Pflanzen etc ignorieren fss+=MonsterIDsAndFightingStrength[spawn.MonsterID]; } fss=fss/mSpawns.Count; //Einfärben je nach Stärke Int64 vSmarterGreen=(medianFightingStrength+minFightingStrength)/2; Int64 vSmarterYellow=(maxFightingStrength+medianFightingStrength)/2; if(fss<vSmarterGreen) { tmpDraw.Fill(green); } else if(fss<vSmarterYellow) { tmpDraw.Fill(yellow); } else { tmpDraw.Fill(red); } } else //Keine Monster auf der Karte vorhanden { tmpDraw.Fill(blue); } //Drawen tmpImage.Draw(0, 0, tmpDraw, true); tmpImage.SaveToFile(filename); }
/// <summary> /// Erzeugt ein Thumbnail /// EXPERIMENTEL Muss getestet werdne /// Quadrates Thumbnail unter beibehaltung der Seitenverhälntisse /// </summary> /// <param name="size"></param> /// <returns></returns> public Graphic ToThumbnail(uint size) { Graphic bmp=null; Graphic crapped=null; uint x=0, y=0; double prop=0; if (width>size) { // compute proportation prop=(double)width/(double)height; if (width>height) { x=(uint)System.Math.Round(size*prop, 0); y=size; } else { x=size; y=(uint)System.Math.Round(size/prop, 0); } //TESTEN bmp=new Graphic(x, y); //bmp=new System.Drawing.Bitmap((Image)image, new Size(x, y)); crapped=new Graphic(size, size, channelFormat); crapped.Draw(0, 0, bmp); //crapped=new System.Drawing.Bitmap(75, 75); //Graphics g=Graphics.FromImage(crapped); //g.DrawImage(bmp, // new Rectangle(0, 0, 75, 75), // new Rectangle(0, 0, 75, 75), // GraphicsUnit.Pixel); bmp=crapped; } else { crapped=this; } return bmp; }
/// <summary> /// Converts a bitmap to ascii art. /// </summary> /// <param name="bitmap">A bitmap.</param> /// <returns>Ascii art.</returns> /// <example> /* 0:::::::::::::::::::::::::::::$MMMMM%:::::::::::::::::::::::::::::::::::::M % (#''` !M8 M % :QMMMMMMMM849640MMM@( M % "MMMMMMM4*' HM: !MB#MMMMMM$ M % 'MMMM3 ''$844$ `6MMMMM' M % '#MNN#H@@@@@@HMMM! '''` $MMM3 M %1M@99889QB81!!M*M4'` @QM: M %1Q'"B000008MMM*`MM:`''` !M@3 :&$;` M %0` $` !B `*MM6 ''''` 'MM(!: $MMMMMMMMMM %!& `8' #` ''1MM@H3'`'''` '$MMMH % 4M$''!@BMMM4M % ;0 46 (3 `''''1#@HBH#&$&$448MMMM0' :' (M& ':@BQ@" M % !B(16BMQ`B :894: `* 'MH B8Q0` M % &MM` *M& !4 ;:"Q#M#' !@3Q` M % 4MM;&` " (01'`'''`"Q0" M % :MN `( `'''` '84B' M % & `` `''QB09` M % ! :( '389088@; M % 1: '9 !"6QQQ! M % `# :B `84' M % (# 04 &' M % 1M6 `9B! $: M % !M#006(:'"6490` `Q: M % 4B! :(1! `48` M % 4@9' ;@B! M % '9QB0! ;8QB3 M % `&88909444099898% M 0:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::M */ /// </example> public string ToAscii() { Graphic edgeMap=DetectEdges(this); string output=""; for(int y=0; y<edgeMap.Height; y+=13) { for(int x=0; x<edgeMap.Width; x+=8) { int minDistance=999999999; char minChar=' '; for(int i=32; i<127; i++) { char c=(char)i; string str=""+c; Graphic characterMap=new Graphic(8, 13, Format.RGB); //System.Drawing.Graphics g=System.Drawing.Graphics.FromImage(characterMap); characterMap.Fill(System.Drawing.Color.White); //characterMap.Rendertex Graphic mytext=Graphic.RenderText(new System.Drawing.Font("Courier New", 10), str, System.Drawing.Color.Blue); characterMap.Draw(-2, -2, mytext); int tmp=ComputeDistance(characterMap, new System.Drawing.Rectangle(0, 0, (int)characterMap.Width, (int)characterMap.Height), edgeMap, new System.Drawing.Rectangle(x, y, (int)characterMap.Width, (int)characterMap.Height)); if(tmp<minDistance) { minDistance=tmp; minChar=c; } } output+=minChar; } output+="\r\n"; } return output; }
static void SaveFeatureMapMusic(string filename, Graphic img, TMX map) { //Farben Color green=Color.FromArgb(128, 0, 255, 0); //Color yellow=Color.FromArgb(128, 255, 255, 0); Color red=Color.FromArgb(128, 255, 0, 0); //Color blue=Color.FromArgb(128, 0, 0, 255); //Images Graphic tmpImage=img.GetImage(); Graphic tmpDraw=new Graphic(tmpImage.Width, tmpImage.Height, tmpImage.ChannelFormat); //Properties durchsuchen bool found=false; foreach(Property prop in map.Properties) { if(prop.Name=="music") { found=true; break; } } if(found) tmpDraw.Fill(green); else tmpDraw.Fill(red); //Drawen tmpImage.Draw(0, 0, tmpDraw, true); tmpImage.SaveToFile(filename); }
public Graphic ConvertToBGRA() { if(channelFormat==Format.BGRA) return this; Graphic ret=new Graphic(width, height, Format.BGRA); if(ret.imageData==null) return ret; uint count=width*height; byte[] src=imageData; uint ind=0; byte[] dst=ret.imageData; uint inds=0; switch(channelFormat) { case Format.GRAY: for(uint i=0; i<count; i++) { byte g=src[inds++]; dst[ind++]=g; dst[ind++]=g; dst[ind++]=g; dst[ind++]=255; } break; case Format.GRAYAlpha: for(uint i=0; i<count; i++) { byte g=src[inds++]; dst[ind++]=g; dst[ind++]=g; dst[ind++]=g; dst[ind++]=src[inds++]; } break; case Format.RGB: for(uint i=0; i<count; i++) { byte r=src[inds++]; byte g=src[inds++]; dst[ind++]=src[inds++]; dst[ind++]=g; dst[ind++]=r; dst[ind++]=255; } break; case Format.RGBA: for(uint i=0; i<count; i++) { byte r=src[inds++]; byte g=src[inds++]; dst[ind++]=src[inds++]; dst[ind++]=g; dst[ind++]=r; dst[ind++]=src[inds++]; } break; case Format.BGR: for(uint i=0; i<count; i++) { dst[ind++]=src[inds++]; dst[ind++]=src[inds++]; dst[ind++]=src[inds++]; dst[ind++]=255; } break; } return ret; }
/// <summary> /// Invertiert den Alphakanal /// </summary> /// <returns></returns> public Graphic InvertAlpha() { if (channelFormat!=Format.RGBA&&channelFormat!=Format.BGRA&&channelFormat!=Format.GRAYAlpha) return this; Graphic ret=new Graphic(width, height, channelFormat); if (ret.imageData==null) return ret; uint count=width*height*BytePerPixel; if (channelFormat==Format.BGRA||channelFormat==Format.RGBA) { for (uint i=0; i<count; i+=4) { ret.imageData[i]=(byte)(imageData[i]); ret.imageData[i+1]=(byte)(imageData[i+1]); ret.imageData[i+2]=(byte)(imageData[i+2]); ret.imageData[i+3]=(byte)(255-imageData[i+3]); } } else if (channelFormat==Format.GRAYAlpha) { for (uint i=0; i<count; i+=2) { ret.imageData[i]=(byte)(imageData[i]); ret.imageData[i+1]=(byte)(255-imageData[i+1]); } } return ret; }
///////////////////////////////////////////////////////////////// // noch mehr Bildverarbeitung ///////////////////////////////////////////////////////////////// public double Compare(Graphic ImageToCompare, uint Threshold) { if(ImageToCompare==null) throw new Exception("Image is null"); if(Width!=ImageToCompare.Width) throw new Exception("Image have different sizes"); if(Height!=ImageToCompare.Height) throw new Exception("Image have different sizes"); if(channelFormat!=ImageToCompare.channelFormat) throw new Exception("Image have different formats"); uint divergency=0; for(uint y=0; y<Width; y++) { for(uint x=0; x<Height; x++) { Color picA=GetPixel(x, y); Color picB=ImageToCompare.GetPixel(x, y); int dif=0; dif+=System.Math.Abs(picA.R-picB.R); dif+=System.Math.Abs(picA.G-picB.G); dif+=System.Math.Abs(picA.B-picB.B); dif/=3; if(dif>Threshold) divergency++; } } //Gibt in % zurück wie stark die Bilder von einander abweichen //0 % == Bilder sind Identisch return (double)(100*(divergency/(double)(Width*Height))); }
private Graphic Render(int width, int height, string onlyLayer) { Graphic ret=new Graphic((uint)width, (uint)height, Format.RGBA); ret=ret.InvertAlpha(); foreach(LayerData i in Layers) { if(onlyLayer=="") { if(i.name=="Collision") continue; //Collision Layer überspringen } else { if(i.name!=onlyLayer) continue; } //Für jedes Tile in X bzw Y Richtung for(int y=0;y<i.height;y++) { for(int x=0;x<i.width;x++) { int number=i.data[x, y]; if(number<=0) continue; //Kein Tile zugewiesen //TODO was genau meint eine Zahl kleiner 0 genau Graphic Tile=GetTile(number); //Korrekturfaktor für Tiles welche breiter bzw. //höher sind als normal int CorFactorX=0; //Korrekturfaktor für x wird nicht benötigt (denke ich) //int CorFactorX=(int)(Tile.Width-TileWidth); int CorFactorY=(int)(Tile.Height-TileHeight); ret.Draw(x*TileWidth-CorFactorX, y*TileHeight-CorFactorY, Tile, true); } } } return ret; }
Graphic NearestPixelResizeH(uint w) { double delta=(double)width/w; uint bpp=BytePerPixel; uint[] dx=new uint[w]; for(uint x=0; x<w; x++) dx[x]=(uint)(x*delta+delta/2); if(bpp==1) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; uint dst=0; for(uint y=0; y<height; y++) { uint src=y*width; for(uint x=0; x<w; x++) ret.imageData[dst++]=imageData[src+dx[x]]; } return ret; } if(bpp==4) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; uint bw=width*4; uint dst=0; for(uint y=0; y<height; y++) { uint src=y*bw; for(uint x=0; x<w; x++) { uint s=src+dx[x]*4; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s]; } } return ret; } if(bpp==3) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; uint bw=width*3; uint dst=0; for(uint y=0; y<height; y++) { uint src=y*bw; for(uint x=0; x<w; x++) { uint s=src+dx[x]*3; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s]; } } return ret; } if(bpp==2) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; uint bw=width*2; uint dst=0; for(uint y=0; y<height; y++) { uint src=y*bw; for(uint x=0; x<w; x++) { uint s=src+dx[x]*2; ret.imageData[dst++]=imageData[s++]; ret.imageData[dst++]=imageData[s]; } } return ret; } return new Graphic(0, 0, channelFormat); }
public static Graphic FromTGAFile(string filename) { Graphic ret=null; using(FileStream fs=new FileStream(filename, FileMode.Open, FileAccess.Read)) { uint fsize=(uint)fs.Length; if(fsize<19) throw new EndOfStreamException("File to small to be a Truevision Image."); BinaryReader br=new BinaryReader(fs); // Read Header (18 bytes) byte ID_Length=br.ReadByte(); byte Color_Map_Type=br.ReadByte(); byte Image_Type=br.ReadByte(); ushort First_Entry_Index=br.ReadUInt16(); ushort Color_Map_Length=br.ReadUInt16(); byte Color_Map_Entry_Size=br.ReadByte(); ushort X_Origin=br.ReadUInt16(); ushort Y_Origin=br.ReadUInt16(); ushort Width=br.ReadUInt16(); ushort Height=br.ReadUInt16(); byte Pixel_Depth=br.ReadByte(); byte Image_Descriptor=br.ReadByte(); // Offsets //uint pImage_ID=0; uint pImage_Data=0; uint pColor_Map_Data=0; uint pDeveloper_Directory=0; uint pExtension_Area=0; uint pScan_Line_Table=0; // *Field 25 == Field 23 // Height*4 bytes // Vars uint width=0, height=0; uint bpp=0; // 8 | 16 | 24 | 32 bool isAlpha=false; bool hor_flipped=false, ver_flipped=false, rle=false; uint[] scan_line_table; //if(ID_Length!=0) // pImage_ID=18; pImage_Data=18u+ID_Length; if(Color_Map_Type!=0) { pColor_Map_Data=18u+ID_Length; if(Color_Map_Length==0) throw new Exception("Color Map Type=1, but Length=0."); if(Color_Map_Entry_Size==15||Color_Map_Entry_Size==16) pImage_Data+=Color_Map_Length*2u; else if(Color_Map_Entry_Size==24) pImage_Data+=Color_Map_Length*3u; else if(Color_Map_Entry_Size==32) pImage_Data+=Color_Map_Length*4u; else throw new Exception("Illegal Color Map Entry Size."); } rle=false; switch(Image_Type) { case 10: { rle=true; if(Pixel_Depth==16) bpp=2; else if(Pixel_Depth==24) bpp=3; else if(Pixel_Depth==32) { bpp=4; isAlpha=true; } else throw new Exception("Illegal or unsupported Pixel Depth (RGB)."); } break; case 2: { if(Pixel_Depth==16) bpp=2; else if(Pixel_Depth==24) bpp=3; else if(Pixel_Depth==32) { bpp=4; isAlpha=true; } else throw new Exception("Illegal or unsupported Pixel Depth (RGB)."); } break; case 9: { rle=true; if(Pixel_Depth==8) bpp=1; else if(Pixel_Depth==16) { bpp=2; isAlpha=true; } else throw new Exception("Illegal or unsupported Pixel Depth (GRAY)."); } break; case 11: { rle=true; if(Pixel_Depth==8) bpp=1; else if(Pixel_Depth==16) { bpp=2; isAlpha=true; } else throw new Exception("Illegal or unsupported Pixel Depth (GRAY)."); } break; case 1: { if(Pixel_Depth==8) bpp=1; else if(Pixel_Depth==16) { bpp=2; isAlpha=true; } else throw new Exception("Illegal or unsupported Pixel Depth (GRAY)."); } break; case 3: { if(Pixel_Depth==8) bpp=1; else if(Pixel_Depth==16) { bpp=2; isAlpha=true; } else throw new Exception("Illegal or unsupported Pixel Depth (GRAY)."); } break; default: throw new Exception("Illegal or unsupported Image Type."); } if(Width==0) throw new Exception("Illegal Image Width."); if(Height==0) throw new Exception("Illegal Image Height."); width=Width; height=Height; if((Image_Descriptor&0x0F)!=(isAlpha?8:0)) throw new Exception("Illegal Alpha Channel Bits Count."); if((Image_Descriptor&0xC0)!=0) throw new Exception("Unsed Bits in Image Description not zero."); hor_flipped=(Image_Descriptor&0x20)!=0; ver_flipped=(Image_Descriptor&0x10)!=0; // checken ob pImage_Data-Offsets in File if((pImage_Data+height)>=fsize) throw new Exception("File to small to fold the complete Image Data."); // Extension Format fs.Seek(fsize-26, SeekOrigin.Begin); pExtension_Area=br.ReadUInt32(); pDeveloper_Directory=br.ReadUInt32(); String sig=br.ReadChars(17).ToString(); scan_line_table=new uint[height]; if(sig=="TRUEVISION-XFILE.") // in der Hoffung, dass nicht zufällig { // diese Zeichenfolge in der Pixeldaten steht if(pExtension_Area!=0) { fs.Seek(pExtension_Area, SeekOrigin.Begin); pScan_Line_Table=0; ushort Extension_Size=br.ReadUInt16(); if(Extension_Size>=495) { fs.Seek(pExtension_Area+490, SeekOrigin.Begin); pScan_Line_Table=br.ReadUInt32(); } if(pScan_Line_Table!=0) { fs.Seek(pScan_Line_Table, SeekOrigin.Begin); for(int i=0; i<height; i++) scan_line_table[i]=br.ReadUInt32(); } } } else pExtension_Area=pDeveloper_Directory=0; if(pScan_Line_Table==0) { if(!rle) { for(uint i=0; i<height; i++) scan_line_table[i]=pImage_Data+i*width*bpp; } else { fs.Seek(pImage_Data, SeekOrigin.Begin); for(uint i=0; i<height; i++) { scan_line_table[i]=(uint)fs.Position; uint internalwidth=0; while(width>internalwidth) { try { byte ph=br.ReadByte(); uint count=(uint)((ph&0x7F)+1); if((ph&0x80)>0) { // rle packet if(br.ReadBytes((int)bpp).Length<bpp) throw new Exception("Error reading rle-packed Image Data."); } else { // raw packet if(br.ReadBytes((int)(count*bpp)).Length<(count*bpp)) throw new Exception("Error reading rle-packed Image Data."); } internalwidth+=count; } catch(Exception) { throw new EndOfStreamException("Error reading rle-packed Image Data."); } } if(internalwidth>width) throw new Exception("Error reading rle-packed Image Data. (Line too long.)"); } } } uint bpp_=bpp; if(!isAlpha&&bpp==2) bpp_=3; // RGB24 statt RGB15 uint lineLen=width*bpp_; byte[] bits=new byte[height*lineLen]; //for(int i=0; i<lineLen*height; i++) bits[i]=0; // Ziel säubern for(uint y=0; y<height; y++) { uint p=y*lineLen; uint dest=p; uint end=width; if(ver_flipped) dest-=(width+1)*bpp_; uint startOfLine; if(hor_flipped) startOfLine=scan_line_table[y]; else startOfLine=scan_line_table[height-y-1]; if(!rle) { uint blocksize=end*bpp; fs.Seek(startOfLine, SeekOrigin.Begin); byte[] buffer=br.ReadBytes((int)blocksize); if(buffer.Length<blocksize) throw new EndOfStreamException(); int ind=0; for(uint myX=0; myX<end; myX++) { if(bpp<3) { // 8 oder 16 Bit if(bpp==1||isAlpha) {// GRAY8 bits[dest++]=buffer[ind++]; if(isAlpha) bits[dest++]=buffer[ind++]; } else { ushort w1=buffer[ind++]; ushort w2=buffer[ind++]; ushort w=(ushort)((w2<<8)&w1); ushort r=(ushort)(w&0x7c00); r>>=7; ushort g=(ushort)(w&0x03e0); g>>=2; ushort b=(ushort)(w&0x001f); b<<=3; bits[dest++]=(byte)b; bits[dest++]=(byte)g; bits[dest++]=(byte)r; } } else { bits[dest++]=buffer[ind++]; bits[dest++]=buffer[ind++]; bits[dest++]=buffer[ind++]; if(bpp>3) bits[dest++]=buffer[ind++]; } if(ver_flipped) dest-=2*bpp_; } } else { fs.Seek(startOfLine, SeekOrigin.Begin); byte[] buffer=new byte[width*bpp]; uint ind=0; uint internalwidth=0; while(width>internalwidth) { try { byte ph=br.ReadByte(); uint count=(uint)((ph&0x7F)+1); if((ph&0x80)>0) { // rle packet byte[] tbuffer=br.ReadBytes((int)bpp); if(tbuffer.Length<bpp) throw new Exception("Error reading rle-packed Image Data."); for(uint i=0; i<count; i++) { tbuffer.CopyTo(buffer, ind); ind+=bpp; } } else { // raw packet byte[] tbuffer=br.ReadBytes((int)(count*bpp)); if(tbuffer.Length<(count*bpp)) throw new Exception("Error reading rle-packed Image Data."); tbuffer.CopyTo(buffer, ind); ind+=count*bpp; } internalwidth+=count; } catch(Exception) { throw new EndOfStreamException("Error reading rle-packed Image Data."); } } if(internalwidth>width) throw new EndOfStreamException("Error reading rle-packed Image Data. (Line too long.)"); ind=0; for(uint myX=0; myX<end; myX++) { if(bpp<3) { // 8 oder 16 Bit if(bpp==1||isAlpha) {// GRAY8 bits[dest++]=buffer[ind++]; if(isAlpha) bits[dest++]=buffer[ind++]; } else { ushort w1=buffer[ind++]; ushort w2=buffer[ind++]; ushort w=(ushort)((w2<<8)&w1); ushort r=(ushort)(w&0x7c00); r>>=7; ushort g=(ushort)(w&0x03e0); g>>=2; ushort b=(ushort)(w&0x001f); b<<=3; bits[dest++]=(byte)b; bits[dest++]=(byte)g; bits[dest++]=(byte)r; } } else { bits[dest++]=buffer[ind++]; bits[dest++]=buffer[ind++]; bits[dest++]=buffer[ind++]; if(bpp>3) bits[dest++]=buffer[ind++]; } if(ver_flipped) dest-=2*bpp_; } } } ret=new Graphic(); switch(bpp_) { case 1: ret.channelFormat=Format.GRAY; break; case 2: ret.channelFormat=Format.GRAYAlpha; break; case 3: ret.channelFormat=Format.RGB; break; case 4: ret.channelFormat=Format.RGBA; break; default: ret.channelFormat=Format.GRAY; break; } ret.imageData=bits; ret.width=width; ret.height=height; br.Close(); fs.Close(); } // using(br) return ret; }
public void Draw(int x, int y, Graphic source, bool considerAlpha) { if(!considerAlpha||source.channelFormat==Format.BGR|| source.channelFormat==Format.RGB||source.channelFormat==Format.GRAY) { Draw(x, y, source); return; } if(x>=width||y>=height) throw new ArgumentOutOfRangeException("x or y", "Out of image."); if(x+source.width<0||y+source.height<0) throw new ArgumentOutOfRangeException("x or y", "Out of image."); Graphic srcimg=null; switch(channelFormat) { case Format.GRAY: srcimg=source.ConvertToGrayAlpha(); break; case Format.GRAYAlpha: srcimg=source.ConvertToGrayAlpha(); break; case Format.RGB: srcimg=source.ConvertToRGBA(); break; case Format.RGBA: srcimg=source.ConvertToRGBA(); break; case Format.BGR: srcimg=source.ConvertToBGRA(); break; case Format.BGRA: srcimg=source.ConvertToBGRA(); break; } uint bpp=ConvertToBytePerPixel(source.channelFormat); unsafe { fixed(byte* src_=srcimg.imageData, dst_=imageData) { uint start=(uint)System.Math.Max(-x, 0); uint end=(uint)System.Math.Min(source.width, width-x); uint jstart=(uint)System.Math.Max(-y, 0); uint jend=(uint)System.Math.Min(source.height, height-y); if(channelFormat==Format.BGR||channelFormat==Format.RGB||channelFormat==Format.GRAY) { uint dbpp=ConvertToBytePerPixel(channelFormat); byte* src__=src_+start*bpp; byte* dst__=dst_+x*dbpp+start*dbpp; uint sw=source.width*bpp; uint dw=width*dbpp; if(channelFormat==Format.BGR||channelFormat==Format.RGB) { for(uint j=jstart; j<jend; j++) { byte* src=src__+sw*j; byte* dst=dst__+dw*(y+j); for(uint i=start; i<end; i++) { byte sr=*src++; byte sg=*src++; byte sb=*src++; byte sa=*src++; if(sa!=0) { byte dr=*dst++; byte dg=*dst++; byte db=*dst++; dst-=3; double a2=sa/255.0; double a1=1-a2; *dst++=(byte)(dr*a1+sr*a2); *dst++=(byte)(dg*a1+sg*a2); *dst++=(byte)(db*a1+sb*a2); } else dst+=3; } } } else // GRAY { for(uint j=jstart; j<jend; j++) { byte* src=src__+sw*j; byte* dst=dst__+dw*(y+j); for(uint i=start; i<end; i++) { byte sg=*src++; byte sa=*src++; if(sa!=0) { byte dg=*dst; double a2=sa/255.0; double a1=1-a2; *dst++=(byte)(dg*a1+sg*a2); } else dst++; } } } // end if RGB || BGR } else // 2x Alpha-Bild { byte* src__=src_+start*bpp; byte* dst__=dst_+x*bpp+start*bpp; uint sw=source.width*bpp; uint dw=width*bpp; if(channelFormat==Format.BGRA||channelFormat==Format.RGBA) { for(uint j=jstart; j<jend; j++) { byte* src=src__+sw*j; byte* dst=dst__+dw*(y+j); for(uint i=start; i<end; i++) { byte sr=*src++; byte sg=*src++; byte sb=*src++; byte sa=*src++; if(sa!=0) { byte dr=*dst++; byte dg=*dst++; byte db=*dst++; byte da=*dst++; dst-=4; double a2=sa/255.0; double a1=1-a2; *dst++=(byte)(dr*a1+sr*a2); *dst++=(byte)(dg*a1+sg*a2); *dst++=(byte)(db*a1+sb*a2); *dst++=da; } else dst+=4; } } } else // GRAYALPHA { for(uint j=jstart; j<jend; j++) { byte* src=src__+sw*j; byte* dst=dst__+dw*(y+j); for(uint i=start; i<end; i++) { byte sg=*src++; byte sa=*src++; if(sa!=0) { byte dg=*dst++; byte da=*dst++; dst-=2; double a2=sa/255.0; double a1=1-a2; *dst++=(byte)(dg*a1+sg*a2); *dst++=da; } else dst+=2; } } } // end if RGBA || BGRA } // end if 2x Alpha-Bild } // fixed } // unsafe }
public Graphic GetSubImage(uint x, uint y, uint w, uint h) { if(x>=width||y>=height) throw new ArgumentOutOfRangeException("x or y", "Out of image."); Graphic ret=new Graphic(w, h, channelFormat); ret.Draw(-(int)x, -(int)y, this); return ret; }
Graphic ReduceByV(uint n) { if((width*height)==0) return new Graphic(0, 0, channelFormat); uint h=height/n; if(channelFormat==Format.GRAY) { Graphic ret=new Graphic(width, h, channelFormat); if(ret.imageData==null) return ret; for(uint x=0; x<width; x++) { byte[] dst=ret.imageData; uint ind=x; byte[] src=imageData; uint inds=x; for(uint y=0; y<h; y++) { uint sum=0; for(uint z=0; z<n; z++) { sum+=src[inds]; inds+=width; } dst[ind]=(byte)(sum/n); ind+=width; } } return ret; } if(channelFormat==Format.RGB||channelFormat==Format.BGR) { Graphic ret=new Graphic(width, h, channelFormat); if(ret.imageData==null) return ret; uint wb=3*width-2; for(uint x=0; x<width; x++) { byte[] dst=ret.imageData; uint ind=x*3; byte[] src=imageData; uint inds=x*3; for(uint y=0; y<h; y++) { uint sumr=0, sumg=0, sumb=0; for(uint z=0; z<n; z++) { sumr+=src[inds++]; sumg+=src[inds++]; sumb+=src[inds]; inds+=wb; } dst[ind++]=(byte)(sumr/n); dst[ind++]=(byte)(sumg/n); dst[ind]=(byte)(sumb/n); ind+=wb; } } return ret; } if(channelFormat==Format.RGBA||channelFormat==Format.BGRA) { Graphic ret=new Graphic(width, h, channelFormat); if(ret.imageData==null) return ret; uint wb=4*width-3; for(uint x=0; x<width; x++) { byte[] dst=ret.imageData; uint ind=x*4; byte[] src=imageData; uint inds=x*4; for(uint y=0; y<h; y++) { uint sumr=0, sumg=0, sumb=0, suma=0; for(uint z=0; z<n; z++) { byte r=src[inds++]; byte g=src[inds++]; byte b=src[inds++]; uint a=src[inds]; inds+=wb; sumr+=r*a; sumg+=g*a; sumb+=b*a; suma+=a; } if(suma==0) { dst[ind++]=0; dst[ind++]=0; dst[ind++]=0; dst[ind]=0; } else { dst[ind++]=(byte)(sumr/suma); dst[ind++]=(byte)(sumg/suma); dst[ind++]=(byte)(sumb/suma); dst[ind]=(byte)(suma/n); } ind+=wb; } } return ret; } if(channelFormat==Format.GRAYAlpha) { Graphic ret=new Graphic(width, h, channelFormat); if(ret.imageData==null) return ret; uint wb=2*width-1; for(uint x=0; x<width; x++) { byte[] dst=ret.imageData; uint ind=x*2; byte[] src=imageData; uint inds=x*2; for(uint y=0; y<h; y++) { uint sumg=0, suma=0; for(uint z=0; z<n; z++) { byte g=src[inds++]; uint a=src[inds]; inds+=wb; sumg+=g*a; suma+=a; } if(suma==0) { dst[ind++]=0; dst[ind]=0; } else { dst[ind++]=(byte)(sumg/suma); dst[ind]=(byte)(suma/n); } ind+=wb; } } return ret; } return new Graphic(0, 0, channelFormat); }
public static Graphic FromBMPFile(string filename) { #region Variablen // Header int bfSize; // Größe der BMP-Datei in Byte. (unzuverlässig) int bfOffBits; // Offset der Bilddaten in Byte vom Beginn der Datei an. // Infoblock uint biSize; // Größe des Informationsblocks in Byte int biWidth; // Breite der Bitmap in Pixel. int biHeight; // Höhe der Bitmap in Pixel short biPlanes; // Bei PCX die Anzahl der Farbebenen bei BMP nicht verwendet (immer 1) short biBitCount; // Farbtiefe (1, 4, 8, 16, 24, 32 Bit) BMPBiCompression biCompression; // Compressionsmethod uint biSizeImage; // Größe der Bilddaten (oder 0) int biXPelsPerMeter; // Horizontale Auflösung des Zielausgabegerätes in Pixel pro Meter int biYPelsPerMeter; // Vertikale Auflösung des Zielausgabegerätes in Pixel pro Meter uint biClrUsed; // Colors uint biClrImportant; // Important Color // Weitere Dinge für den Infoblock uint bmRed=0; // Farbmaske Rot uint bmGreen=0; // Farbmaske Grün uint bmBlue=0; // Farbmaske Blau uint bmAlpha=0; // Farbmaske Alpha // Farbtabelle List<Color> ColorTable=new List<Color>(); #endregion // Datei öffnen BinaryReader fileReader=new BinaryReader(File.OpenRead(filename)); try { #region Header auslesen byte[] buffer=new byte[2]; fileReader.Read(buffer, 0, 2); if(buffer[0]!='B'&&buffer[0]!='M') return new Graphic(); // Signatur überprüfen bfSize=fileReader.ReadInt32(); // (unzuverlässig) fileReader.BaseStream.Seek(10, SeekOrigin.Begin); // bfReserved überspringen bfOffBits=fileReader.ReadInt32(); #endregion #region Informationsblock biSize=fileReader.ReadUInt32(); // 108: Typ Windows V4 wird nicht unterstützt // 124: Typ Windows V5 wird nicht unterstützt if(biSize==12) { // OS/2 1.x biWidth=fileReader.ReadInt16(); biHeight=fileReader.ReadInt16(); biPlanes=fileReader.ReadInt16(); biBitCount=fileReader.ReadInt16(); // Fest definiert biCompression=BMPBiCompression.BI_RGB; biSizeImage=(uint)(bfSize-26); biXPelsPerMeter=2835; // 1000 DPI biYPelsPerMeter=2835; // 1000 DPI if(biBitCount==1||biBitCount==4||biBitCount==8) { int CountColors=1<<biBitCount; // 2^biBitCount for(int i=0; i<CountColors; i++) { byte blue=fileReader.ReadByte(); byte green=fileReader.ReadByte(); byte red=fileReader.ReadByte(); ColorTable.Add(Color.FromArgb(red, green, blue)); } } else if(biBitCount==16||biBitCount==24||biBitCount==32) { // nix } else return new Graphic(); } else if(biSize==40||biSize==56||biSize==64) { // 40: Windows 3.1x, 95, NT // 56: Adobe Photoshop BMP mit Bitmaske (nicht Standardkonform?) // 64: OS/2 2.x (weitere Bytes werden einfach ignoriert) biWidth=fileReader.ReadInt32(); biHeight=fileReader.ReadInt32(); biPlanes=fileReader.ReadInt16(); biBitCount=fileReader.ReadInt16(); biCompression=(BMPBiCompression)fileReader.ReadUInt32(); biSizeImage=fileReader.ReadUInt32(); biXPelsPerMeter=fileReader.ReadInt32(); biYPelsPerMeter=fileReader.ReadInt32(); biClrUsed=fileReader.ReadUInt32(); biClrImportant=fileReader.ReadUInt32(); // 56 Byte Header ist ein 40 Byte Header + BitFields (16 byte): fehlerhaft geschrieben von Adobe PhotoShop if(biSize==64) fileReader.BaseStream.Seek(24, SeekOrigin.Current); // Rest des OS/2 2.x Headers if(biBitCount==16||biBitCount==24||biBitCount==32) { if(biCompression==BMPBiCompression.BI_BITFIELDS&&(biBitCount==16||biBitCount==32)) { bmRed=fileReader.ReadUInt32(); bmGreen=fileReader.ReadUInt32(); bmBlue=fileReader.ReadUInt32(); } if(biCompression==BMPBiCompression.BI_ALPHABITFIELDS&&(biBitCount==16||biBitCount==32)) { bmRed=fileReader.ReadUInt32(); bmGreen=fileReader.ReadUInt32(); bmBlue=fileReader.ReadUInt32(); bmAlpha=fileReader.ReadUInt32(); // ich hoffe mal, dass der Alpha am Anfang ist } } else if(biBitCount==1||biBitCount==4||biBitCount==8) { uint CountColors=biClrUsed; if(biClrUsed==0) CountColors=1u<<biBitCount; // 2^biBitCount for(uint i=0; i<CountColors; i++) { byte blue=fileReader.ReadByte(); byte green=fileReader.ReadByte(); byte red=fileReader.ReadByte(); fileReader.BaseStream.Seek(1, SeekOrigin.Current); ColorTable.Add(Color.FromArgb(red, green, blue)); } } else return new Graphic(); } else return new Graphic(); // Konsistenz Check if(biPlanes!=1||biWidth<=0||biHeight==0) return new Graphic(); if(biBitCount!=16&&biBitCount!=32&&(biCompression==BMPBiCompression.BI_ALPHABITFIELDS|| biCompression==BMPBiCompression.BI_BITFIELDS)) return new Graphic(); // Fall auf Standardbehandlung zurück, wenn Bitfields dem Standardfällen entsprechen if(biCompression==BMPBiCompression.BI_BITFIELDS) { if(biBitCount==32&&bmRed==0xFF0000&&bmGreen==0xFF00&&bmBlue==0xFF) biCompression=BMPBiCompression.BI_RGB; } if(biCompression==BMPBiCompression.BI_ALPHABITFIELDS) { if(biBitCount==32&&bmRed==0xFF0000&&bmGreen==0xFF00&&bmBlue==0xFF&&bmAlpha==0xFF000000) biCompression=BMPBiCompression.BI_RGB; } int absHeight=System.Math.Abs(biHeight); #endregion #region pImage anlegen Graphic ret; if(biBitCount==32||(biBitCount==16&&(biCompression==BMPBiCompression.BI_ALPHABITFIELDS|| biCompression==BMPBiCompression.BI_BITFIELDS))) ret=new Graphic((uint)biWidth, (uint)absHeight, Format.RGBA); else //Andere Bildern ret=new Graphic((uint)biWidth, (uint)absHeight, Format.RGB); #endregion #region Bilddaten in pImage einlesen fileReader.BaseStream.Seek(bfOffBits, SeekOrigin.Begin); // zu Bilddaten springen if(biCompression==BMPBiCompression.BI_RGB) { #region Unkomprimierte Bilddaten if(biBitCount==1) // 1 Bit { #region 1 Bit int BytesPerRow=(int)Align((uint)(biWidth+7)/8, 4); int ind=0; buffer=new byte[BytesPerRow]; while(ColorTable.Count<2) ColorTable.Add(Color.Black); if(biHeight>0) // buttom-up Bild { for(int i=absHeight-1; i>=0; i--) { ind=i*biWidth*3; fileReader.Read(buffer, 0, buffer.Length); byte pixel=0; for(int a=0; a<biWidth; a++) { if(a%8==0) pixel=buffer[a/8]; int bit=(pixel&0x80)==0x80?1:0; ret.imageData[ind++]=ColorTable[bit].B; ret.imageData[ind++]=ColorTable[bit].G; ret.imageData[ind++]=ColorTable[bit].R; pixel<<=1; } } } else if(biHeight<0) // top-down Bild { for(int i=0; i<absHeight; i++) { fileReader.Read(buffer, 0, buffer.Length); byte pixel=0; for(int a=0; a<biWidth; a++) { if(a%8==0) pixel=buffer[a/8]; int bit=(pixel&0x80)==0x80?1:0; ret.imageData[ind++]=ColorTable[bit].B; ret.imageData[ind++]=ColorTable[bit].G; ret.imageData[ind++]=ColorTable[bit].R; pixel<<=1; } } } #endregion } else if(biBitCount==4) // 4 Bit { #region 4 Bit int BytesPerRow=(int)Align((uint)(biWidth*4+7)/8, 4); int ind=0; buffer=new byte[BytesPerRow]; while(ColorTable.Count<16) ColorTable.Add(Color.Black); if(biHeight>0) // buttom-up Bild { for(int i=absHeight-1; i>=0; i--) { ind=i*biWidth*3; fileReader.Read(buffer, 0, buffer.Length); byte pixel=0; for(int a=0; a<biWidth; a++) { if(a%2==0) pixel=buffer[a/2]; int bit=(pixel&0xF0)>>4; ret.imageData[ind++]=ColorTable[bit].B; ret.imageData[ind++]=ColorTable[bit].G; ret.imageData[ind++]=ColorTable[bit].R; pixel<<=4; } } } else if(biHeight<0) // top-down Bild { for(int i=0; i<absHeight; i++) { fileReader.Read(buffer, 0, buffer.Length); byte pixel=0; for(int a=0; a<biWidth; a++) { if(a%2==0) pixel=buffer[a/2]; int bit=(pixel&0xF0)>>4; ret.imageData[ind++]=ColorTable[bit].B; ret.imageData[ind++]=ColorTable[bit].G; ret.imageData[ind++]=ColorTable[bit].R; pixel<<=4; } } } #endregion } else if(biBitCount==8) // 8 Bit { #region 8 Bit int BytesPerRow=(int)Align((uint)biWidth, 4); int ind=0; buffer=new byte[BytesPerRow]; while(ColorTable.Count<256) ColorTable.Add(Color.Black); if(biHeight>0) // buttom-up Bild { for(int i=absHeight-1; i>=0; i--) { ind=i*biWidth*3; fileReader.Read(buffer, 0, buffer.Length); for(int a=0; a<biWidth; a++) { byte pixel=buffer[a]; ret.imageData[ind++]=ColorTable[pixel].B; ret.imageData[ind++]=ColorTable[pixel].G; ret.imageData[ind++]=ColorTable[pixel].R; } } } else if(biHeight<0) // top-down Bild { for(int i=0; i<absHeight; i++) { fileReader.Read(buffer, 0, buffer.Length); for(int a=0; a<biWidth; a++) { byte pixel=buffer[a]; ret.imageData[ind++]=ColorTable[pixel].B; ret.imageData[ind++]=ColorTable[pixel].G; ret.imageData[ind++]=ColorTable[pixel].R; } } } #endregion } else if(biBitCount==16) // 16 Bit { #region 16 Bit int BytesPerRow=(biWidth*2); int rest=(int)(Align((uint)BytesPerRow, 4)-BytesPerRow); int ind=0; buffer=new byte[BytesPerRow]; if(biHeight>0) // buttom-up Bild { for(int i=absHeight-1; i>=0; i--) { ind=i*biWidth*3; fileReader.Read(buffer, 0, buffer.Length); for(int a=0; a<biWidth; a++) { byte pixelA=buffer[a*2]; byte pixelB=buffer[a*2+1]; int b=(pixelA&0x1F)<<3; int g=((pixelB&0x3)<<6)+((pixelA&0xE0)>>2); int r=(pixelB&0x7C)<<1; ret.imageData[ind++]=(byte)(b+b/32); ret.imageData[ind++]=(byte)(g+g/32); ret.imageData[ind++]=(byte)(r+r/32); } } } else if(biHeight<0) // top-down Bild { for(int i=absHeight-1; i>=0; i--) { fileReader.Read(buffer, 0, buffer.Length); for(int a=0; a<biWidth; a++) { byte pixelA=buffer[a*2]; byte pixelB=buffer[a*2+1]; int b=(pixelA&0x1F)<<3; int g=((pixelB&0x3)<<6)+((pixelA&0xE0)>>2); int r=(pixelB&0x7C)<<1; ret.imageData[ind++]=(byte)(b+b/32); ret.imageData[ind++]=(byte)(g+g/32); ret.imageData[ind++]=(byte)(r+r/32); } } } #endregion } else if(biBitCount==24) // 24 Bit { #region 24 Bit int BytesPerRow=(biWidth*3); int rest=(int)(Align((uint)BytesPerRow, 4)-BytesPerRow); if(biHeight>0) // buttom-up Bild { for(int i=0; i<absHeight; i++) { fileReader.Read(ret.imageData, ret.imageData.Length-(i+1)*BytesPerRow, BytesPerRow); if(rest!=0) fileReader.BaseStream.Seek(rest, SeekOrigin.Current); } } else if(biHeight<0) // top-down Bild { if(rest==0) { fileReader.Read(ret.imageData, 0, BytesPerRow*absHeight); // ganze bild auf einmal laden } else { for(int i=0; i<absHeight; i++) { fileReader.Read(ret.imageData, i*BytesPerRow, BytesPerRow); if(rest!=0) fileReader.BaseStream.Seek(rest, SeekOrigin.Current); } } } #endregion } else if(biBitCount==32) // 32 Bit { #region 32 Bit int BytesPerRow=(biWidth*4); buffer=new byte[BytesPerRow]; if(biHeight>0) // buttom-up Bild { for(int i=0; i<absHeight; i++) { fileReader.Read(ret.imageData, ret.imageData.Length-(i+1)*BytesPerRow, BytesPerRow); } } else if(biHeight<0) // top-down Bild { fileReader.Read(ret.imageData, 0, BytesPerRow*absHeight); // ganze bild auf einmal laden } #endregion } #endregion Unkomprimierte Bilddaten } else if(biCompression==BMPBiCompression.BI_RLE8) // RLE 8 Kodierte Daten { #region RLE 8 if(biBitCount!=8) return new Graphic(); // nur 8 Bit Bilder erlaubt int BytesPerRow=(int)Align((uint)biWidth, 4); int rest=BytesPerRow-biWidth; byte[] bufferRLE=new byte[absHeight*BytesPerRow]; int index=0; int lineCount=0; while(ColorTable.Count<256) ColorTable.Add(Color.Black); #region Dekomprimiere RLE 8 while(fileReader.BaseStream.Position<fileReader.BaseStream.Length&&index<(absHeight*BytesPerRow)) { if(rest!=0&&(index/BytesPerRow)!=lineCount) throw new Exception("Bad RLE 8 coding."); if(rest==0&&(index/BytesPerRow)!=lineCount) if(index>BytesPerRow*(lineCount+1)) throw new Exception("Bad RLE 8 coding."); byte cByte=fileReader.ReadByte(); if(cByte==0) // Kommando steht in Byte 2 { byte scByte=fileReader.ReadByte(); switch(scByte) { case 0: // Ende der Bildzeile { lineCount++; index=lineCount*BytesPerRow; break; } case 1: // Ende der Bitmap { index=absHeight*BytesPerRow; lineCount=absHeight; fileReader.BaseStream.Position=fileReader.BaseStream.Length; break; } case 2: // Verschiebung der aktuellen Pixelposition { byte vRight=fileReader.ReadByte(); // Verschiebung nach Rechts if(vRight>=biWidth) throw new Exception("Bad RLE 8 coding."); byte vDown=fileReader.ReadByte(); // Verschiebung nach Unten int currentRow=index-lineCount*BytesPerRow; if((currentRow+vRight)>=biWidth) throw new Exception("Bad RLE 8 coding."); if((lineCount+vDown)>=absHeight) throw new Exception("Bad RLE 8 coding."); lineCount+=vDown; index=lineCount*BytesPerRow+currentRow+vRight; break; } default: // 3-255 Byte unverändert übernehmen { // Die folgenden n Bytes werden direkt übernommen; // der nächste Datensatz findet sich am darauffolgenden // geraden Offset (vom Start der Bilddaten aus gezählt). fileReader.Read(bufferRLE, index, scByte); index+=scByte; // Wenn Offset nicht grade dann ein Byte nach vorne if(scByte%2!=0) fileReader.BaseStream.Seek(1, SeekOrigin.Current); break; } } } else // Daten so oft wie im cByte angegeben reinschreiben { byte dByte=fileReader.ReadByte(); for(int i=0; i<cByte; i++) bufferRLE[index++]=dByte; } } #endregion #region pImage erstellen und füllen if(biHeight>0) // buttom-up Bild { int fIndex=0; // RLE Buffer Index index=0; for(int i=absHeight-1; i>=0; i--) { index=i*biWidth*3; for(int a=0; a<biWidth; a++) { byte pixel=bufferRLE[fIndex++]; ret.imageData[index++]=ColorTable[pixel].B; ret.imageData[index++]=ColorTable[pixel].G; ret.imageData[index++]=ColorTable[pixel].R; } fIndex+=rest; } } else if(biHeight<0) // top-down Bild { int fIndex=0; // RLE Buffer Index index=0; for(int i=0; i<absHeight; i++) { for(int a=0; a<biWidth; a++) { byte pixel=bufferRLE[fIndex++]; ret.imageData[index++]=ColorTable[pixel].B; ret.imageData[index++]=ColorTable[pixel].G; ret.imageData[index++]=ColorTable[pixel].R; } fIndex+=rest; } } #endregion #endregion } else if(biCompression==BMPBiCompression.BI_RLE4) // RLE 4 Kodierte Daten { #region RLE 4 if(biBitCount!=4) return new Graphic(); //Nur 4 Bit Bilder erlaubt int BytesPerRow=(int)Align((uint)biWidth, 4); int rest=BytesPerRow-biWidth; byte[] bufferRLE=new byte[absHeight*BytesPerRow]; int index=0; int lineCount=0; while(ColorTable.Count<16) ColorTable.Add(Color.Black); #region Dekomprimiere RLE 4 while(fileReader.BaseStream.Position<fileReader.BaseStream.Length&&index<(absHeight*BytesPerRow)) { if(rest!=0&&(index/BytesPerRow)!=lineCount) throw new Exception("Bad RLE 4 coding."); if(rest==0&&(index/BytesPerRow)!=lineCount) if(index>BytesPerRow*(lineCount+1)) throw new Exception("Bad RLE 4 coding."); byte cByte=fileReader.ReadByte(); if(cByte==0) // Kommando steht in Byte 2 { byte scByte=fileReader.ReadByte(); switch(scByte) { case 0: // Ende der Bildzeile { lineCount++; index=lineCount*BytesPerRow; break; } case 1: // Ende der Bitmap { index=absHeight*BytesPerRow; lineCount=absHeight; fileReader.BaseStream.Position=fileReader.BaseStream.Length; break; } case 2: // Verschiebung der aktuellen Pixelposition { byte vRight=fileReader.ReadByte(); // Verschiebung nach Rechts if(vRight>=biWidth) throw new Exception("Bad RLE 4 coding."); byte vDown=fileReader.ReadByte(); // Verschiebung nach Unten int currentRow=index-lineCount*BytesPerRow; if((currentRow+vRight)>=biWidth) throw new Exception("Bad RLE 4 coding."); if((lineCount+vDown)>=absHeight) throw new Exception("Bad RLE 4 coding."); lineCount+=vDown; index=lineCount*BytesPerRow+currentRow+vRight; break; } default: // 3-255 Nibbles unverändert übernehmen { // Die folgenden n Nibbles werden direkt übernommen; // der nächste Datensatz findet sich am darauffolgenden // geraden Offset (vom Start der Bilddaten aus gezählt). byte[] nibbles=new byte[(scByte+1)/2]; fileReader.Read(nibbles, 0, nibbles.Length); for(int i=0; i<nibbles.Length-(cByte%2); i++) { bufferRLE[index++]=(byte)(nibbles[i]>>4); bufferRLE[index++]=(byte)(nibbles[i]&0xF); } if(cByte%2!=0) bufferRLE[index++]=(byte)(nibbles[nibbles.Length-1]>>4); // Wenn Offset nicht grade dann ein Byte nach vorne if(((scByte+1)/2)%2!=0) fileReader.BaseStream.Seek(1, SeekOrigin.Current); break; } } } else // Daten so oft wie im cByte angegeben reinschreiben { byte dByte=fileReader.ReadByte(); byte aByte=(byte)(dByte>>4); byte bByte=(byte)(dByte&0xF); for(int i=0; i<cByte/2; i++) { bufferRLE[index++]=aByte; bufferRLE[index++]=bByte; } if(cByte%2!=0) bufferRLE[index++]=aByte; } } #endregion #region pImage erstellen und füllen if(biHeight>0) // buttom-up Bild { int fIndex=0; // RLE Buffer Index index=0; for(int i=absHeight-1; i>=0; i--) { index=i*biWidth*3; for(int a=0; a<biWidth; a++) { byte pixel=bufferRLE[fIndex++]; ret.imageData[index++]=ColorTable[pixel].B; ret.imageData[index++]=ColorTable[pixel].G; ret.imageData[index++]=ColorTable[pixel].R; } fIndex+=rest; } } else if(biHeight<0) // top-down Bild { int fIndex=0; // RLE Buffer Index index=0; for(int i=0; i<absHeight; i++) { for(int a=0; a<biWidth; a++) { byte pixel=bufferRLE[fIndex++]; ret.imageData[index++]=ColorTable[pixel].B; ret.imageData[index++]=ColorTable[pixel].G; ret.imageData[index++]=ColorTable[pixel].R; } fIndex+=rest; } } #endregion #endregion } else if(biCompression==BMPBiCompression.BI_BITFIELDS||biCompression==BMPBiCompression.BI_ALPHABITFIELDS) { // Bitmasken #region BI_BITFIELDS if(biBitCount==16) { #region Bitmasken checken bmRed&=0xffff; // nur 16 bittig bmGreen&=0xffff; bmBlue&=0xffff; bmAlpha&=0xffff; bool doRed=true; bool doGreen=true; bool doBlue=true; bool doAlpha=true; if((bmRed&bmGreen)>0) throw new Exception("Bad bit fields"); if((bmRed&bmBlue)>0) throw new Exception("Bad bit fields"); if((bmGreen&bmBlue)>0) throw new Exception("Bad bit fields"); int rshifta=0; while(((bmRed>>rshifta)&0x1)==0) rshifta++; int rshiftb=rshifta; while(((bmRed>>rshiftb)&0x1)!=0) rshiftb++; for(int i=rshiftb; i<16; i++) if((bmRed&1u<<i)>0) throw new Exception("Bad bit fields"); int gshifta=0; while(((bmGreen>>gshifta)&0x1)==0) gshifta++; int gshiftb=gshifta; while(((bmGreen>>gshiftb)&0x1)!=0) gshiftb++; for(int i=gshiftb; i<16; i++) if((bmGreen&1u<<i)>0) throw new Exception("Bad bit fields"); int bshifta=0; while(((bmBlue>>bshifta)&0x1)==0) bshifta++; int bshiftb=bshifta; while(((bmBlue>>bshiftb)&0x1)!=0) bshiftb++; for(int i=bshiftb; i<16; i++) if((bmBlue&1u<<i)>0) throw new Exception("Bad bit fields"); int ashifta=0; int ashiftb=0; if(biCompression==BMPBiCompression.BI_BITFIELDS) { bmAlpha=~(bmRed|bmGreen|bmBlue); if(bmAlpha!=0xffff0000) { bmAlpha&=0xffff; ashifta=0; while(((bmAlpha>>ashifta)&0x1)==0) ashifta++; ashiftb=ashifta; while(((bmAlpha>>ashiftb)&0x1)!=0) ashiftb++; bmAlpha=~bmAlpha; for(int i=ashiftb; i<16; i++) bmAlpha|=1u<<i; bmAlpha=~bmAlpha; } else bmAlpha=0; } else { if((bmAlpha&bmRed)>0) throw new Exception("Bad bit fields"); if((bmAlpha&bmGreen)>0) throw new Exception("Bad bit fields"); if((bmAlpha&bmBlue)>0) throw new Exception("Bad bit fields"); ashifta=0; while(((bmAlpha>>ashifta)&0x1)==0) ashifta++; ashiftb=ashifta; while(((bmAlpha>>ashiftb)&0x1)!=0) ashiftb++; for(int i=ashiftb; i<16; i++) if((bmAlpha&1u<<i)>0) throw new Exception("Bad bit fields"); } if(bmRed==0) doRed=false; if(bmGreen==0) doGreen=false; if(bmBlue==0) doBlue=false; if(bmAlpha==0) doAlpha=false; if(!doRed&&!doGreen&&!doBlue&&!doAlpha) throw new Exception("Bad bit fields"); int redSize=rshiftb-rshifta; int greenSize=gshiftb-gshifta; int blueSize=bshiftb-bshifta; int alphaSize=ashiftb-ashifta; #endregion #region 16 Bit int BytesPerRow=(biWidth*2); buffer=new byte[BytesPerRow*absHeight]; if(biHeight>0) // buttom-up Bild { for(int i=0; i<absHeight; i++) { fileReader.Read(buffer, buffer.Length-(i+1)*BytesPerRow, BytesPerRow); } } else if(biHeight<0) // top-down Bild { fileReader.Read(buffer, 0, BytesPerRow*absHeight); // ganze bild auf einmal laden } uint redDiv=0, greenDiv=0, blueDiv=0, alphaDiv=0; if(doRed&&redSize<8) redDiv=1u<<redSize; if(doGreen&&greenSize<8) greenDiv=1u<<greenSize; if(doBlue&&blueSize<8) blueDiv=1u<<blueSize; if(doAlpha&&alphaSize<8) alphaDiv=1u<<alphaSize; // Bitmaske anwenden for(int i=0; i<biWidth*absHeight; i++) { int start=i*4; uint color=((uint)buffer[i*2+1]<<8)+(uint)buffer[i*2]; if(doRed) { uint red=(color&bmRed)>>rshifta; if(redSize>8) red>>=redSize-8; if(redSize<8) { red<<=8-redSize; red+=red/redDiv; } ret.imageData[start+2]=(byte)red; } else ret.imageData[start+2]=0; if(doGreen) { uint green=(color&bmGreen)>>gshifta; if(greenSize>8) green>>=greenSize-8; if(greenSize<8) { green<<=8-greenSize; green+=green/greenDiv; } ret.imageData[start+1]=(byte)green; } else ret.imageData[start+1]=0; if(doBlue) { uint blue=(color&bmBlue)>>bshifta; if(blueSize>8) blue>>=blueSize-8; if(blueSize<8) { blue<<=8-blueSize; blue+=blue/blueDiv; } ret.imageData[start]=(byte)blue; } else ret.imageData[start]=0; if(doAlpha) { uint alpha=(color&bmAlpha)>>ashifta; if(alphaSize>8) alpha>>=alphaSize-8; if(alphaSize<8) { alpha<<=8-alphaSize; alpha+=alpha/alphaDiv; } ret.imageData[start+3]=(byte)alpha; } else ret.imageData[start+3]=0; } #endregion } else if(biBitCount==32) { #region Bitmasken checken bool doRed=true; bool doGreen=true; bool doBlue=true; bool doAlpha=true; if((bmRed&bmGreen)>0) throw new Exception("Bad bit fields"); if((bmRed&bmBlue)>0) throw new Exception("Bad bit fields"); if((bmGreen&bmBlue)>0) throw new Exception("Bad bit fields"); int rshifta=0; while(((bmRed>>rshifta)&0x1)==0) rshifta++; int rshiftb=rshifta; while(((bmRed>>rshiftb)&0x1)!=0) rshiftb++; for(int i=rshiftb; i<32; i++) if((bmRed&1u<<i)>0) throw new Exception("Bad bit fields"); int gshifta=0; while(((bmGreen>>gshifta)&0x1)==0) gshifta++; int gshiftb=gshifta; while(((bmGreen>>gshiftb)&0x1)!=0) gshiftb++; for(int i=gshiftb; i<32; i++) if((bmGreen&1u<<i)>0) throw new Exception("Bad bit fields"); int bshifta=0; while(((bmBlue>>bshifta)&0x1)==0) bshifta++; int bshiftb=bshifta; while(((bmBlue>>bshiftb)&0x1)!=0) bshiftb++; for(int i=bshiftb; i<32; i++) if((bmBlue&1u<<i)>0) throw new Exception("Bad bit fields"); int ashifta=0; int ashiftb=0; if(biCompression==BMPBiCompression.BI_BITFIELDS) { bmAlpha=~(bmRed|bmGreen|bmBlue); if(bmAlpha!=0) { ashifta=0; while(((bmAlpha>>ashifta)&0x1)==0) ashifta++; ashiftb=ashifta; while(((bmAlpha>>ashiftb)&0x1)!=0) ashiftb++; bmAlpha=~bmAlpha; for(int i=ashiftb; i<32; i++) bmAlpha|=1u<<i; bmAlpha=~bmAlpha; } } else { if((bmAlpha&bmRed)>0) throw new Exception("Bad bit fields"); if((bmAlpha&bmGreen)>0) throw new Exception("Bad bit fields"); if((bmAlpha&bmBlue)>0) throw new Exception("Bad bit fields"); ashifta=0; while(((bmAlpha>>ashifta)&0x1)==0) ashifta++; ashiftb=ashifta; while(((bmAlpha>>ashiftb)&0x1)!=0) ashiftb++; for(int i=ashiftb; i<32; i++) if((bmAlpha&1u<<i)>0) throw new Exception("Bad bit fields"); } if(bmRed==0) doRed=false; if(bmGreen==0) doGreen=false; if(bmBlue==0) doBlue=false; if(bmAlpha==0) doAlpha=false; if(!doRed&&!doGreen&&!doBlue&&!doAlpha) throw new Exception("Bad bit fields"); int redSize=rshiftb-rshifta; int greenSize=gshiftb-gshifta; int blueSize=bshiftb-bshifta; int alphaSize=ashiftb-ashifta; #endregion #region 32 Bit int BytesPerRow=(biWidth*4); if(biHeight>0) // buttom-up Bild { for(int i=0; i<absHeight; i++) { fileReader.Read(ret.imageData, ret.imageData.Length-(i+1)*BytesPerRow, BytesPerRow); } } else if(biHeight<0) // top-down Bild { fileReader.Read(ret.imageData, 0, BytesPerRow*absHeight); // ganze bild auf einmal laden } uint redDiv=0, greenDiv=0, blueDiv=0, alphaDiv=0; if(doRed&&redSize<8) redDiv=1u<<redSize; if(doGreen&&greenSize<8) greenDiv=1u<<greenSize; if(doBlue&&blueSize<8) blueDiv=1u<<blueSize; if(doAlpha&&alphaSize<8) alphaDiv=1u<<alphaSize; // Bitmaske anwenden for(int i=0; i<biWidth*absHeight; i++) { int start=i*4; uint color=((uint)ret.imageData[start+3]<<24)+((uint)ret.imageData[start+2]<<16)+((uint)ret.imageData[start+1]<<8)+(uint)ret.imageData[start]; if(doRed) { uint red=(color&bmRed)>>rshifta; if(redSize>8) red>>=redSize-8; if(redSize<8) { red<<=8-redSize; red+=red/redDiv; } ret.imageData[start+2]=(byte)red; } else ret.imageData[start+2]=0; if(doGreen) { uint green=(color&bmGreen)>>gshifta; if(greenSize>8) green>>=greenSize-8; if(greenSize<8) { green<<=8-greenSize; green+=green/greenDiv; } ret.imageData[start+1]=(byte)green; } else ret.imageData[start+1]=0; if(doBlue) { uint blue=(color&bmBlue)>>bshifta; if(blueSize>8) blue>>=blueSize-8; if(blueSize<8) { blue<<=8-blueSize; blue+=blue/blueDiv; } ret.imageData[start]=(byte)blue; } else ret.imageData[start]=0; if(doAlpha) { uint alpha=(color&bmAlpha)>>ashifta; if(alphaSize>8) alpha>>=alphaSize-8; if(alphaSize<8) { alpha<<=8-alphaSize; alpha+=alpha/alphaDiv; } ret.imageData[start+3]=(byte)alpha; } else ret.imageData[start+3]=0; } #endregion } return ret; #endregion } #endregion return ret; } catch(Exception) { return new Graphic(); } finally { fileReader.Close(); } }
public Graphic ToRot270() { Graphic ret=new Graphic(height, width, channelFormat); if(ret.imageData==null) return ret; uint bpp=BytePerPixel; uint bw=width*bpp; uint dst=0; uint src_=(height-1)*bw; for(uint y=0; y<width; y++) { uint src=src_; for(uint x=0; x<height; x++) { for(uint i=0; i<bpp; i++) ret.imageData[dst++]=imageData[src++]; src-=bw+bpp; } src_+=bpp; } return ret; }
unsafe Graphic DownsampleH(uint w) { if((width*height)==0) return new Graphic(0, 0, channelFormat); if(w==0) return new Graphic(0, 0, channelFormat); if(width>w&&width%w==0) return ReduceByH(width/w); double delta=((double)width)/w; if(channelFormat==Format.GRAY) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; fixed(byte* _dst=ret.imageData, _src=imageData) { byte* dst=_dst; for(uint y=0; y<height; y++) { byte* src=_src+y*width; for(uint x=0; x<w; x++) { double deltax=x*delta; double dx=1-(deltax-((uint)deltax)); byte* s=src+((uint)deltax); double deltasum=dx; double gsum=*(s++)*dx; while((delta-deltasum)>0.0001) { dx=delta-deltasum; if(dx>=1) { deltasum+=1; gsum+=*(s++); } else { gsum+=*s*dx; break; } } *(dst++)=(byte)(gsum/delta+0.5); } } } return ret; } if(channelFormat==Format.RGB||channelFormat==Format.BGR) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; fixed(byte* _dst=ret.imageData, _src=imageData) { byte* dst=_dst; uint wb=width*3; for(uint y=0; y<height; y++) { byte* src=_src+y*wb; for(uint x=0; x<w; x++) { double deltax=x*delta; double dx=1-(deltax-((uint)deltax)); byte* s=src+((uint)deltax)*3; double deltasum=dx; double rsum=*(s++)*dx; double gsum=*(s++)*dx; double bsum=*(s++)*dx; while((delta-deltasum)>0.0001) { dx=delta-deltasum; if(dx>=1) { deltasum+=1; rsum+=*(s++); gsum+=*(s++); bsum+=*(s++); } else { rsum+=*(s++)*dx; gsum+=*(s++)*dx; bsum+=*s*dx; break; } } *(dst++)=(byte)(rsum/delta+0.5); *(dst++)=(byte)(gsum/delta+0.5); *(dst++)=(byte)(bsum/delta+0.5); } } } return ret; } if(channelFormat==Format.RGBA||channelFormat==Format.BGRA) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; fixed(byte* _dst=ret.imageData, _src=imageData) { byte* dst=_dst; uint wb=width*4; for(uint y=0; y<height; y++) { byte* src=_src+y*wb; for(uint x=0; x<w; x++) { double deltax=x*delta; double dx=1-(deltax-((uint)deltax)); byte* s=src+((uint)deltax)*4; double deltasum=dx; byte r=*(s++), g=*(s++), b=*(s++); uint a=*(s++); double adx=a*dx; double rsum=r*adx; double gsum=g*adx; double bsum=b*adx; double asum=adx; while((delta-deltasum)>0.0001) { dx=delta-deltasum; r=*(s++); g=*(s++); b=*(s++); a=*(s++); if(dx>=1) { deltasum+=1; rsum+=r*a; gsum+=g*a; bsum+=b*a; asum+=a; } else { adx=a*dx; rsum+=r*adx; gsum+=g*adx; bsum+=b*adx; asum+=adx; break; } } *(dst++)=(byte)(rsum/asum+0.5); *(dst++)=(byte)(gsum/asum+0.5); *(dst++)=(byte)(bsum/asum+0.5); *(dst++)=(byte)(asum/delta+0.5); } } } return ret; } if(channelFormat==Format.GRAYAlpha) { Graphic ret=new Graphic(w, height, channelFormat); if(ret.imageData==null) return ret; fixed(byte* _dst=ret.imageData, _src=imageData) { byte* dst=_dst; uint wb=width*2; for(uint y=0; y<height; y++) { byte* src=_src+y*wb; for(uint x=0; x<w; x++) { double deltax=x*delta; double dx=1-(deltax-((uint)deltax)); byte* s=src+((uint)deltax)*2; double deltasum=dx; byte g=*(s++); uint a=*(s++); double gsum=g*dx*a; double asum=a*dx; while((delta-deltasum)>0.0001) { dx=delta-deltasum; g=*(s++); a=*(s++); if(dx>=1) { deltasum+=1; gsum+=g*a; asum+=a; } else { double adx=a*dx; gsum+=g*adx; asum+=adx; break; } } *(dst++)=(byte)(gsum/asum+0.5); *(dst++)=(byte)(asum/delta+0.5); } } } return ret; } return new Graphic(0, 0, channelFormat); }