public override ImageData Read(IBinaryStream file, ImageMetaData info) { using (var reader = new GsaReader(file, (GsaMetaData)info)) { var pixels = reader.Unpack(); if (PartFileNameRe.IsMatch(file.Name)) { var base_name = Path.ChangeExtension(file.Name, "GSA"); if (VFS.FileExists(base_name)) { try { var image = TryBlendImage(base_name, reader, info); if (image != null) { return(image); } } catch { /* ignore failed blending attempt */ } } } return(ImageData.CreateFlipped(info, reader.Format, null, pixels, reader.Stride)); } }
ImageData TryBlendImage(string base_name, GsaReader overlay, ImageMetaData overlay_info) { int ovl_x = overlay_info.OffsetX; int ovl_y = overlay_info.OffsetY; int ovl_width = (int)overlay_info.Width; int ovl_height = (int)overlay_info.Height; if (ovl_x < 0) { ovl_width += ovl_x; ovl_x = 0; } if (ovl_y < 0) { ovl_height += ovl_y; ovl_y = 0; } using (var input = VFS.OpenBinaryStream(base_name)) { var base_info = ReadMetaData(input) as GsaMetaData; if (null == base_info) { return(null); } int base_width = (int)base_info.Width; int base_height = (int)base_info.Height; if (checked (ovl_x + ovl_width) > base_width) { ovl_width = base_width - ovl_x; } if (checked (ovl_y + ovl_height) > base_height) { ovl_height = base_height - ovl_y; } if (ovl_height <= 0 || ovl_width <= 0) { return(null); } input.Position = 0; var reader = new GsaReader(input, base_info); var base_pixels = reader.Unpack(); int src_pixel_size = overlay.PixelSize; int dst_pixel_size = reader.PixelSize; int dst = ovl_y * reader.Stride + ovl_x * dst_pixel_size; int src = 0; for (int y = 0; y < ovl_height; ++y) { int src_pixel = src; int dst_pixel = dst; for (int x = 0; x < ovl_width; ++x) { int src_alpha = overlay.Data[src_pixel + 3]; if (src_alpha > 0) { if (0xFF == src_alpha) { Buffer.BlockCopy(overlay.Data, src_pixel, base_pixels, dst_pixel, dst_pixel_size); } else // assume destination has no alpha channel { base_pixels[dst_pixel + 0] = (byte)((overlay.Data[src_pixel + 0] * src_alpha + base_pixels[dst_pixel + 0] * (0xFF - src_alpha)) / 0xFF); base_pixels[dst_pixel + 1] = (byte)((overlay.Data[src_pixel + 1] * src_alpha + base_pixels[dst_pixel + 1] * (0xFF - src_alpha)) / 0xFF); base_pixels[dst_pixel + 2] = (byte)((overlay.Data[src_pixel + 2] * src_alpha + base_pixels[dst_pixel + 2] * (0xFF - src_alpha)) / 0xFF); } } src_pixel += src_pixel_size; dst_pixel += dst_pixel_size; } src += overlay.Stride; dst += reader.Stride; } return(ImageData.CreateFlipped(base_info, reader.Format, null, base_pixels, reader.Stride)); } }