public static Frame Resize(Frame originalFrame, int x, int y, int width, int height, int destWidth, int destHeight) { Frame newFrame = originalFrame.CloneFrameEmpty(destWidth, destHeight, originalFrame.pixelFormat); newFrame.data = new byte[newFrame.Height * newFrame.Stride]; if (originalFrame.Palette != null) { newFrame.Palette = (int[])originalFrame.Palette.Clone(); } if (destWidth <= width && destHeight <= height) { ShrinkBmp(originalFrame, newFrame, x, y, width, height); } else if (destWidth>= width && destHeight >= height) { ExpandBmp(originalFrame, newFrame, x, y, width, height); } else if (destWidth < width) { //TODO: Currently this is a two pass operation. // A temporary frame to hold the partially resized data Frame f = new Frame(null, destWidth, height, originalFrame.pixelFormat); ShrinkBmp(originalFrame, f, x, y, width, height); ExpandBmp(f, newFrame, 0, 0, destWidth, height); } else if (destHeight < height) { //TODO: currently this is a two pass operation. // A temporary frame to hold the partially resized data Frame f = new Frame(null, width, destHeight, originalFrame.pixelFormat); ShrinkBmp(originalFrame, f, x, y, width, height); ExpandBmp(f, newFrame, 0, 0, width, destHeight); } return newFrame; }
// Load the icon contents from a stream, and then set the // current frame to the first one in the icon image. private void Load(Stream stream) { image = new DotGNU.Images.Image(); image.Load(stream); frame = image.GetFrame(0); frameNum = 0; }
// Convert an image frame into an XImage. public static IntPtr FrameToXImage(Screen screen, Frame frame) { int[] fpalette; XPixel[] palette; int index, color; Colormap colormap = screen.DefaultColormap; // Create a palette to use to render the image. fpalette = frame.Palette; if(fpalette != null) { // Convert the palette within the image frame itself. palette = new XPixel [256]; for(index = 0; index < 256 && index < fpalette.Length; ++index) { color = fpalette[index]; palette[index] = colormap.RGBToPixel (new Color((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF)); } } else { // We have an RGB image: use a standard palette. palette = colormap.GetStandardPalette(); } // Convert the frame into an XImage and return it. return Xlib.XSharpCreateImageFromDIB (screen.screen, frame.Width, frame.Height, frame.Stride, (int)(frame.PixelFormat), frame.Data, 0, palette); }
private Image(Image image, Frame thisFrameOnly) : this(image, image.PixelFormat) { if(thisFrameOnly != null) { this.numFrames = 1; this.frames = new Frame [1]; this.frames[0] = thisFrameOnly.CloneFrame(this); } else { this.numFrames = image.numFrames; if(image.frames != null) { int frame; this.frames = new Frame [this.numFrames]; for(frame = 0; frame < this.numFrames; ++frame) { this.frames[frame] = image.frames[frame].CloneFrame(this); } } } }
private Icon(Icon cloneFrom) { if (cloneFrom == null) { throw new ArgumentNullException("cloneFrom"); } image = (DotGNU.Images.Image)(cloneFrom.image.Clone()); frameNum = cloneFrom.frameNum; frame = image.GetFrame(frameNum); }
// Convert an image frame's mask into an XImage. IntPtr.Zero if no mask. public static IntPtr MaskToXImage(Screen screen, Frame frame) { byte[] mask = frame.Mask; if(mask == null) { return IntPtr.Zero; } return Xlib.XSharpCreateImageFromDIB (screen.screen, frame.Width, frame.Height, frame.MaskStride, (int)(PixelFormat.Format1bppIndexed), mask, 1, null); }
// Convert an image frame into an XImage bitmap. public static IntPtr FrameToXImageBitmap(Screen screen, Frame frame) { byte[] data = frame.Data; if(data == null) { return IntPtr.Zero; } return Xlib.XSharpCreateImageFromDIB (screen.screen, frame.Width, frame.Height, frame.Stride, (int)(PixelFormat.Format1bppIndexed), data, 1, null); }
// Implement the IDisposable interface. public void Dispose() { if (toolkitImage != null) { toolkitImage.Dispose(); toolkitImage = null; } if (image != null) { image.Dispose(); image = null; frame = null; frameNum = 0; } }
// Set this window's icon. void IToolkitTopLevelWindow.SetIcon(Icon icon) { DotGNU.Images.Frame frame = ToolkitManager.GetImageFrame(icon); Xsharp.Image origIcon = Icon; if (frame != null) { Icon = new Xsharp.Image(Screen, frame); } else { Icon = null; } if (origIcon != null) { origIcon.Dispose(); } }
// Select a particular frame from this icon. private void SelectFrame(int width, int height) { int index; Frame frame; for (index = 0; index < image.NumFrames; ++index) { frame = image.GetFrame(index); if (frame.Width == width && frame.Height == height) { this.frame = frame; frameNum = index; return; } } frame = image.GetFrame(0); frameNum = 0; }
// Save a BITMAPINFO structure for a frame. public static void SaveBitmapInfo (Stream stream, Frame frame, int bitCount, int size, byte[] buffer, int height) { // Build and write the BITMAPINFOHEADER structure. Utils.WriteInt32(buffer, 0, 40); // biSize Utils.WriteInt32(buffer, 4, frame.Width); Utils.WriteInt32(buffer, 8, height); Utils.WriteUInt16(buffer, 12, 1); // biPlanes Utils.WriteUInt16(buffer, 14, bitCount); Utils.WriteInt32(buffer, 16, 0); // biCompression Utils.WriteInt32(buffer, 20, size); Utils.WriteInt32(buffer, 24, 3780); // biXPelsPerMeter Utils.WriteInt32(buffer, 28, 3780); // biYPelsPerMeter Utils.WriteInt32(buffer, 32, 0); // biClrUsed Utils.WriteInt32(buffer, 36, 0); // biClrImportant stream.Write(buffer, 0, 40); // Write the palette. if(bitCount <= 8) { int[] palette = frame.Palette; int count = (1 << bitCount); int index; for(index = 0; index < count; ++index) { if(palette != null && index < palette.Length) { Utils.WriteBGR(buffer, index * 4, palette[index]); } else { // Short palette: pad with black pixels. Utils.WriteBGR(buffer, index * 4, 0); } } stream.Write(buffer, 0, count * 4); } }
private Frame(Image newImage, Frame frame, int newWidth, int newHeight, PixelFormat format, bool cloneData) { // Clone from the other frame. image = newImage; width = newWidth; height = newHeight; pixelFormat = format; stride =Utils.FormatToStride(pixelFormat, width); maskStride = (((width + 7) / 8) + 3) & ~3; generatedMask = false; if(frame.palette != null) { if(newImage != null && frame.palette == frame.image.Palette) { // The palette is a copy of the image's. palette = newImage.Palette; } else if (cloneData) { // The palette is specific to this frame. palette = (int[])(frame.palette.Clone()); } } transparentPixel = frame.transparentPixel; hotspotX = frame.hotspotX; hotspotY = frame.hotspotY; offsetX = frame.offsetX; offsetY = frame.offsetY; if(cloneData & frame.data != null) { data = (byte[])(frame.data.Clone()); } if(cloneData & frame.mask != null) { mask = (byte[])(frame.mask.Clone()); generatedMask = frame.generatedMask; } }
/// <summary> /// <para>Create a new cursor, based on a user-supplied image frame.</para> /// </summary> /// /// <param name="screen"> /// <para>The screen to create the cursor for, or /// <see langword="null"/> for the default screen on the /// default display.</para> /// </param> /// /// <param name="frame"> /// <para>The frame defining the cursor image.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"/> /// <para>Raised if <paramref name="frame"/> is /// <see langword="null"/>.</para> /// </exception> public Cursor(Screen screen, Frame frame) { Display dpy; if(frame == null) { throw new ArgumentNullException("frame"); } if(screen != null) { dpy = screen.DisplayOfScreen; } else { dpy = Application.Primary.Display; screen = dpy.DefaultScreenOfDisplay; } if( /* irgnore pixel format! frame.PixelFormat != PixelFormat.Format1bppIndexed || */ frame.Mask == null) { // The frame is not suitable for use as a cursor. this.type = CursorType.XC_left_ptr; this.source = null; this.mask = null; this.cursor = XCursor.Zero; } else { this.type = CursorType.XC_inherit_parent; this.cursor = XCursor.Zero; try { dpy.Lock(); IntPtr pixmapXImage = ConvertImage.FrameToXImageBitmap(screen, frame); IntPtr maskXImage = ConvertImage.MaskToXImage (screen, frame); source = ConvertImage.XImageMaskToBitmap (screen, pixmapXImage); mask = ConvertImage.XImageMaskToBitmap (screen, maskXImage); Xlib.XSharpDestroyImage(pixmapXImage); Xlib.XSharpDestroyImage(maskXImage); hotspotX = frame.HotspotX; hotspotY = frame.HotspotY; if(frame.Palette != null && frame.Palette[0] == 0) { reverse = true; } } finally { dpy.Unlock(); } } }
// Output RGB data in 15-bit 555 format with a 1-bit alpha channel. private static void RgbAlpha555(Frame frame, int y, byte[] scanline) { int width = frame.Width; byte[] data = frame.Data; int posn, offset, value, component; offset = y * frame.Stride + width * 2; for(posn = (width - 1) * 4; posn >= 0; posn -= 4) { offset -= 2; value = data[offset] | (data[offset + 1] << 8); component = ((value >> 7) & 0xF8); scanline[posn] = (byte)(component | (component >> 5)); component = ((value >> 2) & 0xF8); scanline[posn + 1] = (byte)(component | (component >> 5)); component = ((value << 3) & 0xF8); scanline[posn + 2] = (byte)(component | (component >> 5)); if((value & 0x8000) != 0) { scanline[posn + 3] = 0xFF; } else { scanline[posn + 3] = 0x00; } } }
public void SetFrame(int frame, Frame newFrame) { if(frame >= 0 && frame < numFrames && newFrame != null) { newFrame.NewImage(this); frames[frame] = newFrame; } }
public Frame AddFrame(int width, int height, PixelFormat pixelFormat) { Frame frame = new Frame(this, width, height, pixelFormat); frame.Palette = palette; frame.TransparentPixel = transparentPixel; return AddFrame(frame); }
// This is an integer, generic, low quality algorithm for expanding bitmaps. // A significant speed improvement could be optained by splitting out 1bpp & 4 bpp // Eliminating the many if's. private static void ExpandBmp(Frame oldFrame, Frame newFrame, int oldX, int oldY, int oldWidth, int oldHeight) { byte[] data = oldFrame.Data; byte[] dataOut = newFrame.Data; int sumY = 0; int lineStartNew = 0; int bytesPerPixel = Utils.FormatToBitCount(oldFrame.pixelFormat) / 8; int lineStartBit = 0; bool lineStartNibble = false; // Offset to the oldY. int lineStartOld = oldY * oldFrame.Stride; if (oldFrame.pixelFormat == PixelFormat.Format1bppIndexed) { lineStartOld = oldX / 8; lineStartBit = 7 - (oldX & 0x07); } else if (oldFrame.pixelFormat == PixelFormat.Format4bppIndexed) { lineStartOld = oldX / 2; lineStartNibble = ((oldX & 0x01) == 0); } else { lineStartOld =bytesPerPixel * oldX; } int y = 0; while(y < oldHeight) { int newPixel = lineStartNew; int newPixelBit = 7; bool newPixelNibble = true; int newPixelByte = 0; lineStartNew += newFrame.Stride; int oldPixelBit = lineStartBit; int oldPixel = lineStartOld; int oldPixelByte = -1; bool oldPixelNibble = lineStartNibble; int pix = 0; int x = 0; int sumX = 0; while(x < oldWidth) { sumX += oldWidth; // Write the pixel. // 1bpp format. if (oldFrame.pixelFormat == PixelFormat.Format1bppIndexed) { if (oldPixelByte == -1) oldPixelByte = data[oldPixel]; if ( (oldPixelByte & 1<<oldPixelBit) != 0) newPixelByte |= 1<<newPixelBit; if (newPixelBit == 0) { dataOut[newPixel++] = (byte)(newPixelByte); newPixelBit = 7; newPixelByte = 0; } else newPixelBit--; if(sumX >= newFrame.Width) { x++; // Get the next nibble if (oldPixelBit==0) { oldPixelByte = -1; oldPixel++; oldPixelBit = 7; } else oldPixelBit--; sumX -= newFrame.Width; } } // 4bpp format. else if (oldFrame.pixelFormat == PixelFormat.Format4bppIndexed) { if (oldPixelByte == -1) oldPixelByte = data[oldPixel]; if (oldPixelNibble) pix = oldPixelByte >> 4; else pix = oldPixelByte & 0x0F; if (newPixelNibble) newPixelByte = pix << 4; else dataOut[newPixel++] = (byte)(newPixelByte | pix); newPixelNibble = !newPixelNibble; if(sumX >= newFrame.Width) { x++; // Get the next nibble if (!oldPixelNibble) { oldPixelByte = -1; oldPixel++; } oldPixelNibble = !oldPixelNibble; sumX -= newFrame.Width; } } // All other formats. else { for(int i = 0; i < bytesPerPixel; i++, newPixel++) dataOut[newPixel] = data[oldPixel + i]; if(sumX >= newFrame.Width) { x++; oldPixel += bytesPerPixel; sumX -= newFrame.Width; } } } // There maybe some bits left we need to write if (oldFrame.pixelFormat == PixelFormat.Format1bppIndexed && newPixelBit != 7) dataOut[newPixel++] = (byte)(newPixelByte); if (oldFrame.pixelFormat == PixelFormat.Format4bppIndexed && !newPixelNibble) dataOut[newPixel++] = (byte)(newPixelByte); sumY += oldHeight; if(sumY >= newFrame.Height) { y++; lineStartOld += oldFrame.Stride; oldPixel = lineStartOld; sumY -= newFrame.Height; } } }
// This is an integer, generic high quality algorithm for shrinking bitmaps. // A significant speed improvement could be optained by splitting out the formats // Eliminating the many if's. private static void ShrinkBmp(Frame oldFrame, Frame newFrame, int oldX, int oldY, int oldWidth, int oldHeight) { byte[] data = oldFrame.Data; byte[] dataOut = newFrame.Data; int[] palette = oldFrame.Palette; int lineStart = 0; int lineStartBit = 0; bool lineStartNibble = false; // Calculate the right line start based on the oldX if (oldFrame.pixelFormat == PixelFormat.Format1bppIndexed) { lineStart = oldX / 8; lineStartBit = 7 - (oldX & 0x07); } else if (oldFrame.pixelFormat == PixelFormat.Format4bppIndexed) { lineStart = oldX / 2; lineStartNibble = ((oldX & 0x01) == 0); } else { lineStart =Utils.FormatToBitCount(oldFrame.pixelFormat) / 8 * oldX; } // Offset to the right place based on oldY. lineStart += oldY * oldFrame.Stride; int lineStartOut = 0; int[] rowCoefficients = CreateCoefficients(oldWidth, newFrame.Width); int[] columnCoefficients = CreateCoefficients(oldHeight, newFrame.Height); byte pixelByte1 = 0; byte pixelByte2 = 0; byte pixelByte3 = 0; byte pixelAlpha = 255; byte byteData = 0; // Index for 1bpp format. int bit = lineStartBit; // Preread the byte if we have to. if (oldFrame.pixelFormat == PixelFormat.Format1bppIndexed && lineStartBit > 0) byteData = data[lineStart]; // Index for 4bpp format. bool highNibble = lineStartNibble; // Preread the byte if we have to. if (oldFrame.pixelFormat == PixelFormat.Format4bppIndexed && !highNibble) { byteData = data[lineStart]; } int bufWidth = 4; if (oldFrame.pixelFormat == PixelFormat.Format1bppIndexed) { bufWidth = 1; } int bufLine = bufWidth * newFrame.Width * 4; int bufNextLine = bufWidth * newFrame.Width; uint[] buffer = new uint[bufWidth * 2 * newFrame.Width]; int currentLine = 0; uint temp; int currentYCoeff = 0; int y = 0; while(y < newFrame.Height) { int currentPixel = lineStart; lineStart += oldFrame.Stride; int bufCurrentPixel = currentLine; int bufNextPixel = bufNextLine; int currentXCoeff = 0; int yCoefficient1 = columnCoefficients[currentYCoeff + 1]; bool crossRow = yCoefficient1 > 0; int x = 0; while(x < newFrame.Width) { int yCoefficient = columnCoefficients[currentYCoeff]; int xCoefficient = rowCoefficients[currentXCoeff]; temp = (uint)(xCoefficient * yCoefficient); // Read the color from the particular format. // 1 bpp Format. if (oldFrame.pixelFormat==PixelFormat.Format1bppIndexed) { if (bit == 0) { byteData = data[currentPixel++]; bit = 128; } if ((byteData & bit) > 0) { pixelByte1 = 255; } else { pixelByte1 = 0; } bit = (byte)(bit >>1); buffer[bufCurrentPixel] += temp * pixelByte1; } else { // 32 bpp Format. if (oldFrame.pixelFormat==PixelFormat.Format32bppArgb) { pixelByte1 = data[currentPixel++]; pixelByte2 = data[currentPixel++]; pixelByte3 = data[currentPixel++]; pixelAlpha = data[currentPixel++]; } // 24 bpp Format. else if (oldFrame.pixelFormat==PixelFormat.Format24bppRgb) { pixelByte1 = data[currentPixel++]; pixelByte2 = data[currentPixel++]; pixelByte3 = data[currentPixel++]; } // 16 bpp 555 Format. else if (oldFrame.pixelFormat==PixelFormat.Format16bppRgb555) { pixelByte2 = data[currentPixel++]; pixelByte1 = data[currentPixel++]; pixelByte3 = (byte)(pixelByte2 & 0x1F); pixelByte2 = (byte)(pixelByte1 << 3 & 0x18 | pixelByte2 >> 5 & 0x07); pixelByte1 = (byte)(pixelByte1 >> 2 & 0x1f); pixelByte1 = (byte)((int)pixelByte1 * 255 / 31); pixelByte2 = (byte)((int)pixelByte2 * 255 / 31); pixelByte3 = (byte)((int)pixelByte3 * 255 / 31); } // 16 bpp 565 Format. else if (oldFrame.pixelFormat==PixelFormat.Format16bppRgb565) { pixelByte2 = data[currentPixel++]; pixelByte1 = data[currentPixel++]; pixelByte3 = (byte)(pixelByte2 & 0x1F); pixelByte2 = (byte)(pixelByte1 << 3 & 0x38 | pixelByte2 >> 5 & 0x07); pixelByte1 = (byte)(pixelByte1 >> 3); pixelByte1 = (byte)((int)pixelByte1 * 255 / 31); pixelByte2 = (byte)((int)pixelByte2 * 255 / 63); pixelByte3 = (byte)((int)pixelByte3 * 255 / 31); } // 8 bpp Format. else if (oldFrame.pixelFormat==PixelFormat.Format8bppIndexed) { int paletteColor = palette[data[currentPixel++]]; pixelByte1 = (byte)(paletteColor>>16); pixelByte2 = (byte)(paletteColor>>8); pixelByte3 = (byte)paletteColor; } // 4 bpp Format. else if (oldFrame.pixelFormat==PixelFormat.Format4bppIndexed) { int paletteColor; if (highNibble) { byteData = data[currentPixel++]; paletteColor = palette[byteData >>4]; } else { paletteColor = palette[byteData & 0x0F]; } highNibble = !highNibble; pixelByte1 = (byte)(paletteColor>>16); pixelByte2 = (byte)(paletteColor>>8); pixelByte3 = (byte)paletteColor; } buffer[bufCurrentPixel] += temp * pixelByte1; buffer[bufCurrentPixel+1] += temp * pixelByte2; buffer[bufCurrentPixel+2] += temp * pixelByte3; buffer[bufCurrentPixel+3] += temp * pixelAlpha; } int xCoefficient1 = rowCoefficients[currentXCoeff + 1]; bool crossColumn = xCoefficient1> 0; if(crossColumn) { temp = (uint)(xCoefficient1 * yCoefficient); if (oldFrame.pixelFormat==PixelFormat.Format1bppIndexed) buffer[bufCurrentPixel + 1] += temp * pixelByte1; else { buffer[bufCurrentPixel + 4] += temp * pixelByte1; buffer[bufCurrentPixel + 5] += temp * pixelByte2; buffer[bufCurrentPixel + 6] += temp * pixelByte3; buffer[bufCurrentPixel + 7] += temp * pixelAlpha; } } if(crossRow) { temp = (uint)(xCoefficient * yCoefficient1); if (oldFrame.pixelFormat==PixelFormat.Format1bppIndexed) buffer[bufNextPixel] += temp * pixelByte1; else { buffer[bufNextPixel] += temp * pixelByte1; buffer[bufNextPixel + 1] += temp * pixelByte2; buffer[bufNextPixel + 2] += temp * pixelByte3; buffer[bufNextPixel + 3] += temp * pixelAlpha; } if(crossColumn) { temp = (uint)(xCoefficient1 * yCoefficient1); if (oldFrame.pixelFormat==PixelFormat.Format1bppIndexed) buffer[bufNextPixel + 1] += temp * pixelByte1; else { buffer[bufNextPixel + 4] += temp * pixelByte1; buffer[bufNextPixel + 5] += temp * pixelByte2; buffer[bufNextPixel + 6] += temp * pixelByte3; buffer[bufNextPixel + 7] += temp * pixelAlpha; } } } if(xCoefficient1 != 0) { x++; bufCurrentPixel += bufWidth; bufNextPixel += bufWidth; } currentXCoeff += 2; } if(yCoefficient1 != 0) { // set result line bufCurrentPixel = currentLine; currentPixel = lineStartOut; int endWriteBuffer = bufCurrentPixel + bufWidth * newFrame.Width; // Write the buffer. // 1 bpp format. if (oldFrame.pixelFormat==PixelFormat.Format1bppIndexed) { byte bit1 = 128; byte dataByte1 = 0; for(;bufCurrentPixel < endWriteBuffer; bufCurrentPixel++) { if (buffer[bufCurrentPixel] != 0) { dataByte1 |= bit1; } bit1 =(byte)(bit1 >> 1); if (bit1 == 0) { bit1 = 128; dataOut[currentPixel++] = dataByte1; dataByte1 = 0; } } // Write the last bits if (bit != 128) { dataOut[currentPixel] = dataByte1; } } // 32 bpp format. else if (oldFrame.pixelFormat==PixelFormat.Format32bppArgb) { for(; bufCurrentPixel < endWriteBuffer; bufCurrentPixel++) { dataOut[currentPixel++] = (byte)(buffer[bufCurrentPixel]>> 24); } } // 24 bpp format. else if (oldFrame.pixelFormat==PixelFormat.Format24bppRgb) { while( bufCurrentPixel < endWriteBuffer) { dataOut[currentPixel++] = (byte)(buffer[bufCurrentPixel++]>> 24); dataOut[currentPixel++] = (byte)(buffer[bufCurrentPixel++]>> 24); dataOut[currentPixel++] = (byte)(buffer[bufCurrentPixel++]>> 24); bufCurrentPixel++; // Skip alpha } } // 16 bpp 555 format. else if (oldFrame.pixelFormat==PixelFormat.Format16bppRgb555) { while( bufCurrentPixel < endWriteBuffer) { int r = (byte)(buffer[bufCurrentPixel++]>> 24); int g = (byte)(buffer[bufCurrentPixel++]>> 24); int b = (byte)(buffer[bufCurrentPixel++]>> 24); bufCurrentPixel++; // Skip alpha dataOut[currentPixel++] = (byte)((g<<2 & 0xE0) | (b>>3 & 0x1F)); dataOut[currentPixel++] = (byte)((r>>1 & 0x7C) | (g >>6 & 0x03)); } } // 16 bpp 565 format. else if (oldFrame.pixelFormat==PixelFormat.Format16bppRgb565) { while( bufCurrentPixel < endWriteBuffer) { int r = (byte)(buffer[bufCurrentPixel++]>> 24); int g = (byte)(buffer[bufCurrentPixel++]>> 24); int b = (byte)(buffer[bufCurrentPixel++]>> 24); bufCurrentPixel++; // Skip alpha dataOut[currentPixel++] = (byte)((g<<3 & 0xE0) | (b >> 3 & 0x1F)) ; dataOut[currentPixel++] = (byte)((r & 0xF8) | (g >>5 & 0x07)); } } // 8 bpp format. else if (oldFrame.pixelFormat==PixelFormat.Format8bppIndexed) { while(bufCurrentPixel < endWriteBuffer) { int r = (byte)(buffer[bufCurrentPixel++]>> 24); int g = (byte)(buffer[bufCurrentPixel++]>> 24); int b = (byte)(buffer[bufCurrentPixel++]>> 24); bufCurrentPixel++; // Skip alpha dataOut[currentPixel++] = (byte)Utils.BestPaletteColor(palette, r, g, b); } } // 4 bpp format. else if (oldFrame.pixelFormat==PixelFormat.Format4bppIndexed) { bool highNibble1 = true; int dataByte1 = 0; while(bufCurrentPixel < endWriteBuffer) { int r = (byte)(buffer[bufCurrentPixel++]>> 24); int g = (byte)(buffer[bufCurrentPixel++]>> 24); int b = (byte)(buffer[bufCurrentPixel++]>> 24); bufCurrentPixel++; // Skip alpha int palettePos = (byte)Utils.BestPaletteColor(palette, r, g, b); if (highNibble1) { dataByte1 = palettePos << 4; } else { dataByte1 |= palettePos; dataOut[currentPixel++] = (byte)dataByte1; } highNibble1 = !highNibble1; } // Write the last bits if (!highNibble1) { dataOut[currentPixel] = (byte)dataByte1; } } bufCurrentPixel = bufNextLine; bufNextLine = currentLine; currentLine = bufCurrentPixel; int endClearBuffer = bufNextLine + bufLine/4; for (int c = bufNextLine; c < endClearBuffer; c++) { buffer[c] = 0; } y++; lineStartOut += newFrame.Stride; } currentYCoeff += 2; } }
// Output 16-bit grayscale data. private static void GrayScale16bpp(Frame frame, int y, byte[] scanline) { int width = frame.Width; byte[] data = frame.Data; int posn, offset; offset = y * frame.Stride + width * 2; for(posn = (width - 1) * 2; posn >= 0; posn -= 2) { // Byteswap the data. offset -= 2; scanline[posn] = data[offset + 1]; scanline[posn + 1] = data[offset]; } }
// Output 8-bit indexed data. private static void Indexed8bpp(Frame frame, int y, byte[] scanline) { Array.Copy(frame.Data, y * frame.Stride, scanline, 0, frame.Width); }
// Output 4-bit indexed data. private static void Indexed4bpp(Frame frame, int y, byte[] scanline) { int width = frame.Width; byte[] data = frame.Data; int posn, offset, bit; offset = y * frame.Stride; bit = 4; for(posn = 0; posn < width; ++posn) { scanline[posn] = (byte)((data[offset] >> bit) & 0x0F); bit -= 4; if(bit < 0) { ++offset; bit = 4; } } }
// Output 1-bit indexed data. private static void Indexed1bpp(Frame frame, int y, byte[] scanline) { int width = frame.Width; byte[] data = frame.Data; int posn, offset, bit; offset = y * frame.Stride; bit = 0x80; for(posn = 0; posn < width; ++posn) { if((data[offset] & bit) != 0) { scanline[posn] = 1; } else { scanline[posn] = 0; } bit >>= 1; if(bit == 0) { ++offset; bit = 0x80; } } }
// Output 64-bit RGB data with an alpha channel. private static void RgbAlpha64bpp(Frame frame, int y, byte[] scanline) { int width = frame.Width; byte[] data = frame.Data; int posn, offset; offset = y * frame.Stride + width * 8; for(posn = (width - 1) * 8; posn >= 0; posn -= 8) { // Convert BGR data into RGB data and byteswap. offset -= 8; scanline[posn] = data[offset + 5]; scanline[posn + 1] = data[offset + 4]; scanline[posn + 2] = data[offset + 3]; scanline[posn + 3] = data[offset + 1]; scanline[posn + 4] = data[offset + 1]; scanline[posn + 5] = data[offset]; scanline[posn + 6] = data[offset + 7]; scanline[posn + 7] = data[offset + 6]; } }
// Output 32-bit RGB data with an alpha channel. private static void RgbAlpha32bpp(Frame frame, int y, byte[] scanline) { int width = frame.Width; byte[] data = frame.Data; int posn, offset; offset = y * frame.Stride + width * 4; for(posn = (width - 1) * 4; posn >= 0; posn -= 4) { // Convert BGR data into RGB data. offset -= 4; scanline[posn] = data[offset + 2]; scanline[posn + 1] = data[offset + 1]; scanline[posn + 2] = data[offset]; scanline[posn + 3] = data[offset + 3]; } }
public static void Copy(Frame dest, int x, int y, int width, int height, Frame source, int sourceX, int sourceY) { // Developers should be aware of any costly conversions. // So we don't automatically match the depths. if (source.pixelFormat != dest.pixelFormat) { throw new InvalidOperationException(); } if (x < 0 || y < 0 || width <= 0 || height <= 0) { throw new ArgumentOutOfRangeException(); } if (x + width > dest.width) { width = dest.width - x; } if (y + height > dest.height) { height = dest.height - x; } if (source.width - sourceX < width) { width = source.width - sourceX; } if (source.height - sourceY < height) { height = source.height - sourceY; } //TODO: // If we are copying an index bitmap, we need to find the color // in the destination palette that is closest to the color we are // copying to. We would also need to add colors to the palette, // if there is space and optionally optimize the palette. // For now we just overwrite the old palette. if (source.palette != null) { dest.palette = (int[])source.palette.Clone(); } int bits = Utils.FormatToBitCount(source.pixelFormat); Copy (bits, dest.data, dest.stride, x, y, width, height, source.Data, source.stride, sourceX, sourceY); //TODO: // The mask is not taken into account when copying. We need to // look at adding alpha support. // For now, just copy over the mask. if (source.Mask != null) { dest.AddMask(); Copy(1, dest.mask, dest.maskStride, x, y, width, height, source.mask, source.maskStride, sourceX, sourceY); } }
// Copy as much of frame as possible to the x, y position of this frame. public void Copy(Frame frame, int x, int y) { Copy(this, x, y, width, height, frame, 0, 0); }
private void CompileFrameData(Frame f) { int width = f.Width; int height = f.Height; int stride = f.Stride; int fMaskStride = f.MaskStride; int transparentPixel = f.TransparentPixel; int[] fPalette = f.Palette; byte[] fData = f.Data; byte[] fMask = f.Mask; PixelFormat pixelFormat = f.PixelFormat; int maskStride = (width + 7) / 8; byte[] mask = new byte[height*maskStride]; if(fMask != null) { // the mask in the frame is padded to 4-bytes, while the // masks in postscript are padded to 1-byte, so perform a // conversion if necessary, but direct copy if possible if(maskStride == fMaskStride) { Array.Copy(fMask, 0, mask, 0, mask.Length); } else { int i = 0; int j = 0; int k = 0; while(i < height) { Array.Copy(fMask, j, mask, k, maskStride); ++i; j += fMaskStride; k += maskStride; } } } byte[] data = new byte[width*3*height]; int offset = 0; int maskOffset = 0; for(int y = 0, i = 0; y < height; ++y) { for(int x = 0, ptr = offset; x < width; ++x) { switch(pixelFormat) { case PixelFormat.Format64bppPArgb: { byte a = fData[ptr+7]; if(a != 0) { data[i+2] = (byte)((fData[ptr+1] * 255) / a); data[i+1] = (byte)((fData[ptr+3] * 255) / a); data[i] = (byte)((fData[ptr+5] * 255) / a); } i += 3; ptr += 8; } break; case PixelFormat.Format64bppArgb: { data[i+2] = fData[ptr+1]; data[i+1] = fData[ptr+3]; data[i] = fData[ptr+5]; i += 3; ptr += 8; } break; case PixelFormat.Format48bppRgb: { data[i+2] = fData[ptr+1]; data[i+1] = fData[ptr+3]; data[i] = fData[ptr+5]; i += 3; ptr += 6; } break; case PixelFormat.Format32bppPArgb: { byte a = fData[ptr+3]; if(a != 0) { data[i+2] = (byte)((fData[ptr] * 255) / a); data[i+1] = (byte)((fData[ptr+1] * 255) / a); data[i] = (byte)((fData[ptr+2] * 255) / a); } i += 3; ptr += 4; } break; case PixelFormat.Format32bppArgb: { data[i+2] = fData[ptr++]; data[i+1] = fData[ptr++]; data[i] = fData[ptr++]; i += 3; ++ptr; } break; case PixelFormat.Format24bppRgb: { data[i+2] = fData[ptr++]; data[i+1] = fData[ptr++]; data[i] = fData[ptr++]; i += 3; } break; case PixelFormat.Format16bppRgb565: { int g = fData[ptr++]; int r = fData[ptr++]; int b = (g & 0x1F) * 255 / 31; g = (r << 3 & 0x38 | g >> 5 & 0x07) * 255 / 63; r = (r >> 3) * 255 / 31; data[i++] = (byte)r; data[i++] = (byte)g; data[i++] = (byte)b; } break; case PixelFormat.Format16bppRgb555: { int g = fData[ptr++]; int r = fData[ptr++]; int b = (g & 0x1F) * 255 / 31; g =( r << 3 & 0x18 | g >> 5 & 0x07) * 255 / 31; r = ( r >> 2 & 0x1F) * 255 / 31; data[i++] = (byte)r; data[i++] = (byte)g; data[i++] = (byte)b; } break; case (PixelFormat.Format16bppGrayScale): { ++ptr; byte all = data[ptr++]; data[i++] = (byte)all; data[i++] = (byte)all; data[i++] = (byte)all; } break; case PixelFormat.Format8bppIndexed: { int idx = fData[ptr++]; int color = fPalette[idx]; data[i++] = (byte)(color >> 16); data[i++] = (byte)(color >> 8); data[i++] = (byte)(color); if(transparentPixel == idx) { int mptr = maskOffset + x/8; mask[mptr] |= (byte)(1 << (7 - (x & 0x07))); } } break; case PixelFormat.Format4bppIndexed: { int idx = fData[ptr++] >> 4; int color = fPalette[idx]; data[i++] = (byte)(color >> 16); data[i++] = (byte)(color >> 8); data[i++] = (byte)(color); if(transparentPixel == idx) { int mptr = maskOffset + x/8; mask[mptr] |= (byte)(1 << (7 - (x & 0x07))); } ++x; if(x < width) { idx = fData[ptr++] & 0x0F; color = fPalette[idx]; data[i++] = (byte)(color >> 16); data[i++] = (byte)(color >> 8); data[i++] = (byte)(color); if(transparentPixel == idx) { int mptr = maskOffset + x/8; mask[mptr] |= (byte)(1 << (7 - (x & 0x07))); } } } break; case PixelFormat.Format1bppIndexed: { byte r0 = (byte)(fPalette[0] >> 16); byte g0 = (byte)(fPalette[0] >> 8); byte b0 = (byte)(fPalette[0]); byte r1 = (byte)(fPalette[1] >> 16); byte g1 = (byte)(fPalette[1] >> 8); byte b1 = (byte)(fPalette[1]); byte val = fData[ptr++]; byte m = 0x80; int j = 0; int limit = ((width - x) < 8) ? (width - x) : 8; int mptr = ptr-1; while(j < limit) { m = (byte)(m >> j); if((val & m) == 0) { data[i++] = r0; data[i++] = g0; data[i++] = b0; if(transparentPixel == 0) { mask[mptr] |= (byte)(1 << j); } } else { data[i++] = r1; data[i++] = g1; data[i++] = b1; if(transparentPixel == 1) { mask[mptr] |= (byte)(1 << j); } } ++j; } x += j; } break; default: { imageDataDict = null; imageData = null; maskDataDict = null; maskDataStream = null; return; } // Not reached. } offset += stride; maskOffset += maskStride; } } imageData = PostscriptGraphics.ASCII85Encode(data); maskDataStream = String.Format ("currentfile /ASCII85Decode filter " + "/ReusableStreamDecode filter " + "{0} /maskstream exch def ", PostscriptGraphics.ASCII85Encode(mask)); }
private void SetPixelLine(Frame frame, int x, int yPtr, int color) { switch (frame.PixelFormat) { case (PixelFormat.Format24bppRgb): { int ptr = yPtr + x * 3; frame.Data[ptr++] = (byte)color; frame.Data[ptr++] = (byte)(color>>8); frame.Data[ptr++] = (byte)(color>>16); break; } default: throw new NotSupportedException(); } }
/// <summary> /// <para>Constructs a new <see cref="T:Xsharp.Image"/> instance /// from a <see cref="T:DotGNU.Images.Frame"/> instance.</para> /// </summary> /// /// <param name="frame"> /// <para>The frame to load the image from.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>The <paramref name="frame"/> parameter is /// <see langword="null"/>.</para> /// </exception> /// /// <exception cref="T:Xsharp.XInvalidOperationException"> /// <para>Raised if <paramref name="filename"/> could not be /// loaded for some reason.</para> /// </exception> public Image(Frame frame) : this(null, frame) {}
// Set the cursor. The toolkit may ignore "frame" if it already // has a system-defined association for "cursorType". Setting // "cursorType" to "ToolkitCursorType.InheritParent" will reset // the cursor to be the same as the parent window's. void IToolkitWindow.SetCursor(ToolkitCursorType cursorType, Frame frame) { DrawingWindow.ModifyCursor(this, cursorType, frame); }
/// <summary> /// <para>Constructs a new <see cref="T:Xsharp.Image"/> instance /// from a <see cref="T:DotGNU.Images.Frame"/> instance.</para> /// </summary> /// /// <param name="screen"> /// <para>The screen upon which to create the new image.</para> /// </param> /// /// <param name="frame"> /// <para>The frame to load the image from.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>The <paramref name="frame"/> parameter is /// <see langword="null"/>.</para> /// </exception> /// /// <exception cref="T:Xsharp.XInvalidOperationException"> /// <para>Raised if <paramref name="filename"/> could not be /// loaded for some reason.</para> /// </exception> public Image(Screen screen, Frame frame) { Display dpy; if(frame == null) { throw new ArgumentNullException("frame"); } if(screen != null) { dpy = screen.DisplayOfScreen; } else { dpy = Application.Primary.Display; screen = dpy.DefaultScreenOfDisplay; } this.screen = screen; try { dpy.Lock(); pixmapXImage = ConvertImage.FrameToXImage(screen, frame); maskXImage = ConvertImage.MaskToXImage(screen, frame); } finally { dpy.Unlock(); } }
public Frame AddFrame(Frame frame) { if(frames == null) { frames = new Frame[] {frame}; numFrames = 1; } else { Frame[] newFrames = new Frame [numFrames + 1]; Array.Copy(frames, 0, newFrames, 0, numFrames); frames = newFrames; frames[numFrames] = frame; ++numFrames; } return frame; }
// Create a device independant bitmap from a frame. Optionally set all bits that are masked to black. // This is required for icons. private IntPtr HandleFromBitmap(Frame frame, bool andMask) { // By default we use the data straight from the frame. byte[] data = frame.Data; if (andMask) { //TODO: this could be slow. // Create a new image that we will copy the pixels to, leaving the masked pixels black. DotGNU.Images.Image newImage = new DotGNU.Images.Image(frame.Width, frame.Height, frame.PixelFormat); Frame newFrame = newImage.AddFrame(); data = new byte[data.Length]; for (int y = 0; y < frame.Height; y++) { for (int x = 0; x < frame.Width; x++) { if (frame.GetMask(x, y) != 0) newFrame.SetPixel(x, y, frame.GetPixel(x, y)); } } data = newFrame.Data; } // Create BITMAPINFO structure. int bitmapInfoSize = 40; int bitCount = frame.BitsPerPixel; // Do we have a palette? if(bitCount <= 8) bitmapInfoSize += 1 << bitCount * 4; byte[] bitmapInfo = new byte[bitmapInfoSize]; // Build and write the BITMAPINFOHEADER structure. WriteInt32(bitmapInfo, 0, 40);// biSize WriteInt32(bitmapInfo, 4, frame.Width); WriteInt32(bitmapInfo, 8, -frame.Height);// upside down so make the height negative. WriteUInt16(bitmapInfo, 12, 1);// biPlanes WriteUInt16(bitmapInfo, 14, bitCount); WriteInt32(bitmapInfo, 16, 0);// biCompression WriteInt32(bitmapInfo, 20, 0);// size of image WriteInt32(bitmapInfo, 24, 3780);// biXPelsPerMeter WriteInt32(bitmapInfo, 28, 3780);// biYPelsPerMeter WriteInt32(bitmapInfo, 32, 0); // biClrUsed WriteInt32(bitmapInfo, 36, 0); // biClrImportant // Write the palette. if(bitCount <= 8) { int count = (1 << bitCount); for(int index = 0; index < count; ++index) { if(frame.Palette != null && index < frame.Palette.Length) WriteBGR(bitmapInfo, index * 4 + 40, frame.Palette[index]); else { // Short palette: pad with black pixels. WriteBGR(bitmapInfo, index * 4 + 40, 0); } } } return Win32.Api.CreateDIBitmap( Win32.Api.GetDC(hwnd), bitmapInfo, 4 /*CBM_INIT*/, data, bitmapInfo, 0 /*DIB_RGB_COLORS*/); }
// Set the cursor. The toolkit may ignore "frame" if it already // has a system-defined association for "cursorType". Setting // "cursorType" to "ToolkitCursorType.InheritParent" will reset // the cursor to be the same as the parent window's. void IToolkitWindow.SetCursor(ToolkitCursorType cursorType, Frame frame) { // TODO }
// Output RGB data in 16-bit 565 format. private static void Rgb565(Frame frame, int y, byte[] scanline) { int width = frame.Width; byte[] data = frame.Data; int posn, offset, value, component; offset = y * frame.Stride + width * 2; for(posn = (width - 1) * 3; posn >= 0; posn -= 3) { offset -= 2; value = data[offset] | (data[offset + 1] << 8); component = ((value >> 8) & 0xF8); scanline[posn] = (byte)(component | (component >> 5)); component = ((value >> 3) & 0xFC); scanline[posn + 1] = (byte)(component | (component >> 6)); component = ((value << 3) & 0xF8); scanline[posn + 2] = (byte)(component | (component >> 5)); } }