| /* |
| * 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. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.afp.modca; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.util.List; |
| |
| import org.apache.fop.afp.AFPConstants; |
| import org.apache.fop.afp.fonts.AFPFont; |
| import org.apache.fop.afp.fonts.CharacterSet; |
| import org.apache.fop.afp.fonts.DoubleByteFont; |
| import org.apache.fop.afp.fonts.FontRuntimeException; |
| import org.apache.fop.afp.fonts.OutlineFont; |
| import org.apache.fop.afp.fonts.RasterFont; |
| import org.apache.fop.afp.util.BinaryUtils; |
| |
| /** |
| * The Map Coded Font structured field maps a unique coded font resource local |
| * ID, which may be embedded one or more times within an object's data and |
| * descriptor, to the identifier of a coded font resource object. Additionally, |
| * the Map Coded Font structured field specifies a set of resource attributes |
| * for the coded font. |
| */ |
| public class MapCodedFont extends AbstractStructuredObject { |
| |
| /** the collection of map coded fonts (maximum of 254) */ |
| private final List<FontDefinition> fontList |
| = new java.util.ArrayList<FontDefinition>(); |
| |
| /** |
| * Main constructor |
| */ |
| public MapCodedFont() { |
| } |
| |
| /** {@inheritDoc} */ |
| public void writeToStream(OutputStream os) throws IOException { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| |
| byte[] startData = new byte[9]; |
| copySF(startData, Type.MAP, Category.CODED_FONT); |
| baos.write(startData); |
| |
| for (Object aFontList : fontList) { |
| FontDefinition fd = (FontDefinition) aFontList; |
| |
| // Start of repeating groups (occurs 1 to 254) |
| baos.write(0x00); |
| |
| if (fd.scale == 0) { |
| // Raster Font |
| baos.write(0x22); // Length of 34 |
| } else { |
| // Outline Font |
| baos.write(0x3A); // Length of 58 |
| } |
| |
| // Font Character Set Name Reference |
| baos.write(0x0C); //TODO Relax requirement for 8 chars in the name |
| baos.write(0x02); |
| baos.write((byte) 0x86); |
| baos.write(0x00); |
| baos.write(fd.characterSet); |
| |
| // Font Code Page Name Reference |
| baos.write(0x0C); //TODO Relax requirement for 8 chars in the name |
| baos.write(0x02); |
| baos.write((byte) 0x85); |
| baos.write(0x00); |
| baos.write(fd.codePage); |
| |
| //TODO idea: for CIDKeyed fonts, maybe hint at Unicode encoding with X'50' triplet |
| //to allow font substitution. |
| |
| // Character Rotation |
| baos.write(0x04); |
| baos.write(0x26); |
| baos.write(fd.orientation); |
| baos.write(0x00); |
| |
| // Resource Local Identifier |
| baos.write(0x04); |
| baos.write(0x24); |
| baos.write(0x05); |
| baos.write(fd.fontReferenceKey); |
| |
| if (fd.scale != 0) { |
| // Outline Font (triplet '1F') |
| baos.write(0x14); |
| baos.write(0x1F); |
| baos.write(0x00); |
| baos.write(0x00); |
| |
| baos.write(BinaryUtils.convert(fd.scale, 2)); // Height |
| baos.write(new byte[]{0x00, 0x00}); // Width |
| |
| baos.write(new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00}); |
| |
| baos.write(0x60); |
| |
| // Outline Font (triplet '5D') |
| baos.write(0x04); |
| baos.write(0x5D); |
| baos.write(BinaryUtils.convert(fd.scale, 2)); |
| } |
| } |
| |
| byte[] data = baos.toByteArray(); |
| |
| // Set the total record length |
| byte[] rl1 = BinaryUtils.convert(data.length - 1, 2); |
| data[1] = rl1[0]; |
| data[2] = rl1[1]; |
| |
| os.write(data); |
| } |
| |
| /** |
| * Add a font definition on the the map coded font object. |
| * |
| * @param fontReference |
| * the font number used as the resource identifier |
| * @param font |
| * the font |
| * @param size |
| * the size of the font |
| * @param orientation |
| * the orientation of the font |
| * @throws MaximumSizeExceededException if the maximum number of fonts have been exceeded |
| */ |
| public void addFont(int fontReference, AFPFont font, int size, int orientation) |
| throws MaximumSizeExceededException { |
| |
| FontDefinition fontDefinition = new FontDefinition(); |
| |
| fontDefinition.fontReferenceKey = BinaryUtils.convert(fontReference)[0]; |
| |
| switch (orientation) { |
| case 90: |
| fontDefinition.orientation = 0x2D; |
| break; |
| case 180: |
| fontDefinition.orientation = 0x5A; |
| break; |
| case 270: |
| fontDefinition.orientation = (byte) 0x87; |
| break; |
| default: |
| fontDefinition.orientation = 0x00; |
| break; |
| } |
| |
| try { |
| if (font instanceof RasterFont) { |
| RasterFont raster = (RasterFont) font; |
| CharacterSet cs = raster.getCharacterSet(size); |
| if (cs == null) { |
| String msg = "Character set not found for font " |
| + font.getFontName() + " with point size " + size; |
| LOG.error(msg); |
| throw new FontRuntimeException(msg); |
| } |
| |
| fontDefinition.characterSet = cs.getNameBytes(); |
| |
| if (fontDefinition.characterSet.length != 8) { |
| throw new IllegalArgumentException("The character set " |
| + new String(fontDefinition.characterSet, |
| AFPConstants.EBCIDIC_ENCODING) |
| + " must have a fixed length of 8 characters."); |
| } |
| |
| fontDefinition.codePage = cs.getCodePage().getBytes( |
| AFPConstants.EBCIDIC_ENCODING); |
| |
| if (fontDefinition.codePage.length != 8) { |
| throw new IllegalArgumentException("The code page " |
| + new String(fontDefinition.codePage, |
| AFPConstants.EBCIDIC_ENCODING) |
| + " must have a fixed length of 8 characters."); |
| } |
| |
| } else if (font instanceof OutlineFont) { |
| OutlineFont outline = (OutlineFont) font; |
| CharacterSet cs = outline.getCharacterSet(); |
| fontDefinition.characterSet = cs.getNameBytes(); |
| |
| // There are approximately 72 points to 1 inch or 20 1440ths per point. |
| |
| fontDefinition.scale = 20 * size / 1000; |
| |
| fontDefinition.codePage = cs.getCodePage().getBytes( |
| AFPConstants.EBCIDIC_ENCODING); |
| |
| if (fontDefinition.codePage.length != 8) { |
| throw new IllegalArgumentException("The code page " |
| + new String(fontDefinition.codePage, |
| AFPConstants.EBCIDIC_ENCODING) |
| + " must have a fixed length of 8 characters."); |
| } |
| } else if (font instanceof DoubleByteFont) { |
| DoubleByteFont outline = (DoubleByteFont) font; |
| CharacterSet cs = outline.getCharacterSet(); |
| fontDefinition.characterSet = cs.getNameBytes(); |
| |
| // There are approximately 72 points to 1 inch or 20 1440ths per point. |
| |
| fontDefinition.scale = 20 * size / 1000; |
| |
| fontDefinition.codePage = cs.getCodePage().getBytes( |
| AFPConstants.EBCIDIC_ENCODING); |
| |
| //TODO Relax requirement for 8 characters |
| if (fontDefinition.codePage.length != 8) { |
| throw new IllegalArgumentException("The code page " |
| + new String(fontDefinition.codePage, |
| AFPConstants.EBCIDIC_ENCODING) |
| + " must have a fixed length of 8 characters."); |
| } |
| } else { |
| String msg = "Font of type " + font.getClass().getName() |
| + " not recognized."; |
| LOG.error(msg); |
| throw new FontRuntimeException(msg); |
| } |
| |
| if (fontList.size() > 253) { |
| // Throw an exception if the size is exceeded |
| throw new MaximumSizeExceededException(); |
| } else { |
| fontList.add(fontDefinition); |
| } |
| |
| } catch (UnsupportedEncodingException ex) { |
| throw new FontRuntimeException("Failed to create font " |
| + " due to a UnsupportedEncodingException", ex); |
| } |
| } |
| |
| |
| /** |
| * Private utility class used as a container for font attributes |
| */ |
| private static final class FontDefinition { |
| |
| private FontDefinition() { |
| } |
| |
| /** |
| * The code page of the font |
| */ |
| private byte[] codePage; |
| |
| /** |
| * The character set of the font |
| */ |
| private byte[] characterSet; |
| |
| /** |
| * The font reference key |
| */ |
| private byte fontReferenceKey; |
| |
| /** |
| * The orientation of the font |
| */ |
| private byte orientation; |
| |
| /** |
| * The scale (only specified for outline fonts) |
| */ |
| private int scale; |
| } |
| |
| } |