package org.ovirt.engine.core.bll.utils; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import javax.xml.bind.DatatypeConverter; import org.ovirt.engine.core.bll.validator.IconValidator; import org.ovirt.engine.core.common.businessentities.VmBase; import org.ovirt.engine.core.common.businessentities.VmIconDefault; import org.ovirt.engine.core.common.queries.VmIconIdSizePair; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; /** * Shared code related to Vm Icons */ public class IconUtils { private IconUtils() { } /** * * @param dataUrl valid large icon in dataUrl form * @return small icon in dataUrl form */ private static String computeSmallIcon(String dataUrl) { final byte[] rawData = fromDataUrl(dataUrl); final BufferedImage largeImage = loadImage(rawData); final BufferedImage smallImage = resizeToSmall(largeImage); final byte[] smallIconRawData = writeImage(smallImage, IconValidator.FileType.PNG); final String smallIcon = toDataUrl(smallIconRawData, IconValidator.FileType.PNG); return smallIcon; } private static BufferedImage resizeToSmall(BufferedImage largeImage) { if (IconValidator.DimensionsType.SMALL_CUSTOM_ICON.isInMaxBounds(largeImage)) { return largeImage; } final int targetWidth = Math.min(largeImage.getWidth(), IconValidator.DimensionsType.SMALL_CUSTOM_ICON.getMaxWidth()); final int targetHeight = Math.min(largeImage.getHeight(), IconValidator.DimensionsType.SMALL_CUSTOM_ICON.getMaxHeight()); final BufferedImage smallImage = new BufferedImage(targetWidth, targetHeight, largeImage.getType()); final Graphics2D graphics = smallImage.createGraphics(); graphics.drawImage(largeImage, 0, 0, targetWidth, targetHeight, null); graphics.dispose(); return smallImage; } private static byte[] fromDataUrl(String dataUrl) { final String base64Data = dataUrl.substring(dataUrl.indexOf(",") + 1); return DatatypeConverter.parseBase64Binary(base64Data); } private static BufferedImage loadImage(byte[] rawData) { try { return ImageIO.read(new ByteArrayInputStream(rawData)); } catch (IOException e) { throw new RuntimeException(e); } } private static byte[] writeImage(BufferedImage image, IconValidator.FileType fileType) { final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { ImageIO.write(image, fileType.getFormatName(), byteArrayOutputStream); return byteArrayOutputStream.toByteArray(); } catch (IOException e) { throw new RuntimeException(e); } } /** * It converts icon represented by raw bytes to dataurl format. * <p> * Dataurl schema: * <pre> * data:[<MIME-type>][;charset=<encoding>][;base64],<data> * </pre> * </p> * @param data raw icon bytes * @param type icon file type descriptor * @return icon in form of dataurl */ public static String toDataUrl(byte[] data, IconValidator.FileType type) { // data:[<MIME-type>][;charset=<encoding>][;base64],<data> final String base64Data = DatatypeConverter.printBase64Binary(data); final String dataUrl = new StringBuilder() .append("data:") .append(type.getMimeType()) .append(";base64,") .append(base64Data) .toString(); return dataUrl; } public static VmIconIdSizePair ensureIconPairInDatabase(String largeIconDataUrl) { final String smallIconDataUrl = IconUtils.computeSmallIcon(largeIconDataUrl); Guid largeIconId = DbFacade.getInstance().getVmIconDao().ensureIconInDatabase(largeIconDataUrl); Guid smallIconId = DbFacade.getInstance().getVmIconDao().ensureIconInDatabase(smallIconDataUrl); return new VmIconIdSizePair(smallIconId, largeIconId); } /** * @return smallIconId */ private static Guid ensureSmallIconInDatabase(Guid largeIconId) { final String largeIconDataUrl = DbFacade.getInstance().getVmIconDao().get(largeIconId).getDataUrl(); return ensureIconPairInDatabase(largeIconDataUrl).getSmall(); } /** * @return list of icon ids that was previously used and are not used any more by this vm_static entity */ public static List<Guid> updateVmIcon(VmBase originalVmBase, VmBase newVmBase, String vmIconParameter) { if (vmIconParameter != null) { addNewIconPair(newVmBase, vmIconParameter); } else { if (newVmBase.getSmallIconId() == null) { computeSmallByLargeIconId(newVmBase); } } List<Guid> unusedIconIds = new ArrayList<>(2); if (newVmBase.getSmallIconId() != null && originalVmBase.getSmallIconId() != null && !newVmBase.getSmallIconId().equals(originalVmBase.getSmallIconId())) { unusedIconIds.add(originalVmBase.getSmallIconId()); } if (newVmBase.getLargeIconId() != null && originalVmBase.getLargeIconId() != null && !newVmBase.getLargeIconId().equals(originalVmBase.getLargeIconId())) { unusedIconIds.add(originalVmBase.getLargeIconId()); } return unusedIconIds; } private static void computeSmallByLargeIconId(VmBase vmBase) { if (vmBase.getLargeIconId() == null) { return; } final List<VmIconDefault> iconDefaultsByLargeIconId = DbFacade.getInstance().getVmIconsDefaultDao() .getByLargeIconId(vmBase.getLargeIconId()); if (!iconDefaultsByLargeIconId.isEmpty()) { vmBase.setSmallIconId(iconDefaultsByLargeIconId.get(0).getSmallIconId()); } else { vmBase.setSmallIconId(ensureSmallIconInDatabase(vmBase.getLargeIconId())); } } private static void addNewIconPair(VmBase vmBase, String largeIconDataUrl) { final VmIconIdSizePair iconIds = IconUtils.ensureIconPairInDatabase(largeIconDataUrl); vmBase.setLargeIconId(iconIds.getLarge()); vmBase.setSmallIconId(iconIds.getSmall()); } public static void removeUnusedIcons(List<Guid> iconIds) { for (Guid iconId : iconIds) { DbFacade.getInstance().getVmIconDao().removeIfUnused(iconId); } } public static void preserveIcons(VmBase vmBaseFromOvf, VmBase vmBaseFromDb) { vmBaseFromOvf.setSmallIconId(vmBaseFromDb.getSmallIconId()); vmBaseFromOvf.setLargeIconId(vmBaseFromDb.getLargeIconId()); } }