2012-05-15 3 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); 
} 

Это довольно стандартный. Я запускаю Batik и заставляю его разбирать 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()); 
Смежные вопросы