2012-05-15 19 views
4

我使用Batik處理SVG圖像。具體來說,我有一個場景與一些形狀,我需要能夠將每個形狀轉換爲單獨的BufferedImage。爲此,我使用下面的代碼:蠟染 - 計算立方樣條的邊界

SVGDocument document = null; 

// Load the document 
String parser = XMLResourceDescriptor.getXMLParserClassName(); 
SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser); 

File file = new File(inPath); 
try { 
    document = (SVGDocument) f.createDocument(file.toURL().toString()); 
} catch (MalformedURLException e) { 
    e.printStackTrace(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

// Build the tree and get the document dimensions 
UserAgentAdapter userAgentAdapter = new UserAgentAdapter(); 
BridgeContext bridgeContext = new BridgeContext(userAgentAdapter); 

GVTBuilder builder = new GVTBuilder(); 

GraphicsNode graphicsNode = builder.build(bridgeContext, document); 
CanvasGraphicsNode canvasGraphicsNode = (CanvasGraphicsNode) 
     graphicsNode.getRoot().getChildren().get(0); 

if(canvasGraphicsNode.getChildren().get(i) instanceof ShapeNode) { 
    currentNode = (ShapeNode) canvasGraphicsNode.getChildren().get(i); 
    convertNodeToImage (currentNode); 
} 

這是非常標準的。我啓動蠟染,並解析SVG文件。這裏是轉換節點到圖像功能:

Rectangle2D bounds; 
BufferedImage bufferedImage; 
Graphics2D g2d; 

// This is supposed to get the bounds of the svg node. i.e. the rectangle which would 
// fit perfectly around the shape 
bounds = sn.getSensitiveBounds(); 

// Transform the shape so it's in the top left hand corner based on the bounds 
sn.setTransform(AffineTransform.getTranslateInstance(-bounds.getX(), -bounds.getY())); 

// Create a buffered image of the same size as the svg node   
bufferedImage = new BufferedImage((int) bounds.getWidth(), (int) bounds.getHeight(), 
       BufferedImage.TYPE_INT_ARGB); 

// Paint the node to the buffered image and convert the buffered image to an input  
// stream   
g2d = (Graphics2D) bufferedImage.getGraphics(); 
sn.paint(g2d); 

ByteArrayOutputStream os = new ByteArrayOutputStream(); 
ImageIO.write(bufferedImage, "png", os); 
InputStream is = new ByteArrayInputStream(os.toByteArray()); 
return is; 

這適用於矩形和直線形狀,但它不適用於樣條曲線。對於樣條線,邊界大於渲染的樣條線。我認爲這是因爲getBounds函數在邊界計算中包含控制點。我需要找到樣條曲線的邊界,即如果樣條曲線被撫摸,我想找出那個中風的邊界。我試過所有的getBounds()函數(getSensativeBounds,getGeometryBounds ...),它們都給了我相同的結果。所以我想知道我是否錯過了一些東西?這是蠟染的錯誤?或者如果有解決方法?

我想到的解決方法是獲取形狀的頂點列表並手動計算邊界。但是我一直無法找到如何獲得輪廓頂點列表。

任何幫助將不勝感激。

回答

4

對於有此問題的人,我找到了解決方案。從文檔中可以看到,獲取邊界並不能保證提供最小的邊界,只是一些完全包含形狀的矩形。這意味着有必要手動計算邊界。樣條是一個形狀的數學定義,即分段連續函數。這意味着我們必須計算樣條到一定的精度。這是通過使用雙精度程度的路徑迭代器來實現的。此路徑迭代器僅返回LINE_TO命令,這意味着它可用於計算形狀的實際邊界:

BufferedImage bufferedImage; 
Graphics2D g2d; 

// Manually calculate the bounds 
double [] vals = new double[7]; 

double minX = Double.MAX_VALUE; 
double maxX = 0; 

double minY = Double.MAX_VALUE; 
double maxY = 0; 

// Get a path iterator iterating to a certain level of accuracy 
PathIterator pi = sn.getOutline().getPathIterator(null, 0.01); 

while(!pi.isDone()) { 
    pi.currentSegment(vals); 

    if(vals[0] < minX) { 
     minX = vals[0]; 
    } 
    if(vals[0] > maxX) { 
     maxX = vals[0]; 
    } 
    if(vals[1] < minY) { 
     minY = vals[1]; 
    } 
    if(vals[1] > maxY) { 
     maxY = vals[1]; 
    } 

    pi.next(); 
} 

sn.setTransform(AffineTransform.getTranslateInstance(-minX, -minY)); 

bufferedImage = new BufferedImage((int) (maxX - minX), (int) (maxY - minY), 
       BufferedImage.TYPE_INT_ARGB); 

g2d = (Graphics2D) bufferedImage.getGraphics(); 

sn.paint(g2d); 

ByteArrayOutputStream os = new ByteArrayOutputStream(); 
ImageIO.write(bufferedImage, "png", os); 
InputStream is = new ByteArrayInputStream(os.toByteArray());