123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You 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 org.apache.poi.sl.image;
-
- import java.awt.Dimension;
- import java.awt.Rectangle;
- import java.io.IOException;
- import java.io.OutputStream;
-
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.poi.util.Internal;
- import org.apache.poi.util.LittleEndian;
- import org.apache.poi.util.LittleEndianConsts;
- import org.apache.poi.util.Units;
-
- /**
- * Aldus Placeable Metafile header - 22 byte structure before WMF data.
- * <ul>
- * <li>int Key; Magic number (always 9AC6CDD7h)
- * <li>short Handle; Metafile HANDLE number (always 0)
- * <li>short Left; Left coordinate in metafile units
- * <li>short Top; Top coordinate in metafile units
- * <li>short Right; Right coordinate in metafile units
- * <li>short Bottom; Bottom coordinate in metafile units
- * <li>short Inch; Number of metafile units per inch
- * <li>int Reserved; Reserved (always 0)
- * <li>short Checksum; Checksum value for previous 10 shorts
- * </ul>
- */
- @Internal
- public class ImageHeaderWMF {
-
- public static final int APMHEADER_KEY = 0x9AC6CDD7;
- private static final Logger LOG = LogManager.getLogger(ImageHeaderWMF.class);
-
- @SuppressWarnings("unused")
- private final int handle;
- private final int left, top, right, bottom;
-
- /**
- * The number of logical units per inch used to represent the image.
- * This value can be used to scale an image. By convention, an image is
- * considered to be recorded at 1440 logical units (twips) per inch.
- * Thus, a value of 720 specifies that the image SHOULD be rendered at
- * twice its normal size, and a value of 2880 specifies that the image
- * SHOULD be rendered at half its normal size.
- */
- private final int inch;
- @SuppressWarnings("unused")
- private final int reserved;
- private int checksum;
-
- public ImageHeaderWMF(Rectangle dim) {
- handle = 0;
- left = dim.x;
- top = dim.y;
- right = dim.x + dim.width;
- bottom = dim.y + dim.height;
- inch = Units.POINT_DPI; //default resolution is 72 dpi
- reserved = 0;
- }
-
- public ImageHeaderWMF(byte[] data, final int off) {
- int offset = off;
- int key = LittleEndian.getInt(data, offset); offset += LittleEndianConsts.INT_SIZE; //header key
- if (key != APMHEADER_KEY) {
- LOG.atWarn().log("WMF file doesn't contain a placeable header - ignore parsing");
- handle = 0;
- left = 0;
- top = 0;
- right = 200;
- bottom = 200;
- inch = Units.POINT_DPI; //default resolution is 72 dpi
- reserved = 0;
- return;
- }
-
- handle = LittleEndian.getUShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
- left = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
- top = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
- right = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
- bottom = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
-
- inch = LittleEndian.getUShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
- reserved = LittleEndian.getInt(data, offset); offset += LittleEndianConsts.INT_SIZE;
-
- checksum = LittleEndian.getShort(data, offset); offset += LittleEndianConsts.SHORT_SIZE;
- if (checksum != getChecksum()){
- LOG.atWarn().log("WMF checksum does not match the header data");
- }
- }
-
- /**
- * Returns a checksum value for the previous 10 shorts in the header.
- * The checksum is calculated by XORing each short value to an initial value of 0:
- */
- public int getChecksum(){
- int cs = 0;
- cs ^= (APMHEADER_KEY & 0x0000FFFF);
- cs ^= ((APMHEADER_KEY & 0xFFFF0000) >> 16);
- cs ^= left;
- cs ^= top;
- cs ^= right;
- cs ^= bottom;
- cs ^= inch;
- return cs;
- }
-
- public void write(OutputStream out) throws IOException {
- byte[] header = new byte[22];
- int pos = 0;
- LittleEndian.putInt(header, pos, APMHEADER_KEY); pos += LittleEndianConsts.INT_SIZE; //header key
- LittleEndian.putUShort(header, pos, 0); pos += LittleEndianConsts.SHORT_SIZE; //hmf
- LittleEndian.putUShort(header, pos, left); pos += LittleEndianConsts.SHORT_SIZE; //left
- LittleEndian.putUShort(header, pos, top); pos += LittleEndianConsts.SHORT_SIZE; //top
- LittleEndian.putUShort(header, pos, right); pos += LittleEndianConsts.SHORT_SIZE; //right
- LittleEndian.putUShort(header, pos, bottom); pos += LittleEndianConsts.SHORT_SIZE; //bottom
- LittleEndian.putUShort(header, pos, inch); pos += LittleEndianConsts.SHORT_SIZE; //inch
- LittleEndian.putInt(header, pos, 0); pos += LittleEndianConsts.INT_SIZE; //reserved
-
- checksum = getChecksum();
- LittleEndian.putUShort(header, pos, checksum);
-
- out.write(header);
- }
-
- public Dimension getSize() {
- //coefficient to translate from WMF dpi to 72dpi
- double coeff = ((double)Units.POINT_DPI)/inch;
- return new Dimension((int)Math.round((right-left)*coeff), (int)Math.round((bottom-top)*coeff));
- }
-
- public Rectangle getBounds() {
- return new Rectangle(left, top, right-left, bottom-top);
- }
-
- public int getLength(){
- return 22;
- }
- }
|