我使用words.java 试图在word中生成类似sidebar的功能,插入的竖向形状后插入富文本内容,我想知道怎么才能把富文本中的文字和图片都旋转 -90 ° 并保持内容正确,以下是我的代码
private void insertSidebarIntoHeader(Document document, HeaderFooter header, String htmlContent) throws Exception {
// Get the section that contains the header to determine page dimensions
Section section = (Section) header.getParentNode();
PageSetup pageSetup = section.getPageSetup();
// Calculate content area height (excludes top and bottom margins)
double pageHeight = pageSetup.getPageHeight();
double topMargin = pageSetup.getTopMargin();
double bottomMargin = pageSetup.getBottomMargin();
double availableHeight = pageHeight - topMargin - bottomMargin;
// Use 100% of available height to match body content area exactly
double sidebarHeight = availableHeight;
log.debug("Left sidebar dimensions: pageHeight={}pt, topMargin={}pt, bottomMargin={}pt, availableHeight={}pt, sidebarHeight={}pt (100%)",
pageHeight, topMargin, bottomMargin, availableHeight, sidebarHeight);
// ★ CRITICAL: Create a DrawingML Shape using RECTANGLE (not TEXT_BOX)
// This ensures Word recognizes it as a rotatable shape with full UI support
Shape sidebar = new Shape(document, ShapeType.RECTANGLE);
// ★ CRITICAL: Set dimensions for BEFORE rotation
// After -90 degree rotation, width becomes height and height becomes width
// So to get a narrow (40pt) × tall (sidebarHeight) sidebar after rotation:
// - Set width = sidebarHeight (will become height after rotation)
// - Set height = 40 (will become width after rotation)
sidebar.setWidth(sidebarHeight); // Will become height after rotation
sidebar.setHeight(40); // Will become width (narrow) after rotation
log.debug("Sidebar dimensions before rotation: width={}pt (will be height), height=40pt (will be width)",
sidebarHeight);
// CRITICAL: Set to floating (not inline) for fixed positioning
sidebar.setWrapType(WrapType.NONE);
// Mark as decorative shape (not part of content flow)
sidebar.setBehindText(false); // Show in front of text
sidebar.setAllowOverlap(true); // Allow overlap with other content
// Position relative to PAGE for absolute positioning
sidebar.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
sidebar.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
// ★ CRITICAL: Position calculation based on CENTER POINT rotation
// Rotation happens around the shape's center, not the anchor point
//
// Target position AFTER rotation:
// - Rotated shape: width=40pt, height=sidebarHeight
// - Left edge at 15pt from page → Center X = 15 + 40/2 = 35pt
// - Top edge at topMargin → Center Y = topMargin + sidebarHeight/2
//
// BEFORE rotation (horizontal shape: width=sidebarHeight, height=40):
// - Center X = 35pt (same as after rotation)
// - Center Y = topMargin + sidebarHeight/2 (same as after rotation)
// - Therefore: left = centerX - width/2 = 35 - sidebarHeight/2
// - Therefore: top = centerY - height/2 = (topMargin + sidebarHeight/2) - 20
double targetCenterX = 35; // 15 (left edge) + 20 (half of rotated width 40pt)
double targetCenterY = topMargin + sidebarHeight / 2;
double leftBeforeRotation = targetCenterX - sidebarHeight / 2;
double topBeforeRotation = targetCenterY - 20; // 20 = 40pt / 2
sidebar.setLeft(leftBeforeRotation);
sidebar.setTop(topBeforeRotation);
log.debug("Sidebar position before rotation: left={}pt, top={}pt (center-based calculation)",
leftBeforeRotation, topBeforeRotation);
log.debug("Target center point: X={}pt, Y={}pt", targetCenterX, targetCenterY);
// Remove border and background (clean appearance)
sidebar.setStroked(false); // No border
sidebar.getFill().setVisible(false); // No background fill
// ★ CRITICAL: Configure TextBox to ensure content rotates with the Shape
// Content in TextBox follows the Shape's geometric rotation
TextBox textBox = sidebar.getTextBox();
// Configure TextBox layout properties
textBox.setVerticalAnchor(VerticalAlignment.CENTER);
textBox.setInternalMarginTop(10);
textBox.setInternalMarginBottom(10);
textBox.setInternalMarginLeft(10);
textBox.setInternalMarginRight(10);
textBox.setFitShapeToText(false);
// Create paragraph for TextBox content
Paragraph textPara = new Paragraph(document);
textPara.getParagraphFormat().setAlignment(ParagraphAlignment.LEFT);
textPara.getParagraphFormat().setLineSpacing(12);
// ★ CRITICAL: Add paragraph to Shape (which places it in the TextBox)
// This ensures the paragraph rotates with the Shape
sidebar.appendChild(textPara);
// Insert HTML content using DocumentBuilder
DocumentBuilder builder = new DocumentBuilder(document);
builder.moveTo(textPara);
// Ensure horizontal text direction (left-to-right, not bidirectional)
builder.getParagraphFormat().setBidi(false);
builder.insertHtml(htmlContent);
// ★ CRITICAL: Apply true geometric rotation to the entire Shape
// This rotates the entire DrawingML Shape (text + images + coordinate system)
// -90 degrees = 90 degrees counter-clockwise = vertical sidebar on the left
sidebar.setRotation(-90.0); // Rotate 90 degrees counter-clockwise
// CRITICAL: Create a new paragraph as container for the sidebar shape
// This is the proper way to add shapes to headers according to Aspose.Words documentation
Paragraph sidebarPara = new Paragraph(document);
sidebarPara.appendChild(sidebar);
// Ensure header exists
if (header.getChildNodes(com.aspose.words.NodeType.PARAGRAPH, false).getCount() == 0) {
header.appendChild(new Paragraph(document));
}
// Add the sidebar paragraph to the header
// Insert at the beginning of the header (before any existing content)
header.insertBefore(sidebarPara, header.getFirstChild());
log.debug("Sidebar DrawingML Shape (RECTANGLE) inserted and rotated -90 degrees (entire shape including all content)");
}
