SubwayTooter-Android-App/_Emoji/src/main/java/com/android/ide/common/vectordrawable/VdPreview.java

289 lines
12 KiB
Java

/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.common.vectordrawable;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
//import com.sun.org.apache.xml.internal.serialize.OutputFormat;
//import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import java.io.IOException;
import java.io.StringWriter;
/**
* Generate a Image based on the VectorDrawable's XML content.
*
* <p>This class also contains a main method, which can be used to preview a vector drawable file.
*/
public class VdPreview {
private static final String ANDROID_ALPHA = "android:alpha";
private static final String ANDROID_AUTO_MIRRORED = "android:autoMirrored";
private static final String ANDROID_HEIGHT = "android:height";
private static final String ANDROID_WIDTH = "android:width";
public static final int MAX_PREVIEW_IMAGE_SIZE = 4096;
public static final int MIN_PREVIEW_IMAGE_SIZE = 1;
/**
* This encapsulates the information used to determine the preview image size.
* The reason we have different ways here is that both Studio UI and build process need
* to use this common code path to generate images for vectordrawable.
* When mUseWidth is true, use {@code mImageMaxDimension} as the maximum
* dimension value while keeping the aspect ratio.
* Otherwise, use {@code mImageScale} to scale the image based on the XML's size information.
*/
public static class TargetSize {
private boolean mUseWidth;
private int mImageMaxDimension;
private float mImageScale;
private TargetSize(boolean useWidth, int imageWidth, float imageScale) {
mUseWidth = useWidth;
mImageMaxDimension = imageWidth;
mImageScale = imageScale;
}
public static TargetSize createSizeFromWidth(int imageWidth) {
return new TargetSize(true, imageWidth, 0.0f);
}
public static TargetSize createSizeFromScale(float imageScale) {
return new TargetSize(false, 0, imageScale);
}
}
/**
* Since we allow overriding the vector drawable's size, we also need to keep
* the original size and aspect ratio.
*/
public static class SourceSize {
public int getHeight() {
return mSourceHeight;
}
public int getWidth() {
return mSourceWidth;
}
private int mSourceWidth;
private int mSourceHeight;
}
// /**
// * @return a format object for XML formatting.
// */
// @NonNull
// private static OutputFormat getPrettyPrintFormat() {
// OutputFormat format = new OutputFormat();
// format.setLineWidth(120);
// format.setIndenting(true);
// format.setIndent(4);
// format.setEncoding("UTF-8");
// format.setOmitComments(true);
// return format;
// }
/**
* Get the vector drawable's original size.
*/
public static SourceSize getVdOriginalSize(@NonNull Document document) {
Element root = document.getDocumentElement();
SourceSize srcSize = new SourceSize();
// Update attributes, note that attributes as width and height are required,
// while others are optional.
NamedNodeMap attr = root.getAttributes();
Node nodeAttr = attr.getNamedItem(ANDROID_WIDTH);
assert nodeAttr != null;
srcSize.mSourceWidth = parseDimension(0, nodeAttr, false);
nodeAttr = attr.getNamedItem(ANDROID_HEIGHT);
assert nodeAttr != null;
srcSize.mSourceHeight = parseDimension(0, nodeAttr, false);
return srcSize;
}
// /**
// * The UI can override some properties of the Vector drawable.
// * In order to override in an uniform way, we re-parse the XML file
// * and pick the appropriate attributes to override.
// *
// * @param document the parsed document of original VectorDrawable's XML file.
// * @param info incoming override information for VectorDrawable.
// * @param errorLog log for the parsing errors and warnings.
// * param srcSize as an output, store the original size of the VectorDrawable
// * @return the overridden XML file in one string. If exception happens
// * or no attributes needs to be overriden, return null.
// */
// @Nullable
// public static String overrideXmlContent(@NonNull Document document,
// @NonNull VdOverrideInfo info,
// @Nullable StringBuilder errorLog) {
// boolean isXmlFileContentChanged = false;
// Element root = document.getDocumentElement();
//
// // Update attributes, note that attributes as width and height are required,
// // while others are optional.
// NamedNodeMap attr = root.getAttributes();
// if (info.needsOverrideWidth()) {
// Node nodeAttr = attr.getNamedItem(ANDROID_WIDTH);
// int overrideValue = info.getWidth();
// int originalValue = parseDimension(overrideValue, nodeAttr, true);
// if (originalValue != overrideValue) {
// isXmlFileContentChanged = true;
// }
// }
// if (info.needsOverrideHeight()) {
// Node nodeAttr = attr.getNamedItem(ANDROID_HEIGHT);
// int overrideValue = info.getHeight();
// int originalValue = parseDimension(overrideValue, nodeAttr, true);
// if (originalValue != overrideValue) {
// isXmlFileContentChanged = true;
// }
// }
// if (info.needsOverrideOpacity()) {
// Node nodeAttr = attr.getNamedItem(ANDROID_ALPHA);
// String opacityValue = String.format("%.2f", info.getOpacity() / 100.0f);
// if (nodeAttr != null) {
// nodeAttr.setTextContent(opacityValue);
// }
// else {
// root.setAttribute(ANDROID_ALPHA, opacityValue);
// }
// isXmlFileContentChanged = true;
// }
// // When auto mirror is set to true, then we always need to set it.
// // Because SVG has no such attribute at all.
// if (info.needsOverrideAutoMirrored()) {
// Node nodeAttr = attr.getNamedItem(ANDROID_AUTO_MIRRORED);
// if (nodeAttr != null) {
// nodeAttr.setTextContent("true");
// }
// else {
// root.setAttribute(ANDROID_AUTO_MIRRORED, "true");
// }
// isXmlFileContentChanged = true;
// }
//
// if (isXmlFileContentChanged) {
// // Prettify the XML string from the document.
// StringWriter stringOut = new StringWriter();
// XMLSerializer serial = new XMLSerializer(stringOut, getPrettyPrintFormat());
// try {
// serial.serialize(document);
// }
// catch (IOException e) {
// if (errorLog != null) {
// errorLog.append("Exception while parsing XML file:\n").append(e.getMessage());
// }
// }
// return stringOut.toString();
// } else {
// return null;
// }
// }
/**
* Query the dimension info and override it if needed.
*
* @param overrideValue the dimension value to override with.
* @param nodeAttr the node who contains dimension info.
* @param override if true then override the dimension.
* @return the original dimension value.
*/
private static int parseDimension(int overrideValue, Node nodeAttr, boolean override) {
assert nodeAttr != null;
String content = nodeAttr.getTextContent();
assert content.endsWith("dp");
int originalValue = Integer.parseInt(content.substring(0, content.length() - 2));
if (override) {
nodeAttr.setTextContent(overrideValue + "dp");
}
return originalValue;
}
// /**
// * This generates an image according to the VectorDrawable's content {@code xmlFileContent}.
// * At the same time, {@vdErrorLog} captures all the errors found during parsing.
// * The size of image is determined by the {@code size}.
// *
// * @param targetSize the size of result image.
// * @param xmlFileContent VectorDrawable's XML file's content.
// * @param vdErrorLog log for the parsing errors and warnings.
// * @return an preview image according to the VectorDrawable's XML
// */
// @Nullable
// public static BufferedImage getPreviewFromVectorXml(@NonNull TargetSize targetSize,
// @Nullable String xmlFileContent,
// @Nullable StringBuilder vdErrorLog) {
// if (xmlFileContent == null || xmlFileContent.isEmpty()) {
// return null;
// }
// VdParser p = new VdParser();
// VdTree vdTree;
//
// InputStream inputStream = new ByteArrayInputStream(
// xmlFileContent.getBytes(Charsets.UTF_8));
// vdTree = p.parse(inputStream, vdErrorLog);
// if (vdTree == null) {
// return null;
// }
//
// // If the forceImageSize is set (>0), then we honor that.
// // Otherwise, we will ask the vectorDrawable for the prefer size, then apply the imageScale.
// float vdWidth = vdTree.getBaseWidth();
// float vdHeight = vdTree.getBaseHeight();
// float imageWidth;
// float imageHeight;
// int forceImageSize = targetSize.mImageMaxDimension;
// float imageScale = targetSize.mImageScale;
//
// if (forceImageSize > 0) {
// // The goal here is to generate an image within certain size, while keeping the
// // aspect ration as much as we can.
// // If it is scaling too much to fit in, we log an error.
// float maxVdSize = Math.max(vdWidth, vdHeight);
// float ratioToForceImageSize = forceImageSize / maxVdSize;
// float scaledWidth = ratioToForceImageSize * vdWidth;
// float scaledHeight = ratioToForceImageSize * vdHeight;
// imageWidth = Math.max(MIN_PREVIEW_IMAGE_SIZE, Math.min(MAX_PREVIEW_IMAGE_SIZE, scaledWidth));
// imageHeight = Math.max(MIN_PREVIEW_IMAGE_SIZE, Math.min(MAX_PREVIEW_IMAGE_SIZE, scaledHeight));
// if (scaledWidth != imageWidth || scaledHeight != imageHeight) {
// vdErrorLog.append("Invalid image size, can't fit in a square whose size is" + forceImageSize);
// }
// } else {
// imageWidth = vdWidth * imageScale;
// imageHeight = vdHeight * imageScale;
// }
//
// // Create the image according to the vectorDrawable's aspect ratio.
//
// BufferedImage image = AssetUtil.newArgbBufferedImage((int)imageWidth, (int)imageHeight);
// vdTree.drawIntoImage(image);
// return image;
// }
public static void main(String[] args) {
System.out.println("Hello from sdk-common-lib.");
}
}