Пример #1
0
static PointsSize pointsSizeFromHTMLImg(WordConverter *converter, DFNode *img, PixelSize fileSize)
{
    double aspectRatio;
    if (fileSize.heightPx > 0.0)
        aspectRatio = fileSize.widthPx/(double)fileSize.heightPx;
    else
        aspectRatio = 1.0;

    CSSSize htmlSize = HTML_getImageDimensions(img);

    double widthPts = WordSectionContentWidthPts(converter->mainSection);
    if (CSSLengthIsValid(htmlSize.width)) {
        if (CSSLengthIsPercentage(htmlSize.width))
            widthPts = (htmlSize.width.value/100.0)*WordSectionContentWidthPts(converter->mainSection);
        else if (CSSLengthIsAbsolute(htmlSize.width))
            widthPts = convertBetweenUnits(htmlSize.width.value,htmlSize.width.units,UnitsPt);
    }

    double heightPts = widthPts/aspectRatio;

    if ((widthPts <= 0) || (heightPts <= 0)) {
        widthPts = WordSectionContentWidthPts(converter->mainSection);
        heightPts = widthPts/aspectRatio;
    }

    PointsSize result;
    result.widthPts = widthPts;
    result.heightPts = heightPts;
    return result;
}
Пример #2
0
static DFNode *imageWithFilename(WordGetData *get, const char *filename, double widthPts, DFNode *concrete)
{
    const char *concretePath = get->conv->concretePath;
    const char *abstractPath = get->conv->abstractPath;

    char *abstractImagesPath = DFAppendPathComponent(abstractPath,"images");
    char *lastComponent = DFPathBaseName(filename);
    char *srcImagePath = DFAppendPathComponent(concretePath,filename);
    char *dstImagePath = DFAppendPathComponent(abstractImagesPath,lastComponent);

    if (DFFileExists(dstImagePath))
        DFDeleteFile(dstImagePath,NULL);

    DFError *error = NULL;
    DFNode *imageNode = NULL;

    if (!DFFileExists(abstractImagesPath) &&
        !DFCreateDirectory(abstractImagesPath,1,&error)) {
        WordConverterWarning(get->conv,"Create %s: %s",abstractImagesPath,DFErrorMessage(&error));
        DFErrorRelease(error);
        imageNode = createAbstractPlaceholder(get,"[Error reading image]",concrete);
    }
    else if (!DFCopyFile(srcImagePath,dstImagePath,&error)) {
        WordConverterWarning(get->conv,"Copy %s to %s: %s",srcImagePath,dstImagePath,DFErrorMessage(&error));
        DFErrorRelease(error);
        imageNode = createAbstractPlaceholder(get,"[Error reading image]",concrete);
    }
    else {
        imageNode = WordConverterCreateAbstract(get,HTML_IMG,concrete);
        DFFormatAttribute(imageNode,HTML_SRC,"images/%s",lastComponent);

        double contentWidthPts = WordSectionContentWidthPts(get->conv->mainSection);
        if (contentWidthPts > 0) {
            double widthPct = widthPts/contentWidthPts*100.0;
            CSSProperties *properties = CSSPropertiesNew();
            char buf[100];
            CSSPut(properties,"width",DFFormatDoublePct(buf,100,widthPct));
            char *propertiesText = CSSPropertiesCopyDescription(properties);
            DFSetAttribute(imageNode,HTML_STYLE,propertiesText);
            free(propertiesText);
            CSSPropertiesRelease(properties);
        }
    }

    free(abstractImagesPath);
    free(lastComponent);
    free(srcImagePath);
    free(dstImagePath);
    return imageNode;
}
Пример #3
0
void WordPutPPr(DFNode *pPr, CSSProperties *properties, const char *styleId, WordSection *section, int outlineLvl)
{
    assert(pPr->tag == WORD_PPR);

    // The child elements of pPr have to be in a specific order. So we build up a structure based
    // on the existing elements (updated as appropriate from newProperties), and then rebuild
    // from that

    CSSProperties *oldp = CSSPropertiesNew();
    CSSProperties *newp = properties;
    const char *oldStyleId = NULL;
    const char *newStyleId = styleId;
    WordGetPPr(pPr,oldp,&oldStyleId,section);

    {
        DFNode *children[PREDEFINED_TAG_COUNT];
        childrenToArray(pPr,children);

        int existingOutlineLvl = -1;
        if (children[WORD_OUTLINELVL] != NULL) {
            const char *value = DFGetAttribute(children[WORD_OUTLINELVL],WORD_VAL);
            if (value != NULL)
                existingOutlineLvl = atoi(value);
        }

        // Style name
        if (!DFStringEquals(oldStyleId,newStyleId)) {
            if (newStyleId != NULL) {
                children[WORD_PSTYLE] = DFCreateElement(pPr->doc,WORD_PSTYLE);
                DFSetAttribute(children[WORD_PSTYLE],WORD_VAL,newStyleId);
            }
            else {
                children[WORD_PSTYLE] = NULL;
            }
        }

        // Paragraph border (pBdr)

        if (children[WORD_PBDR] == NULL)
            children[WORD_PBDR] = DFCreateElement(pPr->doc,WORD_PBDR);

        WordPutPBdr(children[WORD_PBDR],oldp,newp);

        if (children[WORD_PBDR]->first == NULL)
            children[WORD_PBDR] = NULL;

        // Numbering and outline level
        // Don't change these properties for styles with outline level >= 6, as these can't be
        // represented with the standard HTML heading elements, which only go from h1 - h6
        // (outline levels 0 - 5)
        if (existingOutlineLvl < 6) {
            if (children[WORD_NUMPR] == NULL)
                children[WORD_NUMPR] = DFCreateElement(pPr->doc,WORD_NUMPR);

            WordPutNumPr(children[WORD_NUMPR],newp);

            if (children[WORD_NUMPR]->first == NULL)
                children[WORD_NUMPR] = NULL;

            if ((outlineLvl >= 0) && (outlineLvl <= 5)) {
                if (children[WORD_OUTLINELVL] == NULL)
                    children[WORD_OUTLINELVL] = DFCreateElement(pPr->doc,WORD_OUTLINELVL);
                DFFormatAttribute(children[WORD_OUTLINELVL],WORD_VAL,"%d",outlineLvl);
            }
            else {
                children[WORD_OUTLINELVL] = NULL;
            }
        }

        // background-color

        char *oldBackgroundColor = CSSHexColor(CSSGet(oldp,"background-color"),0);
        char *newBackgroundColor = CSSHexColor(CSSGet(newp,"background-color"),0);
        if (!DFStringEquals(oldBackgroundColor,newBackgroundColor))
            WordPutShd(pPr->doc,&children[WORD_SHD],newBackgroundColor);
        free(oldBackgroundColor);
        free(newBackgroundColor);

        // text-align

        if (!DFStringEquals(CSSGet(oldp,"text-align"),CSSGet(newp,"text-align"))) {
            const char *newTextAlign = CSSGet(newp,"text-align");
            if (newTextAlign != NULL) {
                const char *val = NULL;
                if (!strcmp(newTextAlign,"left"))
                    val = "left";
                else if (!strcmp(newTextAlign,"right"))
                    val = "right";
                else if (!strcmp(newTextAlign,"center"))
                    val = "center";
                else if (!strcmp(newTextAlign,"justify"))
                    val = "both";
                if (val != NULL) {
                    children[WORD_JC] = DFCreateElement(pPr->doc,WORD_JC);
                    DFSetAttribute(children[WORD_JC],WORD_VAL,val);
                }
            }
            else {
                children[WORD_JC] = NULL;
            }
        }

        if ((section != NULL) && (WordSectionContentWidth(section) >= 0)) {
            const char *oldMarginLeft = CSSGet(oldp,"margin-left");
            const char *oldMarginRight = CSSGet(oldp,"margin-right");
            const char *oldTextIndent = CSSGet(oldp,"text-indent");
            const char *newMarginLeft = CSSGet(newp,"margin-left");
            const char *newMarginRight = CSSGet(newp,"margin-right");
            const char *newTextIndent = CSSGet(newp,"text-indent");

            // Special case of the List_Paragraph style, which is used by Word to ensure lists are indented. We
            // don't set this property for HTML, because it automatically indents lists. However we need to ensure
            // that it remains unchanged when updating the word document
            const char *newWordMarginLeft = CSSGet(newp,"-word-margin-left");
            if (newMarginLeft == NULL)
                newMarginLeft = newWordMarginLeft;

            if ((newMarginLeft == NULL) && (newMarginRight == NULL) && (newTextIndent == NULL)) {
                children[WORD_IND] = NULL;
            }
            else {
                if (children[WORD_IND] == NULL)
                    children[WORD_IND] = DFCreateElement(pPr->doc,WORD_IND);

                if (!DFStringEquals(oldMarginLeft,newMarginLeft)) {
                    if (newMarginLeft != NULL)
                        updateTwipsFromLength(children[WORD_IND],WORD_LEFT,newMarginLeft,WordSectionContentWidth(section));
                    else
                        DFRemoveAttribute(children[WORD_IND],WORD_LEFT);
                    DFRemoveAttribute(children[WORD_IND],WORD_START);
                }

                if (!DFStringEquals(oldMarginRight,newMarginRight)) {
                    if (newMarginRight != NULL)
                        updateTwipsFromLength(children[WORD_IND],WORD_RIGHT,newMarginRight,WordSectionContentWidth(section));
                    else
                        DFRemoveAttribute(children[WORD_IND],WORD_RIGHT);
                    DFRemoveAttribute(children[WORD_IND],WORD_END);
                }

                if (!DFStringEquals(oldTextIndent,newTextIndent)) {
                    if (newTextIndent != NULL) {
                        CSSLength length = CSSLengthFromString(newTextIndent);

                        if (CSSLengthIsValid(length)) {
                            double pts = CSSLengthToPts(length,WordSectionContentWidthPts(section));
                            int twips = (int)round(pts*20);

                            if (twips >= 0) {
                                DFFormatAttribute(children[WORD_IND],WORD_FIRSTLINE,"%d",twips);
                                DFRemoveAttribute(children[WORD_IND],WORD_HANGING);
                            }
                            else {
                                DFFormatAttribute(children[WORD_IND],WORD_HANGING,"%d",-twips);
                                DFRemoveAttribute(children[WORD_IND],WORD_FIRSTLINE);
                            }
                        }
                    }
                    else {
                        DFRemoveAttribute(children[WORD_IND],WORD_FIRSTLINE);
                        DFRemoveAttribute(children[WORD_IND],WORD_HANGING);
                    }
                }

            }
        }

        if (!DFStringEquals(CSSGet(oldp,"margin-top"),CSSGet(newp,"margin-top")) ||
            !DFStringEquals(CSSGet(oldp,"margin-bottom"),CSSGet(newp,"margin-bottom")) ||
            !DFStringEquals(CSSGet(oldp,"line-height"),CSSGet(newp,"line-height"))) {

            if ((CSSGet(newp,"margin-top") == NULL) &&
                (CSSGet(newp,"margin-bottom") == NULL) &&
                (CSSGet(newp,"line-height") == NULL)) {
                children[WORD_SPACING] = NULL;
            }
            else {
                children[WORD_SPACING] = DFCreateElement(pPr->doc,WORD_SPACING);

                if (DFStringEquals(CSSGet(newp,"margin-top"),"-word-auto")) {
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFORE,"100");
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFOREAUTOSPACING,"1");
                }
                else {
                    char *before = twipsFromCSS(CSSGet(newp,"margin-top"),WordSectionContentWidth(section));
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFORE,before);
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFOREAUTOSPACING,NULL);
                    free(before);
                }

                if (DFStringEquals(CSSGet(newp,"margin-bottom"),"-word-auto")) {
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTER,"100");
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTERAUTOSPACING,"1");
                }
                else {
                    char *after = twipsFromCSS(CSSGet(newp,"margin-bottom"),WordSectionContentWidth(section));
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTER,after);
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTERAUTOSPACING,NULL);
                    free(after);
                }

                CSSLength lineHeight = CSSLengthFromString(CSSGet(newp,"line-height"));
                if (CSSLengthIsValid(lineHeight) && (lineHeight.units == UnitsPct)) {
                    int value = (int)round(lineHeight.value*2.4);
                    DFFormatAttribute(children[WORD_SPACING],WORD_LINE,"%d",value);
                }
                
                if (children[WORD_SPACING]->attrsCount == 0)
                    children[WORD_SPACING] = NULL;
            }
        }
        
        replaceChildrenFromArray(pPr,children,WordPPR_Children);
    }
    CSSPropertiesRelease(oldp);
}
Пример #4
0
static void WordTblPut(WordPutData *put, DFNode *abstract, DFNode *concrete)
{
    if ((abstract->tag != HTML_TABLE) || (concrete->tag != WORD_TBL))
        return;;

    DFTable *abstractStructure = HTML_tableStructure(abstract);
    const char *inlineCSSText = DFGetAttribute(abstract,HTML_STYLE);
    CSSProperties *tableProperties = CSSPropertiesNewWithString(inlineCSSText);
    CSSProperties *cellProperties = CSSPropertiesNew();
    const char *className = DFGetAttribute(abstract,HTML_CLASS);
    char *selector = CSSMakeSelector("table",className);
    WordStyle *style = WordSheetStyleForSelector(put->conv->styles,selector);
    CellPadding padding = getPadding(put->conv->styleSheet,style,cellProperties);

    DFNode *tblPr = DFChildWithTag(concrete,WORD_TBLPR);
    if (tblPr == NULL)
        tblPr = DFCreateElement(concrete->doc,WORD_TBLPR);;

    DFNode *tblGrid = DFChildWithTag(concrete,WORD_TBLGRID);
    if (tblGrid == NULL)
        tblGrid = DFCreateElement(concrete->doc,WORD_TBLGRID);

    while (concrete->first != NULL)
        DFRemoveNode(concrete->first);

    const char *oldJc = DFGetChildAttribute(tblPr,WORD_JC,WORD_VAL);
    WordPutTblPr(tblPr,tableProperties,NULL,put->conv->mainSection,style != NULL ? style->styleId : NULL);
    const char *newJc = DFGetChildAttribute(tblPr,WORD_JC,WORD_VAL);

    double tableWidthPct = 100;
    if (CSSGet(tableProperties,"width") != NULL) {
        CSSLength length = CSSLengthFromString(CSSGet(tableProperties,"width"));
        if (CSSLengthIsValid(length) && (length.units == UnitsPct))
            tableWidthPct = length.value;
    }

    double contentWidthPts = WordSectionContentWidthPts(put->conv->mainSection);
    double totalWidthPts = (contentWidthPts+padding.leftPts+padding.rightPts)*(tableWidthPct/100.0);

    while (tblGrid->first != NULL)
        DFRemoveNode(tblGrid->first);
    for (unsigned int i = 0; i < abstractStructure->cols; i++) {
        DFNode *gridCol = DFCreateChildElement(tblGrid,WORD_GRIDCOL);

        double colWidthPct = DFTablePctWidthForCol(abstractStructure,i);
        double colWidthPts = totalWidthPts*colWidthPct/100.0;
        int colWidthTwips = (int)round(colWidthPts*20);

        DFFormatAttribute(gridCol,WORD_W,"%d",colWidthTwips);
    }

    DFAppendChild(concrete,tblPr);
    DFAppendChild(concrete,tblGrid);
    for (unsigned int row = 0; row < abstractStructure->rows; row++) {
        DFNode *htmlTr = DFTableGetRowElement(abstractStructure,row);
        DFNode *wordTr = concreteRowForAbstractRow(put,htmlTr);
        updateTrJc(wordTr,oldJc,newJc);
        DFAppendChild(concrete,wordTr);
        unsigned int col = 0;
        while (col < abstractStructure->cols) {

            DFCell *cell = DFTableGetCell(abstractStructure,row,col);
            assert(cell != NULL);

            DFNode *tc = WordConverterGetConcrete(put,cell->element);
            if ((tc == NULL) || (row != cell->row))
                tc = DFCreateElement(concrete->doc,WORD_TC);
            DFAppendChild(wordTr,tc);

            if (cell->row == row)
                WordTcPut(put,cell->element,tc);;

            const char *vMerge = NULL;
            if (cell->rowSpan > 1) {
                if (row == cell->row)
                    vMerge = "restart";
                else
                    vMerge = "continue";
            }

            DFNode *tcPr = DFChildWithTag(tc,WORD_TCPR);
            if (tcPr == NULL)
                tcPr = DFCreateElement(concrete->doc,WORD_TCPR);
            // Make sure tcPr comes first
            DFInsertBefore(tc,tcPr,tc->first);

            WordPutTcPr2(tcPr,cell->colSpan,vMerge);

            const char *inlineCSSText = DFGetAttribute(cell->element,HTML_STYLE);
            CSSProperties *innerCellProperties = CSSPropertiesNewWithString(inlineCSSText);

            if ((row == cell->row) && (totalWidthPts > 0)) {
                double spannedWidthPct = 0;
                for (unsigned int c = col; c < col + cell->colSpan; c++)
                    spannedWidthPct += DFTablePctWidthForCol(abstractStructure,c);
                char buf[100];
                CSSPut(innerCellProperties,"width",DFFormatDoublePct(buf,100,spannedWidthPct));
            }

            WordPutTcPr1(tcPr,innerCellProperties);

            int haveBlockLevelElement = 0;
            for (DFNode *tcChild = tc->first; tcChild != NULL; tcChild = tcChild->next) {
                if (WordBlockLevelLens.isVisible(put,tcChild))
                    haveBlockLevelElement = 1;
            }

            // Every cell must contain at least one block-level element
            if (!haveBlockLevelElement) {
                DFNode *p = DFCreateElement(concrete->doc,WORD_P);
                DFAppendChild(tc,p);
            }

            col += cell->colSpan;
            CSSPropertiesRelease(innerCellProperties);
        }
    }

    free(selector);
    DFTableRelease(abstractStructure);
    CSSPropertiesRelease(tableProperties);
    CSSPropertiesRelease(cellProperties);
}