private static PdfFunction ConstructSingleGradientSegmentFunction(GradientColorStop from, GradientColorStop to) { double exponent = 1d; float[] fromColor = from.GetRgbArray(); float[] toColor = to.GetRgbArray(); if (from.GetHintOffsetType() == GradientColorStop.HintOffsetType.RELATIVE_BETWEEN_COLORS) { double hintOffset = from.GetHintOffset(); if (hintOffset <= 0d + ZERO_EPSILON) { fromColor = toColor; } else { if (hintOffset >= 1d - ZERO_EPSILON) { toColor = fromColor; } else { // similar to css color hint logic exponent = Math.Log(0.5) / Math.Log(hintOffset); } } } return(new PdfFunction.Type2(new PdfArray(new float[] { 0f, 1f }), null, new PdfArray(fromColor), new PdfArray (toColor), new PdfNumber(exponent))); }
private static void NormalizeFirstStopOffset(IList <GradientColorStop> result) { // assert that all stops has no absolute on vector offsets and hints GradientColorStop firstStop = result[0]; if (firstStop.GetOffsetType() != GradientColorStop.OffsetType.AUTO) { return; } double firstStopOffset = 0; foreach (GradientColorStop stopColor in result) { if (stopColor.GetOffsetType() == GradientColorStop.OffsetType.RELATIVE) { firstStopOffset = stopColor.GetOffset(); break; } else { if (stopColor.GetHintOffsetType() == GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT) { firstStopOffset = stopColor.GetHintOffset(); break; } } } firstStopOffset = Math.Min(0, firstStopOffset); firstStop.SetOffset(firstStopOffset, GradientColorStop.OffsetType.RELATIVE); }
private static PdfFunction ConstructFunction(IList <GradientColorStop> toConstruct) { int functionsAmount = toConstruct.Count - 1; double[] bounds = new double[functionsAmount - 1]; IList <PdfFunction> type2Functions = new List <PdfFunction>(functionsAmount); GradientColorStop currentStop; GradientColorStop nextStop = toConstruct[0]; double domainStart = nextStop.GetOffset(); for (int i = 1; i < functionsAmount; ++i) { currentStop = nextStop; nextStop = toConstruct[i]; bounds[i - 1] = nextStop.GetOffset(); type2Functions.Add(ConstructSingleGradientSegmentFunction(currentStop, nextStop)); } currentStop = nextStop; nextStop = toConstruct[toConstruct.Count - 1]; type2Functions.Add(ConstructSingleGradientSegmentFunction(currentStop, nextStop)); double domainEnd = nextStop.GetOffset(); double[] encode = new double[functionsAmount * 2]; for (int i = 0; i < encode.Length; i += 2) { encode[i] = 0d; encode[i + 1] = 1d; } return(new PdfFunction.Type3(new PdfArray(new double[] { domainStart, domainEnd }), null, type2Functions, new PdfArray(bounds), new PdfArray(encode))); }
private static void NormalizeHintsOffsets(IList <GradientColorStop> result) { // normalize all except last for (int i = 0; i < result.Count - 1; ++i) { GradientColorStop stopColor = result[i]; if (stopColor.GetHintOffsetType() == GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT) { double currentStopOffset = stopColor.GetOffset(); double nextStopOffset = result[i + 1].GetOffset(); if (currentStopOffset != nextStopOffset) { double hintOffset = (stopColor.GetHintOffset() - currentStopOffset) / (nextStopOffset - currentStopOffset); stopColor.SetHint(hintOffset, GradientColorStop.HintOffsetType.RELATIVE_BETWEEN_COLORS); } else { // if stops has the same offset, then no hint needed stopColor.SetHint(0, GradientColorStop.HintOffsetType.NONE); } } } // the last color hint is not needed as even with pad and reflect it won't be used result[result.Count - 1].SetHint(0, GradientColorStop.HintOffsetType.NONE); }
/// <summary> /// Adds the new color stop to the end ( /// <see cref="AbstractLinearGradientBuilder">more info</see> /// ). /// </summary> /// <remarks> /// Adds the new color stop to the end ( /// <see cref="AbstractLinearGradientBuilder">more info</see> /// ). /// Note: if the previously added color stop's offset would have grater offset than the added /// one, then the new offset would be normalized to be equal to the previous one. (Comparison /// made between relative on coordinates vector offsets. If any of them has /// the absolute offset, then the absolute value would converted to relative first.) /// </remarks> /// <param name="gradientColorStop">the gradient stop color to add</param> /// <returns>the current builder instance</returns> public virtual AbstractLinearGradientBuilder AddColorStop(GradientColorStop gradientColorStop) { if (gradientColorStop != null) { this.stops.Add(gradientColorStop); } return(this); }
public virtual void CornerCasesTest() { GradientColorStop stopToTest = new GradientColorStop((float[])null, 1.5, GradientColorStop.OffsetType.AUTO ).SetHint(1.5, GradientColorStop.HintOffsetType.NONE); NUnit.Framework.Assert.AreEqual(new float[] { 0f, 0f, 0f }, stopToTest.GetRgbArray()); NUnit.Framework.Assert.AreEqual(0, stopToTest.GetOffset(), 1e-10); NUnit.Framework.Assert.AreEqual(GradientColorStop.OffsetType.AUTO, stopToTest.GetOffsetType()); NUnit.Framework.Assert.AreEqual(0, stopToTest.GetHintOffset(), 1e-10); NUnit.Framework.Assert.AreEqual(GradientColorStop.HintOffsetType.NONE, stopToTest.GetHintOffsetType()); }
public virtual void NormalizationTest() { GradientColorStop stopToTest = new GradientColorStop(new float[] { -0.5f, 1.5f, 0.5f, 0.5f }, 1.5, GradientColorStop.OffsetType .AUTO).SetHint(1.5, GradientColorStop.HintOffsetType.NONE); NUnit.Framework.Assert.AreEqual(new float[] { 0f, 1f, 0.5f }, stopToTest.GetRgbArray()); NUnit.Framework.Assert.AreEqual(0, stopToTest.GetOffset(), 1e-10); NUnit.Framework.Assert.AreEqual(GradientColorStop.OffsetType.AUTO, stopToTest.GetOffsetType()); NUnit.Framework.Assert.AreEqual(0, stopToTest.GetHintOffset(), 1e-10); NUnit.Framework.Assert.AreEqual(GradientColorStop.HintOffsetType.NONE, stopToTest.GetHintOffsetType()); }
private static PdfShading.Axial CreateAxialShading(Point[] baseCoordinatesVector, IList <GradientColorStop> stops, GradientSpreadMethod spreadMethod, Rectangle targetBoundingBox) { double baseVectorLength = baseCoordinatesVector[1].Distance(baseCoordinatesVector[0]); IList <GradientColorStop> stopsToConstruct = NormalizeStops(stops, baseVectorLength); double[] coordinatesDomain = new double[] { 0, 1 }; Point[] actualCoordinates; if (baseVectorLength < ZERO_EPSILON || stopsToConstruct.Count == 1) { // single color case if (spreadMethod == GradientSpreadMethod.NONE) { return(null); } actualCoordinates = new Point[] { new Point(targetBoundingBox.GetLeft(), targetBoundingBox.GetBottom()), new Point(targetBoundingBox.GetRight(), targetBoundingBox.GetBottom()) }; GradientColorStop lastColorStop = stopsToConstruct[stopsToConstruct.Count - 1]; stopsToConstruct = JavaUtil.ArraysAsList(new GradientColorStop(lastColorStop, 0d, GradientColorStop.OffsetType .RELATIVE), new GradientColorStop(lastColorStop, 1d, GradientColorStop.OffsetType.RELATIVE)); } else { coordinatesDomain = EvaluateCoveringDomain(baseCoordinatesVector, targetBoundingBox); if (spreadMethod == GradientSpreadMethod.REPEAT || spreadMethod == GradientSpreadMethod.REFLECT) { stopsToConstruct = AdjustNormalizedStopsToCoverDomain(stopsToConstruct, coordinatesDomain, spreadMethod); } else { if (spreadMethod == GradientSpreadMethod.PAD) { AdjustStopsForPadIfNeeded(stopsToConstruct, coordinatesDomain); } else { // none case double firstStopOffset = stopsToConstruct[0].GetOffset(); double lastStopOffset = stopsToConstruct[stopsToConstruct.Count - 1].GetOffset(); if ((lastStopOffset - firstStopOffset < ZERO_EPSILON) || coordinatesDomain[1] <= firstStopOffset || coordinatesDomain [0] >= lastStopOffset) { return(null); } coordinatesDomain[0] = Math.Max(coordinatesDomain[0], firstStopOffset); coordinatesDomain[1] = Math.Min(coordinatesDomain[1], lastStopOffset); } } System.Diagnostics.Debug.Assert(coordinatesDomain[0] <= coordinatesDomain[1]); actualCoordinates = CreateCoordinatesForNewDomain(coordinatesDomain, baseCoordinatesVector); } return(new PdfShading.Axial(new PdfDeviceCs.Rgb(), CreateCoordsPdfArray(actualCoordinates), new PdfArray(coordinatesDomain ), ConstructFunction(stopsToConstruct))); }
private static void NormalizeAutoStops(IList <GradientColorStop> toNormalizeList, int fromIndex, int toIndex , double prevOffset, double nextOffset) { System.Diagnostics.Debug.Assert(toIndex >= fromIndex); int intervalsCount = Math.Min(toIndex, toNormalizeList.Count - 1) - fromIndex + 1; double offsetShift = (nextOffset - prevOffset) / intervalsCount; double currentOffset = prevOffset; for (int i = fromIndex; i < toIndex; ++i) { currentOffset += offsetShift; GradientColorStop currentAutoStop = toNormalizeList[i]; System.Diagnostics.Debug.Assert(currentAutoStop.GetOffsetType() == GradientColorStop.OffsetType.AUTO); currentAutoStop.SetOffset(currentOffset, GradientColorStop.OffsetType.RELATIVE); } }
private static void AdjustStopsForPadIfNeeded(IList <GradientColorStop> stopsToConstruct, double[] coordinatesDomain ) { GradientColorStop firstStop = stopsToConstruct[0]; if (coordinatesDomain[0] < firstStop.GetOffset()) { stopsToConstruct.Add(0, new GradientColorStop(firstStop, coordinatesDomain[0], GradientColorStop.OffsetType .RELATIVE)); } GradientColorStop lastStop = stopsToConstruct[stopsToConstruct.Count - 1]; if (coordinatesDomain[1] > lastStop.GetOffset()) { stopsToConstruct.Add(new GradientColorStop(lastStop, coordinatesDomain[1], GradientColorStop.OffsetType.RELATIVE )); } }
private static IList <GradientColorStop> CopyStopsAndNormalizeAbsoluteOffsets(IList <GradientColorStop> toNormalize , double baseVectorLength) { double lastUsedOffset = double.NegativeInfinity; IList <GradientColorStop> copy = new List <GradientColorStop>(toNormalize.Count); foreach (GradientColorStop stop in toNormalize) { double offset = stop.GetOffset(); GradientColorStop.OffsetType offsetType = stop.GetOffsetType(); if (offsetType == GradientColorStop.OffsetType.ABSOLUTE) { offsetType = GradientColorStop.OffsetType.RELATIVE; offset /= baseVectorLength; } if (offsetType == GradientColorStop.OffsetType.RELATIVE) { if (offset < lastUsedOffset) { offset = lastUsedOffset; } lastUsedOffset = offset; } GradientColorStop result = new GradientColorStop(stop, offset, offsetType); double hintOffset = stop.GetHintOffset(); GradientColorStop.HintOffsetType hintOffsetType = stop.GetHintOffsetType(); if (hintOffsetType == GradientColorStop.HintOffsetType.ABSOLUTE_ON_GRADIENT) { hintOffsetType = GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT; hintOffset /= baseVectorLength; } if (hintOffsetType == GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT) { if (hintOffset < lastUsedOffset) { hintOffset = lastUsedOffset; } lastUsedOffset = hintOffset; } result.SetHint(hintOffset, hintOffsetType); copy.Add(result); } return(copy); }
private static void NormalizeAutoStops(IList <GradientColorStop> toNormalize) { System.Diagnostics.Debug.Assert(toNormalize[0].GetOffsetType() == GradientColorStop.OffsetType.RELATIVE); int firstAutoStopIndex = 1; GradientColorStop firstStopColor = toNormalize[0]; double prevOffset = firstStopColor.GetHintOffsetType() == GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT ? firstStopColor.GetHintOffset() : firstStopColor.GetOffset(); for (int i = 1; i < toNormalize.Count; ++i) { GradientColorStop currentStop = toNormalize[i]; if (currentStop.GetOffsetType() == GradientColorStop.OffsetType.AUTO) { if (currentStop.GetHintOffsetType() == GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT) { double hintOffset = currentStop.GetHintOffset(); NormalizeAutoStops(toNormalize, firstAutoStopIndex, i + 1, prevOffset, hintOffset); prevOffset = hintOffset; firstAutoStopIndex = i + 1; } } else { if (firstAutoStopIndex < i) { // current stop offset is relative double offset = currentStop.GetOffset(); NormalizeAutoStops(toNormalize, firstAutoStopIndex, i, prevOffset, offset); } firstAutoStopIndex = i + 1; prevOffset = currentStop.GetHintOffsetType() == GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT ? currentStop .GetHintOffset() : currentStop.GetOffset(); } } // check whether the last interval has auto if (firstAutoStopIndex < toNormalize.Count) { double lastStopOffset = Math.Max(1, prevOffset); NormalizeAutoStops(toNormalize, firstAutoStopIndex, toNormalize.Count, prevOffset, lastStopOffset); } }
private static IList <GradientColorStop> AdjustNormalizedStopsToCoverDomain(IList <GradientColorStop> normalizedStops , double[] targetDomain, GradientSpreadMethod spreadMethod) { IList <GradientColorStop> adjustedStops = new List <GradientColorStop>(); GradientColorStop lastColorStop = normalizedStops[normalizedStops.Count - 1]; double originalIntervalEnd = lastColorStop.GetOffset(); double originalIntervalStart = normalizedStops[0].GetOffset(); double originalIntervalLength = originalIntervalEnd - originalIntervalStart; if (originalIntervalLength <= ZERO_EPSILON) { return(JavaUtil.ArraysAsList(new GradientColorStop(lastColorStop, targetDomain[0], GradientColorStop.OffsetType .RELATIVE), new GradientColorStop(lastColorStop, targetDomain[1], GradientColorStop.OffsetType.RELATIVE ))); } double startIntervalsShift = Math.Floor((targetDomain[0] - originalIntervalStart) / originalIntervalLength ); double iterationOffset = originalIntervalStart + (originalIntervalLength * startIntervalsShift); bool isIterationInverse = spreadMethod == GradientSpreadMethod.REFLECT && Math.Abs(startIntervalsShift) % 2 != 0; int currentIterationIndex = isIterationInverse ? normalizedStops.Count - 1 : 0; double lastComputedOffset = iterationOffset; while (lastComputedOffset <= targetDomain[1]) { GradientColorStop currentStop = normalizedStops[currentIterationIndex]; lastComputedOffset = isIterationInverse ? iterationOffset + originalIntervalEnd - currentStop.GetOffset() : iterationOffset + currentStop.GetOffset() - originalIntervalStart; GradientColorStop computedStop = new GradientColorStop(currentStop, lastComputedOffset, GradientColorStop.OffsetType .RELATIVE); if (lastComputedOffset < targetDomain[0] && !adjustedStops.IsEmpty()) { adjustedStops[0] = computedStop; } else { adjustedStops.Add(computedStop); } if (isIterationInverse) { --currentIterationIndex; if (currentIterationIndex < 0) { iterationOffset += originalIntervalLength; isIterationInverse = false; currentIterationIndex = 1; } } else { ++currentIterationIndex; if (currentIterationIndex == normalizedStops.Count) { iterationOffset += originalIntervalLength; isIterationInverse = spreadMethod == GradientSpreadMethod.REFLECT; currentIterationIndex = isIterationInverse ? normalizedStops.Count - 2 : 0; } } // check the next iteration type to set the correct stop color hint for just added stop if (isIterationInverse) { GradientColorStop nextColor = normalizedStops[currentIterationIndex]; // this method should be invoked only after the normalization. it means that // the hint offset type for each stop is either relative to colors interval // (i.e. for inverse iteration we need to inverse the hint offset), or is none // (i.e. the hint offset value should be ignored) computedStop.SetHint(1 - nextColor.GetHintOffset(), nextColor.GetHintOffsetType()); } else { computedStop.SetHint(currentStop.GetHintOffset(), currentStop.GetHintOffsetType()); } } return(adjustedStops); }