Esempio n. 1
0
		private string BuildMobImageSmall(ViewableMonster mob) {
			var iconColumnValue = mob.Icon;
			var iconName = iconColumnValue.Substring(0, 4);
			if (listMonsters.SmallImageList.Images.ContainsKey(iconName) == false) {
				// [M014]010
				var iconFilename = string.Format("{0}.dds", iconName);
				var iconFilepath = Path.Combine(MobIconDir, iconFilename);
				if (File.Exists(iconFilepath)) {

					var dds = new DdsFile();
					using (var stream = File.OpenRead(iconFilepath)) {
						dds.Deserialize(stream);
					}

					var png = dds.AsPng();
					listMonsters.SmallImageList.Images.Add(iconName, png);
					listMonsters.LargeImageList.Images.Add(iconName, png);
				}
			}

			return iconName;
		}
Esempio n. 2
0
        /// <summary>
        /// Apply <see cref="HSVShift"/> values to this DDS image based on the
        /// channels in the <paramref name="mask"/>.
        /// </summary>
        /// <param name="mask">A DDS image file, each colourway acting as a mask channel.</param>
        /// <param name="ch1Shift">A shift to apply to the image when the first channel of the mask is active.</param>
        /// <param name="ch2Shift">A shift to apply to the image when the second channel of the mask is active.</param>
        /// <param name="ch3Shift">A shift to apply to the image when the third channel of the mask is active.</param>
        /// <param name="ch4Shift">A shift to apply to the image when the fourth channel of the mask is active.</param>
        public void MaskedHSVShift(DdsFile mask, HSVShift ch1Shift, HSVShift ch2Shift, HSVShift ch3Shift, HSVShift ch4Shift)
        {
            if (!SupportsHSV) return;

            maskInEffect = maskInEffect || !ch1Shift.IsEmpty || !ch2Shift.IsEmpty || !ch3Shift.IsEmpty || !ch4Shift.IsEmpty;

            if (!maskInEffect) return;

            if (!ch1Shift.IsEmpty) MaskedHSVShift(mask, hsvData, x => x.R() > 0, ch1Shift);
            if (!ch2Shift.IsEmpty) MaskedHSVShift(mask, hsvData, x => x.G() > 0, ch2Shift);
            if (!ch3Shift.IsEmpty) MaskedHSVShift(mask, hsvData, x => x.B() > 0, ch3Shift);
            if (!ch4Shift.IsEmpty) MaskedHSVShift(mask, hsvData, x => x.A() > 0, ch4Shift);

            currentImage = ColorHSVA.ToArrayARGB(hsvData);
        }
Esempio n. 3
0
 void MaskedApplyImage(DdsFile mask, Channel channel, uint[] image, Size imageSize)
 {
     MaskedApply(this.currentImage, this.Size, mask.currentImage, mask.Size, channel, (x, y) => image[((y % imageSize.Height) * imageSize.Width) + (x % imageSize.Width)]);
 }
Esempio n. 4
0
        /// <summary>
        /// Creates an image from a given <see cref="T:DdsFile"/>.
        /// If <paramref name="supportHSV"/> is true, also creates an HSVa-encoded version of the image.
        /// </summary>
        /// <param name="image"><see cref="T:DdsFile"/> to clone.</param>
        /// <param name="supportHSV">When true, create an HSVa-encoded version of the image.</param>
        public void CreateImage(DdsFile image, bool supportHSV)
        {
            width = image.width;
            height = image.height;
            useBlockCompression = image.useBlockCompression;
            useLuminence = image.useLuminence;
            alphaDepth = image.alphaDepth;

            baseImage = (uint[])image.currentImage.Clone();

            currentImage = (uint[])baseImage.Clone();
            if (supportHSV) UpdateHSVData();
        }
Esempio n. 5
0
 /// <summary>
 /// Creates a mask with given <paramref name="maskChannels"/> active and of given <paramref name="width"/> and <paramref name="height"/>.
 /// </summary>
 /// <param name="maskChannels">Which channels in the mask should be activated.</param>
 /// <param name="width">Width of image.</param>
 /// <param name="height">Height of image.</param>
 public void CreateMask(MaskChannel maskChannels, int width, int height)
 {
     ClearMask();
     ddsMask = new DdsFile();
     ddsMask.CreateImage(
         MaskChannelToByte(maskChannels, MaskChannel.C1),
         MaskChannelToByte(maskChannels, MaskChannel.C2),
         MaskChannelToByte(maskChannels, MaskChannel.C3),
         MaskChannelToByte(maskChannels, MaskChannel.C4),
         width, height, false);
 }
Esempio n. 6
0
 /// <summary>
 /// Load a mask to use for HSV shifting or masked application of colours.
 /// Clears any mask currently applied.
 /// </summary>
 /// <param name="mask"></param>
 public void LoadMask(Stream mask)
 {
     ClearMask();
     try
     {
         base.Enabled = false;
         Application.UseWaitCursor = true;
         Application.DoEvents();
         this.ddsMask = new DdsFile();
         this.ddsMask.Load(mask, false);//only want the pixmap data
     }
     finally { base.Enabled = true; Application.UseWaitCursor = false; Application.DoEvents(); }
 }
Esempio n. 7
0
        /// <summary>
        /// Get a copy of the current DDS image as a <see cref="DdsFile"/>.
        /// </summary>
        /// <returns>A new <see cref="DdsFile"/> copy of the current DDS image.</returns>
        public DdsFile GetDdsFile()
        {
            if (!this.loaded || ddsFile == null) return null;

            DdsFile res = new DdsFile();
            res.CreateImage(ddsFile, false);
            return res;
        }
Esempio n. 8
0
 /// <summary>
 /// Sets the DDS image for this <see cref="DDSPanel"/> from the given <paramref name="ddsfile"/>.
 /// <see cref="SupportsHSV"/> is determined from the <see cref="DdsFile.SupportsHSV"/> value.
 /// </summary>
 /// <param name="ddsfile">A <see cref="DdsFile"/> to display in this <see cref="DDSPanel"/>.</param>
 public void DDSLoad(DdsFile ddsfile)
 {
     this.ddsFile = ddsfile;
     loaded = true;
     this.supportHSV = ddsfile.SupportsHSV;
     ckb_CheckedChanged(null, null);
 }
Esempio n. 9
0
        /// <summary>
        /// Set the colour of the image based on the channels in the <paramref name="mask"/>.
        /// </summary>
        /// <param name="mask">The <see cref="System.IO.Stream"/> containing the DDS image to use as a mask.</param>
        /// <param name="ch1Colour">(Nullable) ARGB colour to the image when the first channel of the mask is active.</param>
        /// <param name="ch2Colour">(Nullable) ARGB colour to the image when the second channel of the mask is active.</param>
        /// <param name="ch3Colour">(Nullable) ARGB colour to the image when the third channel of the mask is active.</param>
        /// <param name="ch4Colour">(Nullable) ARGB colour to the image when the fourth channel of the mask is active.</param>
        public void MaskedSetColour(DdsFile mask, uint? ch1Colour, uint? ch2Colour, uint? ch3Colour, uint? ch4Colour)
        {

            maskInEffect = maskInEffect || ch1Colour.HasValue || ch2Colour.HasValue || ch3Colour.HasValue || ch4Colour.HasValue;

            if (!maskInEffect) return;

            if (ch1Colour.HasValue) MaskedSetColour(mask, x => x.R() > 0, ch1Colour.Value);
            if (ch2Colour.HasValue) MaskedSetColour(mask, x => x.G() > 0, ch2Colour.Value);
            if (ch3Colour.HasValue) MaskedSetColour(mask, x => x.B() > 0, ch3Colour.Value);
            if (ch4Colour.HasValue) MaskedSetColour(mask, x => x.A() > 0, ch4Colour.Value);

            if (SupportsHSV) UpdateHSVData();
        }
Esempio n. 10
0
        /// <summary>
        /// Converts the R, G and B channels of the supplied <paramref name="image"/> to greyscale
        /// and loads this into the Alpha channel of the current image.
        /// The image format will be changed to one supporting an 8-bit Alpha channel, if required.
        /// </summary>
        /// <param name="image"><see cref="DdsFile"/> to extract greyscale data from for alpha channel.</param>
        public void SetAlphaFromGreyscale(DdsFile image)
        {
            AlphaDepth = UseDXT ? 5 : 8;

            SetPixels((x, y, value) =>
            {
                uint alpha;
                lock (image)
                {
                    uint srcValue = image.GetPixel(x % image.width, y % image.height);
                    alpha = ((srcValue.R() + srcValue.G() + srcValue.B()) / 3) & 0xff;
                }

                return (value & 0x00FFFFFF) | (alpha << 24);
            });

            if (SupportsHSV) UpdateHSVData();
        }
Esempio n. 11
0
 /// <summary>
 /// Get a new DdsFile of the given size based on the current image.
 /// </summary>
 /// <param name="size">The new size.</param>
 /// <returns>A new DdsFile of the given size based on the current image.</returns>
 public DdsFile Resize(Size size)
 {
     DdsFile ddsFile = new DdsFile();
     ddsFile.CreateImage(this, size.Width, size.Height, SupportsHSV);
     return ddsFile;
 }
Esempio n. 12
0
 /// <summary>
 /// Creates an image from a given <see cref="T:Bitmap"/>, resized as requested.
 /// If <paramref name="supportHSV"/> is true, also creates an HSVa-encoded version of the image.
 /// </summary>
 /// <param name="image"><see cref="T:Bitmap"/> from which to extract image pixels.</param>
 /// <param name="width">Width of image.</param>
 /// <param name="height">Height of image.</param>
 /// <param name="supportHSV">When true, create an HSVa-encoded version of the image.</param>
 public void CreateImage(Bitmap image, int width, int height, bool supportHSV)
 {
     using (DdsFile ddsFileBase = new DdsFile())
     {
         ddsFileBase.CreateImage(image, false);
         CreateImage(ddsFileBase.Resize(new Size(width, height)), supportHSV);
     }
 }
Esempio n. 13
0
        /// <summary>
        /// Creates an image from a given <see cref="T:DdsFile"/>, resized as requested.
        /// If <paramref name="supportHSV"/> is true, also creates an HSVa-encoded version of the image.
        /// </summary>
        /// <param name="image"><see cref="T:DdsFile"/> to clone.</param>
        /// <param name="width">Width of image.</param>
        /// <param name="height">Height of image.</param>
        /// <param name="supportHSV">When true, create an HSVa-encoded version of the image.</param>
        public void CreateImage(DdsFile image, int width, int height, bool supportHSV)
        {
            this.width = width;
            this.height = height;
            this.useBlockCompression = image.useBlockCompression;
            this.useLuminence = image.useLuminence;
            this.alphaDepth = image.alphaDepth;

            if (this.useLuminence)
            {
                // Life would be still relatively simple were it not for Luminence maps.
                // With these, you can't just strip the alpha channel -- they exist only for that channel,
                // so we need to deal with them separately.
                this.currentImage = new uint[width * height];
                this.SetPixels((x, y, unused) => 0);
                this.baseImage = (uint[])this.currentImage.Clone();

                Bitmap alpha = new Bitmap(image.GetGreyscaleFromAlpha(), width, height);
                this.SetAlphaFromGreyscale(alpha);
            }
            else if (alphaDepth == 0)
            {
                this.baseImage = new Bitmap(image.Image, width, height).ToARGBData();
                this.currentImage = (uint[])this.baseImage.Clone();
            }
            else
            {
                // Regardless of the pixel format, using Bitmap to resize the image pre-multiplies the alpha
                // so we need this mess.

                // Clone the image, strip the alpha, then resize
                using (DdsFile ddsFileBase = new DdsFile())
                {
                    ddsFileBase.CreateImage(image, false);
                    ddsFileBase.DeleteAlphaChannel();
                    this.baseImage = new Bitmap(ddsFileBase.Image, width, height).ToARGBData();
                }

                this.currentImage = (uint[])this.baseImage.Clone();

                // Now reapply the original alpha
                Bitmap alpha = new Bitmap(image.GetGreyscaleFromAlpha(), width, height);
                this.SetAlphaFromGreyscale(alpha);
            }

            if (supportHSV) this.UpdateHSVData();
        }
Esempio n. 14
0
        /// <summary>
        /// Creates an image from a given <see cref="T:DdsFile"/>.
        /// If <paramref name="supportHSV"/> is true, also creates an HSVa-encoded version of the image.
        /// </summary>
        /// <param name="image"><see cref="T:DdsFile"/> to clone.</param>
        /// <param name="supportHSV">When true, create an HSVa-encoded version of the image.</param>
        public void CreateImage(DdsFile image, bool supportHSV)
        {
            this.width = image.width;
            this.height = image.height;
            this.useBlockCompression = image.useBlockCompression;
            this.useLuminence = image.useLuminence;
            this.alphaDepth = image.alphaDepth;

            this.baseImage = (uint[])image.currentImage.Clone();

            this.currentImage = (uint[])this.baseImage.Clone();
            if (supportHSV) this.UpdateHSVData();
        }
Esempio n. 15
0
        private void btnOpenMask_Click(object sender, EventArgs e)
        {
            openFileDialog1.FileName = "*.dds";
            openFileDialog1.FilterIndex = 0;
            string caption = openFileDialog1.Title;
            try
            {
                openFileDialog1.Title = "Select DDS Image to use as a mask";
                DialogResult dr = openFileDialog1.ShowDialog();
                if (dr != DialogResult.OK) return;
            }
            finally { openFileDialog1.Title = caption; }

            using (FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read))
            {
                using (DdsFile ddsfile = new DdsFile())
                {
                    ddsfile.Load(fs, false); fs.Position = 0;

                    DdsFile ddsfile2 = ddsfile.Resize(ddsMaskCh1.Size);
                    ddsMaskCh1.DDSLoad(ddsfile2);
                    ddsMaskCh2.DDSLoad(ddsfile2);
                    ddsMaskCh3.DDSLoad(ddsfile2);
                    ddsMaskCh4.DDSLoad(ddsfile2);
                }
                
                ddsPanel1.LoadMask(fs);

                lbMaskW.Text = ddsPanel1.MaskSize.Width + "";
                lbMaskH.Text = ddsPanel1.MaskSize.Height + "";
                tlpMaskSize.Visible = true;

                fs.Close();
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Apply <see cref="HSVShift"/> values to this DDS image based on the
        /// channels in the <paramref name="mask"/>.
        /// Each channel of the mask acts independently, in order "R", "G", "B", "A".
        /// </summary>
        /// <param name="mask">A DDS image file, each colourway acting as a mask channel.</param>
        /// <param name="ch1Shift">A shift to apply to the image when the first channel of the mask is active.</param>
        /// <param name="ch2Shift">A shift to apply to the image when the second channel of the mask is active.</param>
        /// <param name="ch3Shift">A shift to apply to the image when the third channel of the mask is active.</param>
        /// <param name="ch4Shift">A shift to apply to the image when the fourth channel of the mask is active.</param>
        public void MaskedHSVShiftNoBlend(DdsFile mask, HSVShift ch1Shift, HSVShift ch2Shift, HSVShift ch3Shift, HSVShift ch4Shift)
        {
            if (!SupportsHSV) return;

            maskInEffect = maskInEffect || !ch1Shift.IsEmpty || !ch2Shift.IsEmpty || !ch3Shift.IsEmpty || !ch4Shift.IsEmpty;

            if (!maskInEffect) return;

            ColorHSVA[] result = new ColorHSVA[hsvData.Length];
            Array.Copy(hsvData, 0, result, 0, result.Length);

            if (!ch1Shift.IsEmpty) MaskedHSVShift(mask, result, x => x.R() > 0, ch1Shift);
            if (!ch2Shift.IsEmpty) MaskedHSVShift(mask, result, x => x.G() > 0, ch2Shift);
            if (!ch3Shift.IsEmpty) MaskedHSVShift(mask, result, x => x.B() > 0, ch3Shift);
            if (!ch4Shift.IsEmpty) MaskedHSVShift(mask, result, x => x.A() > 0, ch4Shift);

            hsvData = result;
            currentImage = ColorHSVA.ToArrayARGB(hsvData);
        }
Esempio n. 17
0
        void MaskedHSVShift(DdsFile mask, ColorHSVA[] result, Channel channel, HSVShift hsvShift)
        {
            for (int y = 0; y < this.Size.Height; y++)
            {
                int imageOffset = y * this.Size.Width;
                int maskOffset = (y % mask.Size.Height) * mask.Size.Width;

                for (int x = 0; x < this.Size.Width; x++)
                {
                    uint maskPixel = mask.currentImage[maskOffset + x % mask.Size.Width];
                    if (channel(maskPixel)) result[imageOffset + x] = hsvData[imageOffset + x].HSVShift(hsvShift);
                }
            }
        }
Esempio n. 18
0
 void MaskedSetColour(DdsFile mask, Channel channel, uint argb)
 {
     MaskedApply(this.currentImage, this.Size, mask.currentImage, mask.Size, channel, (x, y) => argb);
 }
Esempio n. 19
0
 /// <summary>
 /// Sets the DDSPanel to an unloaded state, freeing resources.
 /// </summary>
 public void Clear()
 {
     ddsFile = new DdsFile();
     loaded = false;
     ddsMask = null;
     pictureBox1.Image = image = null;
     pictureBox1.Size = (this.MaxSize == Size.Empty) ? new Size(0x80, 0x80) : Min(new Size(0x80, 0x80), this.MaxSize);
     ckb_CheckedChanged(null, null);
 }
Esempio n. 20
0
 /// <summary>
 /// Use the <paramref name="mask"/> to apply the DDS image supplied.
 /// </summary>
 /// <param name="mask">Determines to which areas each DDS image is applied.</param>
 /// <param name="ch1DdsFile">DDS image applied to <paramref name="mask"/> channel 1 area.</param>
 /// <param name="ch2DdsFile">DDS image applied to <paramref name="mask"/> channel 2 area.</param>
 /// <param name="ch3DdsFile">DDS image applied to <paramref name="mask"/> channel 3 area.</param>
 /// <param name="ch4DdsFile">DDS image applied to <paramref name="mask"/> channel 4 area.</param>
 public void MaskedApplyImage(DdsFile mask, DdsFile ch1DdsFile, DdsFile ch2DdsFile, DdsFile ch3DdsFile, DdsFile ch4DdsFile)
 {
     this.MaskedApplyImage(mask,
         (ch1DdsFile == null) ? null : ch1DdsFile.currentImage, (ch1DdsFile == null) ? Size.Empty : ch1DdsFile.Size,
         (ch2DdsFile == null) ? null : ch2DdsFile.currentImage, (ch2DdsFile == null) ? Size.Empty : ch2DdsFile.Size,
         (ch3DdsFile == null) ? null : ch3DdsFile.currentImage, (ch3DdsFile == null) ? Size.Empty : ch3DdsFile.Size,
         (ch4DdsFile == null) ? null : ch4DdsFile.currentImage, (ch4DdsFile == null) ? Size.Empty : ch4DdsFile.Size);
 }
Esempio n. 21
0
 /// <summary>
 /// Set the alpha channel of the current image from the given DDS file stream.
 /// </summary>
 /// <param name="image"><see cref="Stream"/> containing a DDS image.</param>
 public void SetAlphaFromGreyscale(Stream image)
 {
     DdsFile greyscale = new DdsFile();
     greyscale.Load(image, false);
     ddsFile.SetAlphaFromGreyscale(greyscale);
     ckb_CheckedChanged(null, null);
 }
Esempio n. 22
0
 /// <summary>
 /// Use the <paramref name="mask"/> to apply the supplied images.
 /// </summary>
 /// <param name="mask">Determines to which areas each image is applied.</param>
 /// <param name="ch1Image">Image applied to <paramref name="mask"/> channel 1 area.</param>
 /// <param name="ch2Image">Image applied to <paramref name="mask"/> channel 2 area.</param>
 /// <param name="ch3Image">Image applied to <paramref name="mask"/> channel 3 area.</param>
 /// <param name="ch4Image">Image applied to <paramref name="mask"/> channel 4 area.</param>
 public void MaskedApplyImage(DdsFile mask, Image ch1Image, Image ch2Image, Image ch3Image, Image ch4Image)
 {
     this.MaskedApplyImage(mask,
         (ch1Image == null) ? null : new Bitmap(ch1Image),
         (ch2Image == null) ? null : new Bitmap(ch2Image),
         (ch3Image == null) ? null : new Bitmap(ch3Image),
         (ch4Image == null) ? null : new Bitmap(ch4Image));
 }
Esempio n. 23
0
 /// <summary>
 /// Removes any previously applied masked shifts
 /// </summary>
 public void ClearMask()
 {
     if (SupportsHSV)
         ddsFile.ClearMask();
     ddsMask = null;
     if (loaded)
         ckb_CheckedChanged(null, null);
 }
Esempio n. 24
0
 /// <summary>
 /// Use the <paramref name="mask"/> to apply the supplied bitmaps.
 /// </summary>
 /// <param name="mask">Determines to which areas each image is applied.</param>
 /// <param name="ch1Bitmap">Bitmap applied to <paramref name="mask"/> channel 1 area.</param>
 /// <param name="ch2Bitmap">Bitmap applied to <paramref name="mask"/> channel 2 area.</param>
 /// <param name="ch3Bitmap">Bitmap applied to <paramref name="mask"/> channel 3 area.</param>
 /// <param name="ch4Bitmap">Bitmap applied to <paramref name="mask"/> channel 4 area.</param>
 public void MaskedApplyImage(DdsFile mask, Bitmap ch1Bitmap, Bitmap ch2Bitmap, Bitmap ch3Bitmap, Bitmap ch4Bitmap)
 {
     this.MaskedApplyImage(mask,
         (ch1Bitmap == null) ? null : ch1Bitmap.ToARGBData(), (ch1Bitmap == null) ? Size.Empty : ch1Bitmap.Size,
         (ch2Bitmap == null) ? null : ch2Bitmap.ToARGBData(), (ch2Bitmap == null) ? Size.Empty : ch2Bitmap.Size,
         (ch3Bitmap == null) ? null : ch3Bitmap.ToARGBData(), (ch3Bitmap == null) ? Size.Empty : ch3Bitmap.Size,
         (ch4Bitmap == null) ? null : ch4Bitmap.ToARGBData(), (ch4Bitmap == null) ? Size.Empty : ch4Bitmap.Size);
 }
Esempio n. 25
0
        /// <summary>
        /// Apply the supplied images to the areas of the base image defined by the
        /// channels in the currently loaded mask.
        /// </summary>
        /// <param name="ch1Image">The <see cref="T:System.IO.Stream"/> containing the DDS image to apply to the image when the first channel of the mask is active.</param>
        /// <param name="ch2Image">The <see cref="T:System.IO.Stream"/> containing the DDS image to apply to the image when the second channel of the mask is active.</param>
        /// <param name="ch3Image">The <see cref="T:System.IO.Stream"/> containing the DDS image to apply to the image when the third channel of the mask is active.</param>
        /// <param name="ch4Image">The <see cref="T:System.IO.Stream"/> containing the DDS image to apply to the image when the fourth channel of the mask is active.</param>
        public void ApplyImage(Stream ch1Image, Stream ch2Image, Stream ch3Image, Stream ch4Image)
        {
            if (!this.loaded || !this.MaskLoaded) return;

            DdsFile ch1dds = null, ch2dds = null, ch3dds = null, ch4dds = null;
            try
            {
                this.Enabled = false;
                Application.UseWaitCursor = true;
                Application.DoEvents();
                if (ch1Image != null) { ch1dds = new DdsFile(); ch1dds.Load(ch1Image, false); }
                if (ch2Image != null) { ch2dds = new DdsFile(); ch2dds.Load(ch2Image, false); }
                if (ch3Image != null) { ch3dds = new DdsFile(); ch3dds.Load(ch3Image, false); }
                if (ch4Image != null) { ch4dds = new DdsFile(); ch4dds.Load(ch4Image, false); }
                ddsFile.MaskedApplyImage(this.ddsMask, ch1dds, ch2dds, ch3dds, ch4dds);
            }
            finally { this.Enabled = true; Application.UseWaitCursor = false; Application.DoEvents(); }
            this.ckb_CheckedChanged(null, null);
        }
Esempio n. 26
0
        void MaskedApplyImage(DdsFile mask,
            uint[] ch1image, Size ch1imageSize, uint[] ch2image, Size ch2imageSize, uint[] ch3image, Size ch3imageSize, uint[] ch4image, Size ch4imageSize)
        {

            maskInEffect = maskInEffect || ch1image != null || ch2image != null || ch3image != null || ch4image != null;

            if (!maskInEffect) return;

            if (ch1image != null) MaskedApplyImage(mask, x => x.R() > 0, ch1image, ch1imageSize);
            if (ch2image != null) MaskedApplyImage(mask, x => x.G() > 0, ch2image, ch2imageSize);
            if (ch3image != null) MaskedApplyImage(mask, x => x.B() > 0, ch3image, ch3imageSize);
            if (ch4image != null) MaskedApplyImage(mask, x => x.A() > 0, ch4image, ch4imageSize);

            if (SupportsHSV) UpdateHSVData();
        }