/// <summary> /// Creates a Bitmap image corresponding to an HSVA image. /// </summary> /// <param name="hsvaData">An HSVA image.</param> /// <param name="hsvShift">An optional <see cref="HSVShift"/> to apply.</param> /// <returns>A Bitmap image corresponding to <paramref name="hsvaData"/>.</returns> public static uint[] ToArrayARGB(ColorHSVA[] hsvaData, HSVShift hsvShift = new HSVShift()) { uint[] argbData = new uint[hsvaData.Length]; for (int i = 0; i < hsvaData.Length; i++) { argbData[i] = hsvShift.IsEmpty ? hsvaData[i].ToARGB() : hsvaData[i].HSVShift(hsvShift).ToARGB(); } return(argbData); }
/// <summary> /// Returns true if <paramref name="obj"/> is a <see cref="HSVShift"/> with the same value as this instance. /// </summary> /// <param name="obj">An object to compare.</param> /// <returns>True if <paramref name="obj"/> is a <see cref="HSVShift"/> with the same value as this instance; otherwise false.</returns> public override bool Equals(object obj) { if (!(obj is HSVShift)) { return(false); } HSVShift other = (HSVShift)obj; return(h == other.h && s == other.s && v == other.v); }
/// <summary> /// Return the current <see cref="ColorHSVA"/> adjusted by a given <see cref="HSVShift"/> value. /// </summary> /// <param name="hsvShift">The <see cref="HSVShift"/> value by which to adjust this <see cref="ColorHSVA"/>.</param> /// <returns>The current <see cref="ColorHSVA"/> adjusted by a given <see cref="HSVShift"/> value.</returns> public ColorHSVA HSVShift(HSVShift hsvShift) { float h = this.h / 255.0f + hsvShift.h; if (h < 0) { h += (float)Math.Floor(Math.Abs(h)) + 1; } if (h > 1) { h -= (float)Math.Floor(Math.Abs(h)) + 1; } return(new ColorHSVA { h = (byte)Math.Round(h * 255.0f), s = (byte)Math.Round(Math.Max(0, Math.Min(1, this.s / 255.0f + hsvShift.s)) * 255.0f), v = (byte)Math.Round(Math.Max(0, Math.Min(1, this.v / 255.0f + hsvShift.v)) * 255.0f), a = this.a, }); }
/// <summary> /// Apply <see cref="HSVShift"/> values to the image, based on the /// channels in the currently loaded mask. /// </summary> /// <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> /// <param name="blend">When true, each channel's shift adds; when false, each channel's shift overrides.</param> public void ApplyHSVShift(HSVShift ch1Shift, HSVShift ch2Shift, HSVShift ch3Shift, HSVShift ch4Shift, bool blend) { if (!SupportsHSV || !MaskLoaded) return; if (blend) ddsFile.MaskedHSVShift(ddsMask, ch1Shift, ch2Shift, ch3Shift, ch4Shift); else ddsFile.MaskedHSVShiftNoBlend(ddsMask, ch1Shift, ch2Shift, ch3Shift, ch4Shift); ckb_CheckedChanged(null, null); }
/// <summary> /// Apply <see cref="HSVShift"/> values to 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="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> /// <param name="blend">When true, each channel's shift adds; when false, each channel's shift overrides.</param> public void ApplyHSVShift(Stream mask, HSVShift ch1Shift, HSVShift ch2Shift, HSVShift ch3Shift, HSVShift ch4Shift, bool blend) { if (!SupportsHSV) return; LoadMask(mask); ApplyHSVShift(ch1Shift, ch2Shift, ch3Shift, ch4Shift, blend); }
/// <summary> /// Apply a hue, saturation and value shift to the image. /// </summary> /// <param name="h">Hue shift, default 0</param> /// <param name="s">Saturation shift, default 0</param> /// <param name="v">Value shift, default 0</param> public void HSVShift(decimal h = 0, decimal s = 0, decimal v = 0) { hsvShift = new HSVShift { h = (float)h, s = (float)s, v = (float)v, }; if (SupportsHSV) ckb_CheckedChanged(null, null); }
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); } } }
/// <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); }
/// <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); }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { baseImage = null; currentImage = null; maskInEffect = false; hsvData = null; hsvShift = HSVShift.Empty; }
/// <summary> /// Creates a Bitmap image corresponding to an HSVA image. /// </summary> /// <param name="hsvaData">An HSVA image.</param> /// <param name="hsvShift">An optional <see cref="HSVShift"/> to apply.</param> /// <returns>A Bitmap image corresponding to <paramref name="hsvaData"/>.</returns> public static uint[] ToArrayARGB(ColorHSVA[] hsvaData, HSVShift hsvShift = new HSVShift()) { uint[] argbData = new uint[hsvaData.Length]; for (int i = 0; i < hsvaData.Length; i++) argbData[i] = hsvShift.IsEmpty ? hsvaData[i].ToARGB() : hsvaData[i].HSVShift(hsvShift).ToARGB(); return argbData; }
/// <summary> /// Return the current <see cref="ColorHSVA"/> adjusted by a given <see cref="HSVShift"/> value. /// </summary> /// <param name="hsvShift">The <see cref="HSVShift"/> value by which to adjust this <see cref="ColorHSVA"/>.</param> /// <returns>The current <see cref="ColorHSVA"/> adjusted by a given <see cref="HSVShift"/> value.</returns> public ColorHSVA HSVShift(HSVShift hsvShift) { float h = this.h / 255.0f + hsvShift.h; if (h < 0) h += (float)Math.Floor(Math.Abs(h)) + 1; if (h > 1) h -= (float)Math.Floor(Math.Abs(h)) + 1; return new ColorHSVA { h = (byte)Math.Round(h * 255.0f), s = (byte)Math.Round(Math.Max(0, Math.Min(1, this.s / 255.0f + hsvShift.s)) * 255.0f), v = (byte)Math.Round(Math.Max(0, Math.Min(1, this.v / 255.0f + hsvShift.v)) * 255.0f), a = this.a, }; }