private void ParseChannelValue(Debugger debugger, string type, out ChannelValueKind channelValueKind, out int channelValueSize) { channelValueKind = ChannelValueKind.Unknown; channelValueSize = 0; string rawType = type; if (type == "unsigned char" || type == "unsigned short" || type == "unsigned int" || type == "unsigned long" || type == "unsigned __int64") { channelValueKind = ChannelValueKind.UnsignedIntegral; } else if (type == "char" || // TODO: this could actually depend on compiler flags type == "signed char" || type == "short" || type == "signed short" || type == "int" || type == "signed int" || type == "long" || type == "signed long" || type == "__int64" || type == "signed __int64") { channelValueKind = ChannelValueKind.SignedIntegral; } else if (type == "float" || type == "double") { channelValueKind = ChannelValueKind.FloatingPoint; } else if (Util.TypeId(type) == "boost::gil::scoped_channel_value") { List <string> tparams = Util.Tparams(type); if (tparams.Count >= 1) { rawType = tparams[0]; if (rawType == "float" || rawType == "double") { // NOTE: Assuming scope [0, 1] channelValueKind = ChannelValueKind.ScopedFloatingPoint; } } } channelValueSize = channelValueKind != ChannelValueKind.Unknown ? GetSizeOfType(debugger, rawType) : 0; }
byte[] GetChannelsInterleaved(byte[] memory, int pixelIndex, ChannelValueKind channelValueKind, int channelSize, int channelsCount) { byte[] result = new byte[channelsCount]; int offset = pixelIndex * channelSize * channelsCount; if (channelSize == 1) { Buffer.BlockCopy(memory, offset, result, 0, channelsCount); if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(result); } } else if (channelSize == 2) { ushort[] tmp = new ushort[channelsCount]; Buffer.BlockCopy(memory, offset, tmp, 0, 2 * channelsCount); if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(tmp); } ConvertChannels(tmp, result); } else if (channelSize == 4) { if (channelValueKind == ChannelValueKind.UnsignedIntegral || channelValueKind == ChannelValueKind.SignedIntegral) { uint[] tmp = new uint[channelsCount]; Buffer.BlockCopy(memory, offset, tmp, 0, 4 * channelsCount); if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(tmp); } ConvertChannels(tmp, result); } else { float[] tmp = new float[channelsCount]; Buffer.BlockCopy(memory, offset, tmp, 0, 4 * channelsCount); if (channelValueKind == ChannelValueKind.FloatingPoint) { ConvertChannels(tmp, result); } else // ScopedFloatingPoint { ConvertChannelsScoped(tmp, result); } } } else if (channelSize == 8) { if (channelValueKind == ChannelValueKind.UnsignedIntegral || channelValueKind == ChannelValueKind.SignedIntegral) { ulong[] tmp = new ulong[channelsCount]; Buffer.BlockCopy(memory, offset, tmp, 0, 8 * channelsCount); if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(tmp); } ConvertChannels(tmp, result); } else { double[] tmp = new double[channelsCount]; Buffer.BlockCopy(memory, offset, tmp, 0, 8 * channelsCount); if (channelValueKind == ChannelValueKind.FloatingPoint) { ConvertChannels(tmp, result); } else // ScopedFloatingPoint { ConvertChannelsScoped(tmp, result); } } } else { result = null; } return(result); }
public override ExpressionDrawer.IDrawable Load(MemoryReader mreader, Debugger debugger, string name, string type, LoadCallback callback) { // NOTE: If the image is not created at the point of debugging, so the variable is // uninitialized, the size may be out of bounds of int32 range. In this case the // exception is thrown here and this is ok. However if there is some garbage in // memory random size could be loaded here. Then also the memory probably points // to some random place in memory (maybe protected?) so the result will probably // be another exception which is fine or an image containing noise from memory. int width = ExpressionParser.LoadSize(debugger, name + "._view._dimensions.x"); int height = ExpressionParser.LoadSize(debugger, name + "._view._dimensions.y"); if (width < 1 || height < 1) { return(null); } string pixelType, isPlanarStr; if (!Util.Tparams(type, out pixelType, out isPlanarStr)) { return(null); } string pixelId = Util.TypeId(pixelType); if (pixelId != "boost::gil::pixel") { return(null); } bool isPlanar = (isPlanarStr == "1"); string channelValueType, layoutType; if (!Util.Tparams(pixelType, out channelValueType, out layoutType)) { return(null); } string layoutId = Util.TypeId(layoutType); if (layoutId != "boost::gil::layout") { return(null); } string colorSpaceType, channelMappingType; if (!Util.Tparams(layoutType, out colorSpaceType, out channelMappingType)) { return(null); } ChannelValueKind channelValueKind = ChannelValueKind.Unknown; int channelValueSize = 0; ParseChannelValue(debugger, channelValueType, out channelValueKind, out channelValueSize); if (channelValueKind == ChannelValueKind.Unknown || channelValueSize == 0) { return(null); } string colorSpaceId = Util.TypeId(colorSpaceType); ColorSpace colorSpace = ParseColorSpace(colorSpaceType); int colorSpaceSize = ColorSpaceSize(colorSpace); if (colorSpace == ColorSpace.Unknown || colorSpaceSize == 0) { return(null); } Layout layout = ParseChannelMapping(colorSpace, channelMappingType); if (layout == Layout.Unknown) { return(null); } if (channelValueSize != 1 && channelValueSize != 2 && channelValueSize != 4 && channelValueSize != 8) { return(null); } // TODO: size_t? ulong? int bytesCount = width * height * colorSpaceSize * channelValueSize; byte[] memory = new byte[bytesCount]; bool isLoaded = false; if (mreader != null) { ulong address = ExpressionParser.GetValueAddress(debugger, name + "._memory[0]"); if (address == 0) { return(null); } isLoaded = mreader.ReadBytes(address, memory); } if (!isLoaded) { // Parsing the memory byte by byte may take very long time // even for small images. So don't do it. return(null); } LayoutMapper layoutMapper = GetLayoutMapper(layout); if (layoutMapper == null) { return(null); } // Use Pixel format native to Gil Image? System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height); for (int j = 0; j < height; ++j) { for (int i = 0; i < width; ++i) { int pixelIndex = (j * width + i); // The raw bytes are converted into channel values pixel by pixel. // It could be more efficient to convert all channel values at once first // and only create pixels from array of channels in this loop. // Another thing is that when channels are always converted to byte // the information is lost. This information could be used during potential // conversion in GetColor() below (cmyk->rgb). Channels could be returned // as float[]. In practice the eye will probably not notice the difference. byte[] channels = isPlanar ? GetChannelsPlanar(memory, pixelIndex, channelValueKind, channelValueSize, colorSpaceSize) : GetChannelsInterleaved(memory, pixelIndex, channelValueKind, channelValueSize, colorSpaceSize); if (channels == null) { return(null); } System.Drawing.Color c = layoutMapper.GetColor(channels); bmp.SetPixel(i, j, c); // TODO: Checked per pixel. Too often? // But it's the same for geometries (ForEachMemoryBlock). if (!callback()) { return(null); } } } return(new ExpressionDrawer.Image(bmp)); }
byte[] GetChannelsPlanar(byte[] memory, int pixelIndex, ChannelValueKind channelValueKind, int channelSize, int channelsCount) { byte[] result = new byte[channelsCount]; int rowSize = memory.Length / channelsCount; int offset = pixelIndex * channelSize; if (channelSize == 1) { for (int i = 0; i < channelsCount; ++i) { //Buffer.BlockCopy(memory, i * rowSize + offset, result, i, 1); result[i] = memory[i * rowSize + offset]; } if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(result); } } else if (channelSize == 2) { ushort[] tmp = new ushort[channelsCount]; for (int i = 0; i < channelsCount; ++i) { Buffer.BlockCopy(memory, i * rowSize + offset, tmp, 2 * i, 2); } if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(tmp); } ConvertChannels(tmp, result); } else if (channelSize == 4) { if (channelValueKind == ChannelValueKind.UnsignedIntegral || channelValueKind == ChannelValueKind.SignedIntegral) { uint[] tmp = new uint[channelsCount]; for (int i = 0; i < channelsCount; ++i) { Buffer.BlockCopy(memory, i * rowSize + offset, tmp, 4 * i, 4); } if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(tmp); } ConvertChannels(tmp, result); } else { float[] tmp = new float[channelsCount]; for (int i = 0; i < channelsCount; ++i) { Buffer.BlockCopy(memory, i * rowSize + offset, tmp, 4 * i, 4); } if (channelValueKind == ChannelValueKind.FloatingPoint) { ConvertChannels(tmp, result); } else // ScopedFloatingPoint { ConvertChannelsScoped(tmp, result); } } } else if (channelSize == 8) { if (channelValueKind == ChannelValueKind.UnsignedIntegral || channelValueKind == ChannelValueKind.SignedIntegral) { ulong[] tmp = new ulong[channelsCount]; for (int i = 0; i < channelsCount; ++i) { Buffer.BlockCopy(memory, i * rowSize + offset, tmp, 8 * i, 8); } if (channelValueKind == ChannelValueKind.SignedIntegral) { SignedToUnsigned(tmp); } ConvertChannels(tmp, result); } else { double[] tmp = new double[channelsCount]; for (int i = 0; i < channelsCount; ++i) { Buffer.BlockCopy(memory, i * rowSize + offset, tmp, 8 * i, 8); } if (channelValueKind == ChannelValueKind.FloatingPoint) { ConvertChannels(tmp, result); } else // ScopedFloatingPoint { ConvertChannelsScoped(tmp, result); } } } else { result = null; } return(result); }