2012-05-15 8 views
4

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

이 문제가있는 사람이라면 누구나 해결책을 찾았습니다. 문서에서 get bounds는 모양을 완전히 포함하는 사각형 중 가장 작은 경계를 제공한다는 보장이 없다고 말합니다. 즉, 범위를 수동으로 계산해야합니다. 스플라인은 모양의 수학적 정의, 즉 조각 별 연속 함수입니다. 이것은 우리가 스플라인을 어느 정도 정확하게 계산해야한다는 것을 의미합니다. 이것은 정확도를 두 배로하는 경로 반복자를 사용하여 수행됩니다. 이 경로 반복자는 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()); 
관련 문제