public void Example() { // Allocating a new bitmap with 99x99 pixels, 16-bit color depth and an allocation of 5 bits for each color. dib = FreeImage.Allocate(99, 99, 16, FreeImage.FI16_555_RED_MASK, FreeImage.FI16_555_GREEN_MASK, FreeImage.FI16_555_BLUE_MASK); // Saving bitmap. if (!FreeImage.SaveEx(ref dib, "example01.bmp", true)) { Console.WriteLine("Saving 'example.bmp' failed."); FreeImage.UnloadEx(ref dib); } // Allocation a new bitmap with 71x33 pixels, 4-bit color depth. Bitmaps below 16-bit have paletts. // Each pixel references an index within the palette wich contains the true color. // Therefor no bit-masks are needed and can be set to 0. dib = FreeImage.Allocate(71, 33, 4, 0, 0, 0); // Saving bitmap. if (!FreeImage.SaveEx(ref dib, "example02.tif", true)) { Console.WriteLine("Saving 'example02.tif' failed."); FreeImage.UnloadEx(ref dib); } // Allocation a new bitmap. This time 'AllocateT' is used because 'Allocate' can only create standard bitmaps. // In this case a RGBF bitmap is created. Red, green and blue are represented by a float-value so no bit-masks are needed. dib = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_RGBF, 50, 75, 9, 0, 0, 0); // Saving bitmap. if (!FreeImage.SaveEx(ref dib, "example03.hdr", true)) { Console.WriteLine("Saving 'example03.hdr' failed."); FreeImage.UnloadEx(ref dib); } }
public bool Save(string path) { if (string.IsNullOrEmpty(path)) { return(false); } bool isHDR = false; System.IO.FileInfo fileInfo = new System.IO.FileInfo(path); if (fileInfo.Extension.ToLower().Contains(".hdr")) { isHDR = true; } FIBITMAP dib = new FIBITMAP(); if (isHDR) { dib = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_RGBF, (int)width, (int)height, 96); uint h = FreeImage.GetHeight(dib); for (int i = 0; i < h; i++) { Scanline <FIRGBF> scanline = new Scanline <FIRGBF>(dib, i); FIRGBF[] data = scanline.Data; for (int j = 0; j < data.Length; j++) { Color color = this.GetPixel(data.Length - 1 - j, i); data[j].red = color.r; data[j].green = color.g; data[j].blue = color.b; } scanline.Data = data; } } else { FREE_IMAGE_FORMAT fif = FreeImage.GetFIFFromFilename(path); dib = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_BITMAP, (int)width, (int)height, 24); uint h = FreeImage.GetHeight(dib); for (int i = 0; i < h; i++) { Scanline <RGBTRIPLE> scanline = new Scanline <RGBTRIPLE>(dib, i); RGBTRIPLE[] data = scanline.Data; for (int j = 0; j < data.Length; j++) { Color color = this.GetPixel(data.Length - 1 - j, i); color.Gamma(0.45f); int r = (int)(color.r * 255.0f); int g = (int)(color.g * 255.0f); int b = (int)(color.b * 255.0f); if (r < 0) { r = 0; } if (r > 255) { r = 255; } if (g < 0) { g = 0; } if (g > 255) { g = 255; } if (b < 0) { b = 0; } if (b > 255) { b = 255; } data[j].rgbtRed = (byte)r; data[j].rgbtGreen = (byte)g; data[j].rgbtBlue = (byte)b; } scanline.Data = data; } } if (!FreeImage.SaveEx(ref dib, path, true)) { FreeImage.UnloadEx(ref dib); return(false); } FreeImage.UnloadEx(ref dib); return(true); }
/// <summary> /// 保存贴图到文件,适用于 Chunk_CreateTexture2D 及 Chunk_CreateSwapBuffer /// </summary> /// <param name="subDatas"></param> /// <param name="desc"></param> /// <param name="section"></param> public static void SaveTextureToFile(D3D11_SUBRESOURCE_DATA[] subDatas, D3D11_TEXTURE2D_DESC desc, Section section, string path) { DXGI_FORMAT format = desc.Format; if (Common.IsBlockFormat(format)) // 暂时不支持导出压缩格式 { return; } if (format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_TYPELESS || format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) // 4通道保存成tga以方便编辑A通道 { FIBITMAP bmp = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_BITMAP, (int)desc.Width, (int)desc.Height, 32); Debug.Assert(subDatas[0].sysMemLength >= desc.Width * desc.Height * 4); // sysMemLength 是对齐的,因此可能大于真实数据大小 fixed(void *p = §ion.uncompressedData[subDatas[0].sysMemDataOffset]) { byte *rawData = (byte *)p; for (int h = (int)(desc.Height - 1); h >= 0; h--) // bitmap 存储方向与 dx 相反 { byte *scanLine = (byte *)FreeImage.GetScanLine(bmp, h); for (int w = 0; w < desc.Width; w++) { *scanLine++ = rawData[w * 4]; *scanLine++ = rawData[w * 4 + 1]; *scanLine++ = rawData[w * 4 + 2]; *scanLine++ = rawData[w * 4 + 3]; } rawData += subDatas[0].SysMemPitch; } } path = $"{path}.tga"; File.Delete(path); FreeImage.Save(FREE_IMAGE_FORMAT.FIF_TARGA, bmp, path, FREE_IMAGE_SAVE_FLAGS.DEFAULT); FreeImage.Unload(bmp); } else if (format == DXGI_FORMAT.DXGI_FORMAT_R8_SNORM || format == DXGI_FORMAT.DXGI_FORMAT_R8_TYPELESS || format == DXGI_FORMAT.DXGI_FORMAT_R8_UNORM || format == DXGI_FORMAT.DXGI_FORMAT_A8_UNORM) // 经过测试单通道无论指定哪个通道数据都只存了一个通道, 单通道保存成png24 { FIBITMAP bmp = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_BITMAP, (int)desc.Width, (int)desc.Height, 24); Debug.Assert(subDatas[0].sysMemLength >= desc.Width * desc.Height); fixed(void *p = §ion.uncompressedData[subDatas[0].sysMemDataOffset]) { byte *rawData = (byte *)p; for (int h = (int)(desc.Height - 1); h >= 0; h--) // bitmap 存储方向与 dx 相反 { byte *scanLine = (byte *)FreeImage.GetScanLine(bmp, h); for (int w = 0; w < desc.Width; w++) { byte val = rawData[w]; * scanLine++ = val; * scanLine++ = val; * scanLine++ = val; } rawData += subDatas[0].SysMemPitch; } } path = $"{path}.bmp"; File.Delete(path); FreeImage.Save(FREE_IMAGE_FORMAT.FIF_BMP, bmp, path, FREE_IMAGE_SAVE_FLAGS.BMP_SAVE_RLE); FreeImage.Unload(bmp); } }
private static FIBITMAP NewFiBitMap(PixImage <float> pi) { FreeImageCheck(pi.Volume.Info); var sx = pi.Size.X; var sy = pi.Size.Y; var data = pi.Volume.Data; long i = pi.Volume.FirstIndex; long j = pi.Volume.JY; switch (pi.ChannelCount) { case 1: { var dib = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_FLOAT, sx, sy, 32); var delta = (int)FreeImage.GetPitch(dib); var bits = FreeImage.GetBits(dib) + sy * delta; for (var y = 0; y < sy; y++) { bits = bits - delta; unsafe { float *pixel = (float *)bits; for (var x = 0; x < sx; x++) { pixel[x] = data[i++]; } } i += j; } return(dib); } case 3: { var dib = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_RGBF, sx, sy, 96); var delta = (int)FreeImage.GetPitch(dib); var bits = FreeImage.GetBits(dib) + sy * delta; for (var y = 0; y < sy; y++) { bits = bits - delta; unsafe { FIRGBF *pixel = (FIRGBF *)bits; for (var x = 0; x < sx; x++) { pixel[x].red = data[i++]; pixel[x].green = data[i++]; pixel[x].blue = data[i++]; } } i += j; } return(dib); } case 4: { var dib = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_RGBAF, sx, sy, 128); var delta = (int)FreeImage.GetPitch(dib); var bits = FreeImage.GetBits(dib) + sy * delta; for (var y = 0; y < sy; y++) { bits = bits - delta; unsafe { FIRGBAF *pixel = (FIRGBAF *)bits; for (var x = 0; x < sx; x++) { pixel[x].red = data[i++]; pixel[x].green = data[i++]; pixel[x].blue = data[i++]; pixel[x].alpha = data[i++]; } } i += j; } return(dib); } default: break; } throw new ArgumentException("cannot save PixImage"); }
private bool MergeImages(string fileNameFormat, string outputDir, string prefix, int frameNum, string ext) { FreeImageBitmap combined = null; string fname = ""; bool supported = false; bool mergeSuccessful = true; FREE_IMAGE_TYPE type = FREE_IMAGE_TYPE.FIT_UNKNOWN; FreeImageBitmap source = null; string mergedFile = string.Format(fileNameFormat, outputDir, prefix, frameNum, ext); string tempFile = string.Format(fileNameFormat, outputDir, prefix, frameNum, "_tmp" + ext); // Allocate a bitmap to store the final image fname = string.Format(fileNameFormat, outputDir, "slice_0_" + prefix, frameNum, ext); try { source = new FreeImageBitmap(fname); if (source != null) { type = source.ImageType; switch (type) { case FREE_IMAGE_TYPE.FIT_BITMAP: if (source.ColorDepth == 32 || source.ColorDepth == 24) { supported = true; } break; case FREE_IMAGE_TYPE.FIT_RGB16: case FREE_IMAGE_TYPE.FIT_RGBA16: case FREE_IMAGE_TYPE.FIT_RGBAF: case FREE_IMAGE_TYPE.FIT_RGBF: supported = true; break; } } } catch (Exception ex) { logger.Error(ex, "Error opening slice file"); } if (supported == false) { Console.WriteLine("Image format not supported"); return(false); } try { // Create a new image of the input file type and the correct size FIBITMAP newImage = FreeImage.AllocateT(type, Width, Height, source.ColorDepth, source.RedMask, source.BlueMask, source.GreenMask); FreeImage.SaveEx(newImage, tempFile); FreeImage.UnloadEx(ref newImage); source.Dispose(); source = null; GC.Collect(); GC.WaitForPendingFinalizers(); combined = new FreeImageBitmap(tempFile); } catch (Exception ex) { logger.Error(ex, "Error creating output file"); mergeSuccessful = false; } for (int i = 0; i < SlicesAcross * SlicesDown; i++) { // Load the image slice fname = string.Format(fileNameFormat, outputDir, "slice_" + i + "_" + prefix, frameNum, ext); FreeImageBitmap slice = new FreeImageBitmap(fname); int posX; int posY; if (SlicesDown > 1 && SlicesAcross > 1) { posX = i % SlicesAcross; posY = i / SlicesAcross; } else if (SlicesDown == 1) { posX = i; posY = 0; } else { posX = 0; posY = i; } // Calculate the image slice sizes and the row/column position double sizeV = (1.0 / SlicesDown) * Height; double sizeH = (1.0 / SlicesAcross) * Width; double overlapV = sizeV * (Overlap / 100.0); double overlapH = sizeH * (Overlap / 100.0); double realLeft = sizeH * posX; double left = realLeft - overlapH; double realTop = sizeV * posY; double top = realTop - overlapV; // Check the sizes are within limits and adjust left = Math.Max(0.0, left); top = Math.Max(0.0, top); try { switch (type) { case FREE_IMAGE_TYPE.FIT_BITMAP: if (slice.ColorDepth == 24) { for (int y = 0; y < slice.Height; y++) { int srcY = (slice.Height - 1) - y; int destY = (combined.Height - 1) - (srcY + (int)top); int topY = y + (int)top; Scanline <RGBTRIPLE> srcLine = (Scanline <RGBTRIPLE>)slice.GetScanline(y); Scanline <RGBTRIPLE> destLine = (Scanline <RGBTRIPLE>)combined.GetScanline(destY); for (int x = 0; x < slice.Width; x++) { int destX = x + (int)left; // Make sure it's not out of bounds if (destY >= Height || destY >= Width) { continue; } // Is the pixel in an overlapping Area if (topY < realTop || destX < realLeft) { MergePixel srcPixel = new MergePixel(srcLine[x].rgbtRed, srcLine[x].rgbtGreen, srcLine[x].rgbtBlue, 0); MergePixel destPixel = new MergePixel(destLine[destX].rgbtRed, destLine[destX].rgbtGreen, destLine[destX].rgbtBlue, 0); destPixel = CalculatePixelWeight(overlapV, overlapH, realLeft, left, realTop, top, y, topY, x, srcPixel, destPixel); RGBTRIPLE dest; dest.rgbtRed = destPixel.red > 255.0 ? (byte)255 : (byte)destPixel.red; dest.rgbtGreen = destPixel.green > 255.0 ? (byte)255 : (byte)destPixel.green; dest.rgbtBlue = destPixel.blue > 255.0 ? (byte)255 : (byte)destPixel.blue; destLine[destX] = dest; } else { destLine[destX] = srcLine[x]; } } } } else { for (int y = 0; y < slice.Height; y++) { int srcY = (slice.Height - 1) - y; int destY = (combined.Height - 1) - (srcY + (int)top); int topY = y + (int)top; Scanline <RGBQUAD> srcLine = (Scanline <RGBQUAD>)slice.GetScanline(y); Scanline <RGBQUAD> destLine = (Scanline <RGBQUAD>)combined.GetScanline(destY); for (int x = 0; x < slice.Width; x++) { int destX = x + (int)left; // Make sure it's not out of bounds if (destY >= Height || destY >= Width) { continue; } // Is the pixel in an overlapping Area if (topY < realTop || destX < realLeft) { MergePixel srcPixel = new MergePixel(srcLine[x].rgbRed, srcLine[x].rgbGreen, srcLine[x].rgbBlue, destLine[destX].rgbReserved); MergePixel destPixel = new MergePixel(destLine[destX].rgbRed, destLine[destX].rgbGreen, destLine[destX].rgbBlue, destLine[destX].rgbReserved); destPixel = CalculatePixelWeight(overlapV, overlapH, realLeft, left, realTop, top, y, topY, x, srcPixel, destPixel); RGBQUAD dest = new RGBQUAD(); dest.rgbRed = destPixel.red > 255.0 ? (byte)255 : (byte)destPixel.red; dest.rgbGreen = destPixel.green > 255.0 ? (byte)255 : (byte)destPixel.green; dest.rgbBlue = destPixel.blue > 255.0 ? (byte)255 : (byte)destPixel.blue; dest.rgbReserved = destPixel.alpha > 255.0 ? (byte)255 : (byte)destPixel.alpha; destLine[destX] = dest; } else { destLine[destX] = srcLine[x]; } } } } break; case FREE_IMAGE_TYPE.FIT_RGB16: for (int y = 0; y < slice.Height; y++) { int srcY = (slice.Height - 1) - y; int destY = (combined.Height - 1) - (srcY + (int)top); int topY = y + (int)top; Scanline <FIRGB16> srcLine = (Scanline <FIRGB16>)slice.GetScanline(y); Scanline <FIRGB16> destLine = (Scanline <FIRGB16>)combined.GetScanline(destY); for (int x = 0; x < slice.Width; x++) { int destX = x + (int)left; // Make sure it's not out of bounds if (destY >= Height || destY >= Width) { continue; } // Is the pixel in an overlapping Area if (topY < realTop || destX < realLeft) { MergePixel srcPixel = new MergePixel(srcLine[x].red, srcLine[x].green, srcLine[x].blue, 0); MergePixel destPixel = new MergePixel(destLine[destX].red, destLine[destX].green, destLine[destX].blue, 0); destPixel = CalculatePixelWeight(overlapV, overlapH, realLeft, left, realTop, top, y, topY, x, srcPixel, destPixel); FIRGB16 dest = new FIRGB16(); dest.red = (ushort)destPixel.red; dest.green = (ushort)destPixel.green; dest.blue = (ushort)destPixel.blue; destLine[destX] = dest; } else { destLine[destX] = srcLine[x]; } } } break; case FREE_IMAGE_TYPE.FIT_RGBA16: for (int y = 0; y < slice.Height; y++) { int srcY = (slice.Height - 1) - y; int destY = (combined.Height - 1) - (srcY + (int)top); int topY = y + (int)top; Scanline <FIRGBA16> srcLine = (Scanline <FIRGBA16>)slice.GetScanline(y); Scanline <FIRGBA16> destLine = (Scanline <FIRGBA16>)combined.GetScanline(destY); for (int x = 0; x < slice.Width; x++) { int destX = x + (int)left; // Make sure it's not out of bounds if (destY >= Height || destY >= Width) { continue; } // Is the pixel in an overlapping Area if (topY < realTop || destX < realLeft) { MergePixel srcPixel = new MergePixel(srcLine[x].red, srcLine[x].green, srcLine[x].blue, srcLine[x].alpha); MergePixel destPixel = new MergePixel(destLine[destX].red, destLine[destX].green, destLine[destX].blue, destLine[destX].alpha); destPixel = CalculatePixelWeight(overlapV, overlapH, realLeft, left, realTop, top, y, topY, x, srcPixel, destPixel); FIRGBA16 dest = new FIRGBA16(); dest.red = (ushort)destPixel.red; dest.green = (ushort)destPixel.green; dest.blue = (ushort)destPixel.blue; dest.alpha = (ushort)destPixel.alpha; destLine[destX] = dest; } else { destLine[destX] = srcLine[x]; } } } break; case FREE_IMAGE_TYPE.FIT_RGBAF: for (int y = 0; y < slice.Height; y++) { int srcY = (slice.Height - 1) - y; int destY = (combined.Height - 1) - (srcY + (int)top); int topY = y + (int)top; Scanline <FIRGBAF> srcLine = (Scanline <FIRGBAF>)slice.GetScanline(y); Scanline <FIRGBAF> destLine = (Scanline <FIRGBAF>)combined.GetScanline(destY); for (int x = 0; x < slice.Width; x++) { int destX = x + (int)left; // Make sure it's not out of bounds if (destY >= Height || destY >= Width) { continue; } // Is the pixel in an overlapping Area if (topY < realTop || destX < realLeft) { MergePixel srcPixel = new MergePixel(srcLine[x].red, srcLine[x].green, srcLine[x].blue, destLine[destX].alpha); MergePixel destPixel = new MergePixel(destLine[destX].red, destLine[destX].green, destLine[destX].blue, destLine[destX].alpha); destPixel = CalculatePixelWeight(overlapV, overlapH, realLeft, left, realTop, top, y, topY, x, srcPixel, destPixel); FIRGBAF dest = new FIRGBAF(); dest.red = (float)destPixel.red; dest.green = (float)destPixel.green; dest.blue = (float)destPixel.blue; dest.alpha = (float)destPixel.alpha; destLine[destX] = dest; } else { destLine[destX] = srcLine[x]; } } } break; case FREE_IMAGE_TYPE.FIT_RGBF: for (int y = 0; y < slice.Height; y++) { int srcY = (slice.Height - 1) - y; int destY = (combined.Height - 1) - (srcY + (int)top); int topY = y + (int)top; Scanline <FIRGBF> srcLine = (Scanline <FIRGBF>)slice.GetScanline(y); Scanline <FIRGBF> destLine = (Scanline <FIRGBF>)combined.GetScanline(destY); for (int x = 0; x < slice.Width; x++) { int destX = x + (int)left; // Make sure it's not out of bounds if (destY >= Height || destY >= Width) { continue; } // Is the pixel in an overlapping Area if (topY < realTop || destX < realLeft) { MergePixel srcPixel = new MergePixel(srcLine[x].red, srcLine[x].green, srcLine[x].blue, 0); MergePixel destPixel = new MergePixel(destLine[destX].red, destLine[destX].green, destLine[destX].blue, 0); destPixel = CalculatePixelWeight(overlapV, overlapH, realLeft, left, realTop, top, y, topY, x, srcPixel, destPixel); FIRGBF dest = new FIRGBF(); dest.red = (float)destPixel.red; dest.green = (float)destPixel.green; dest.blue = (float)destPixel.blue; destLine[destX] = dest; } else { destLine[destX] = srcLine[x]; } } } break; } slice.Dispose(); } catch (Exception ex) { logger.Error(ex, "Error merging image files"); mergeSuccessful = false; } } try { if (mergeSuccessful) { combined.Save(mergedFile); combined.Dispose(); combined = null; GC.Collect(); GC.WaitForPendingFinalizers(); File.Delete(tempFile); } else { Log += DateTime.Now.ToLongTimeString() + " Merging frame " + frameNum + " failed.\n"; } } catch (Exception ex) { logger.Error(ex, "Error writing combined file"); mergeSuccessful = false; } return(mergeSuccessful); }