Пример #1
0
void XARGenerator::DetermineLinearGradientPoints(const Gradient* pGradient, const Transformation& trans,
												 const RectD& boundings, DocCoord& p1, DocCoord& p2)
{
	if (pGradient->units == Gradient::ObjectBoundingBox) {
		PointD pLower = boundings.LowerCoord();
		PointD pHigher = boundings.HigherCoord();
		p1 = DocCoord((INT32)pLower.x, m_docSize.y - (INT32)pLower.y);
		p2 = DocCoord((INT32)pHigher.x, m_docSize.y - (INT32)pHigher.y);
#ifdef SVGDEBUG
		svgtrace(DBGTRACE_GRADIENTS, "using ObjectBoundingBox %d,%d %d,%d\n", p1.x, p1.y, p2.x, p2.y);
#endif
	} else { // Gradient->units == Gradient::UserSpaceOnUse
		double fX1 = pGradient->x1;
		double fY1 = pGradient->y1;
		double fX2 = pGradient->x2;
		double fY2 = pGradient->y2;
		trans.ApplyToCoordinate(fX1, fY1, &fX1, &fY1);
		trans.ApplyToCoordinate(fX2, fY2, &fX2, &fY2);
		p1 = DocCoord((INT32)fX1, m_docSize.y - (INT32)fY1);
		p2 = DocCoord((INT32)fX2, m_docSize.y - (INT32)fY2);
#if SVGDEBUG
		svgtrace(DBGTRACE_GRADIENTS, "using UserSpaceOnUse %d,%d %d,%d\n", p1.x, p1.y, p2.x, p2.y);
#endif
	}
}
Пример #2
0
bool XARGenerator::OutputFillLinearGradient(const Style& style, const Transformation& trans, const RectD& boundings)
{
	bool ok = true;
	CXaraFileRecord Rec(0);

	const Gradient* pGradient = style.GetFillGradient();
	const GradientStopList& stops = pGradient->stops;

	if (stops.GetCount() < 1) {
#if SVGDEBUG
		svgtrace(DBGTRACE_GRADIENTS, "gradient '%s' has no stop points, giving up\n", (const char *)pGradient->xmlId.mb_str(wxConvUTF8));
#endif
		return false;
	}

#if SVGDEBUG
	svgtrace(DBGTRACE_GRADIENTS, "using linear fill gradient '%s' with %d colours\n", (const char *)pGradient->xmlId.mb_str(wxConvUTF8), stops.GetCount());
	svgtrace(DBGTRACE_GRADIENTS, "gradient trans: ");
	DebugDumpTransformation(DBGTRACE_GRADIENTS, trans);
#endif

    // start and end points of gradient
	DocCoord p1, p2;

	DetermineLinearGradientPoints(pGradient, trans, boundings, p1, p2);

	if (pGradient->units == Gradient::ObjectBoundingBox) {
		// first and last offsets of gradient
		double fOffsetFirst, fOffsetLast;

		if (stops.GetCount() == 1) {
			fOffsetFirst = 0.0;
			fOffsetLast = 1.0;
		} else { // stops.GetCount() > 1
			GradientStop* pStop1 = stops.GetFirst()->GetData();
			GradientStop* pStop2 = stops.GetLast()->GetData();
			fOffsetFirst = pStop1->offset;
			fOffsetLast = pStop2->offset;
		}

#if 0
		// determine vector of direction of object gradient
		double fDX=1.0, fDY=0.0;
		trans.ApplyToCoordinate(fDX, fDY, &fDX, &fDY);
		double fMod = sqrt(fDX*fDX+fDY*fDY);
		fDX /= fMod;
		fDY /= fMod;
#if SVGDEBUG
		svgtrace(DBGTRACE_GRADIENTS, "direction of gradient: %.2f %.2f\n", fDX, fDY);
#endif
#endif

		PointD pLower = boundings.LowerCoord();
		PointD pHigher = boundings.HigherCoord();
		double fWidth = fabs(pHigher.x - pLower.x);
		//double fHeight = fabs(pHigher.x - pLower.x);
		p1.x += (INT32)(fWidth * fOffsetFirst);
		//p1.y += (INT32)(fHeight * fOffsetFirst);
		p2.x -= (INT32)(fWidth * (1.0 - fOffsetLast));
		//p2.y -= (INT32)(fHeight * (1.0 - fOffsetLast));
#ifdef SVGDEBUG
		svgtrace(DBGTRACE_GRADIENTS, "new ObjectBoundingBox %d,%d %d,%d\n", p1.x, p1.y, p2.x, p2.y);
#endif
	}

	if (stops.GetCount() < 3) { // 1 or 2 stops
		wxColour col1, col2;
		double fOpacity1, fOpacity2;
		if (stops.GetCount() == 1) {
			GradientStop* pStop1 = stops.GetFirst()->GetData();
			col2 = col1 = pStop1->stopColour;
			fOpacity1 = fOpacity2 = pStop1->stopOpacity;
		} else { // stops.GetCount() == 2
			GradientStop* pStop1 = stops.GetFirst()->GetData();
			GradientStop* pStop2 = stops.GetLast()->GetData();
			col1 = pStop1->stopColour;
			col2 = pStop2->stopColour;
			fOpacity1 = pStop1->stopOpacity;
			fOpacity2 = pStop2->stopOpacity;
		}

#if SVGDEBUG
		svgtrace(DBGTRACE_GRADIENTS, "stop points: %d, %d and %d, %d\n", p1.x, p1.y, p2.x, p2.y);
#endif

		UINT32 iRecNo1 = DefineColour(col1);
		UINT32 iRecNo2 = DefineColour(col2);

		Rec.Reinit(TAG_LINEARFILL, TAG_LINEARFILL_SIZE);
		ok = Rec.WriteCoord(p1);
		ok = Rec.WriteCoord(p2);
		ok = Rec.WriteReference(iRecNo1);
		ok = Rec.WriteReference(iRecNo2);
		ok = Rec.WriteDOUBLE(0.0); // bias
		ok = Rec.WriteDOUBLE(0.0); // gain
		ok = m_pExporter->WriteRecord(&Rec);

		if (fOpacity1 != 1.0 || fOpacity2 != 1.0) {
			// the fill has also alpha transparency
			BYTE bOpacity1 = (BYTE)((1.0-fOpacity1)*255.0);
			BYTE bOpacity2 = (BYTE)((1.0-fOpacity2)*255.0);

			Rec.Reinit(TAG_LINEARTRANSPARENTFILL, TAG_LINEARTRANSPARENTFILL_SIZE);
			ok = Rec.WriteCoord(p1);
			ok = Rec.WriteCoord(p2);
			ok = Rec.WriteBYTE(bOpacity1);
			ok = Rec.WriteBYTE(bOpacity2);
			ok = Rec.WriteBYTE(0x01); // mix
			ok = Rec.WriteDOUBLE(0.0); // bias
			ok = Rec.WriteDOUBLE(0.0); // gain
			ok = m_pExporter->WriteRecord(&Rec);

		}
	} else { // stops.GetCount() > 2
		// we have more than 2 colours
		size_t size = stops.GetCount();
		double* fvOffsets = new double[size];
		UINT32* ivRecNo = new UINT32[size];
		double* fvOpacity = new double[size];

		bool bHaveTransparency = false;
		for (unsigned int i = 0; i < size; ++i) {
			GradientStop* pStop = stops.Item(i)->GetData();
			ivRecNo[i] = DefineColour(pStop->stopColour);
			fvOffsets[i] = pStop->offset;
			fvOpacity[i] = pStop->stopOpacity;
			if (pStop->stopOpacity < 1.0)
				bHaveTransparency = true;
		}

		Rec.Reinit(TAG_LINEARFILLMULTISTAGE, TAG_LINEARFILLMULTISTAGE_SIZE);
		ok = Rec.WriteCoord(p1);
		ok = Rec.WriteCoord(p2);
		ok = Rec.WriteReference(ivRecNo[0]);
		ok = Rec.WriteReference(ivRecNo[size-1]);
		ok = Rec.WriteINT32((INT32)size-2);
		for (unsigned int i = 1; i < size - 1; ++i) {
			ok = Rec.WriteDOUBLE(fvOffsets[i]);
			ok = Rec.WriteReference(ivRecNo[i]);
		}
		ok = m_pExporter->WriteRecord(&Rec);

		if (bHaveTransparency) {
			if (size == 3) {
				DocCoord pM;
				// calculate middle point position
				pM.x = p1.x + (INT32)((p2.x-p1.x)*fvOffsets[1]);
				pM.y = p1.y + (INT32)((p2.y-p1.y)*fvOffsets[1]);

				// hack: avoid aligned points, otherwise the fill will not work
				if (pM.y == p1.y) {
					pM.y -= 10;
				}

				BYTE bOpacity1 = (BYTE)((1.0-fvOpacity[0])*255.0);
				BYTE bOpacityM = (BYTE)((1.0-fvOpacity[1])*255.0);
				BYTE bOpacity2 = (BYTE)((1.0-fvOpacity[2])*255.0);

				Rec.Reinit(TAG_THREECOLTRANSPARENTFILL, TAG_THREECOLTRANSPARENTFILL_SIZE);
				ok = Rec.WriteCoord(p1);
				ok = Rec.WriteCoord(pM);
				ok = Rec.WriteCoord(p2);
				ok = Rec.WriteBYTE(bOpacity1);
				ok = Rec.WriteBYTE(bOpacityM);
				ok = Rec.WriteBYTE(bOpacity2);
				ok = Rec.WriteBYTE(0x01); // mix
				ok = m_pExporter->WriteRecord(&Rec);

			} else { // size > 3
				// XXX the maximum number of transparent positions in XAR files is 4
				DocCoord pM1, pM2;
				// calculate middle point position
				pM1.x = p1.x + (INT32)((p2.x-p1.x)*fvOffsets[1]); // XXX should get the best offsets
				pM1.y = p1.y + (INT32)((p2.y-p1.y)*fvOffsets[1]); // not simply the first two
				pM2.x = p1.x + (INT32)((p2.x-p1.x)*fvOffsets[2]);
				pM2.y = p1.y + (INT32)((p2.y-p1.y)*fvOffsets[2]);

				// hack: avoid aligned points, otherwise the fill will not work
				if (pM1.y == p1.y) {
					pM1.y -= 10;
				}
				if (pM2.y == p1.y) {
					pM2.y -= 20;
				}

				BYTE bOpacity1  = (BYTE)((1.0-fvOpacity[0])*255.0);
				BYTE bOpacityM1 = (BYTE)((1.0-fvOpacity[1])*255.0);
				BYTE bOpacityM2 = (BYTE)((1.0-fvOpacity[2])*255.0);
				BYTE bOpacity2  = (BYTE)((1.0-fvOpacity[size-1])*255.0);

				Rec.Reinit(TAG_FOURCOLTRANSPARENTFILL, TAG_FOURCOLTRANSPARENTFILL_SIZE);
				ok = Rec.WriteCoord(p1);
				ok = Rec.WriteCoord(pM1);
				ok = Rec.WriteCoord(pM2);
				//ok = Rec.WriteCoord(p2); // XXX this is wrong
				ok = Rec.WriteBYTE(bOpacity1);
				ok = Rec.WriteBYTE(bOpacityM1);
				ok = Rec.WriteBYTE(bOpacityM2);
				ok = Rec.WriteBYTE(bOpacity2);
				ok = Rec.WriteBYTE(0x01); // mix
				ok = m_pExporter->WriteRecord(&Rec);
			}
		}

		delete[] fvOffsets;
		delete[] ivRecNo;
		delete[] fvOpacity;
	}

	return ok;
}