| /* |
| * 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.render.afp; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.EnumMap; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.fop.afp.AFPConstants; |
| import org.apache.fop.afp.AFPDataObjectInfo; |
| import org.apache.fop.afp.AFPEventProducer; |
| import org.apache.fop.afp.AFPResourceLevel; |
| import org.apache.fop.afp.AFPResourceLevelDefaults; |
| import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; |
| import org.apache.fop.apps.FOPException; |
| import org.apache.fop.apps.FOUserAgent; |
| import org.apache.fop.apps.MimeConstants; |
| import org.apache.fop.apps.io.InternalResourceResolver; |
| import org.apache.fop.configuration.Configuration; |
| import org.apache.fop.configuration.ConfigurationException; |
| import org.apache.fop.fonts.FontManager; |
| import org.apache.fop.render.RendererConfig; |
| import org.apache.fop.render.afp.AFPFontConfig.AFPFontInfoConfigParser; |
| import org.apache.fop.util.LogUtil; |
| |
| import static org.apache.fop.render.afp.AFPRendererConfig.ImagesModeOptions.MODE_COLOR; |
| import static org.apache.fop.render.afp.AFPRendererConfig.ImagesModeOptions.MODE_GRAYSCALE; |
| import static org.apache.fop.render.afp.AFPRendererOption.DEFAULT_RESOURCE_LEVELS; |
| import static org.apache.fop.render.afp.AFPRendererOption.GOCA; |
| import static org.apache.fop.render.afp.AFPRendererOption.GOCA_TEXT; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_DITHERING_QUALITY; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_FS45; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_JPEG; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MAPPING_OPTION; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_MODE; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_NATIVE; |
| import static org.apache.fop.render.afp.AFPRendererOption.IMAGES_WRAP_PSEG; |
| import static org.apache.fop.render.afp.AFPRendererOption.JPEG_ALLOW_JPEG_EMBEDDING; |
| import static org.apache.fop.render.afp.AFPRendererOption.JPEG_BITMAP_ENCODING_QUALITY; |
| import static org.apache.fop.render.afp.AFPRendererOption.LINE_WIDTH_CORRECTION; |
| import static org.apache.fop.render.afp.AFPRendererOption.RENDERER_RESOLUTION; |
| import static org.apache.fop.render.afp.AFPRendererOption.RESOURCE_GROUP_URI; |
| import static org.apache.fop.render.afp.AFPRendererOption.SHADING; |
| |
| /** |
| * The AFP renderer config object. |
| */ |
| public final class AFPRendererConfig implements RendererConfig { |
| |
| /** |
| * An enumeration for the various images modes available to the AFP renderer. |
| */ |
| public enum ImagesModeOptions { |
| |
| MODE_GRAYSCALE("b+w", "bits-per-pixel"), |
| MODE_COLOR("color", "cmyk"); |
| |
| private final String name; |
| |
| private final String modeAttribute; |
| |
| private ImagesModeOptions(String name, String modeAttribute) { |
| this.name = name; |
| this.modeAttribute = modeAttribute; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public String getModeAttribute() { |
| return modeAttribute; |
| } |
| |
| public static ImagesModeOptions forName(String name) { |
| for (ImagesModeOptions option : values()) { |
| if (option.name.equals(name)) { |
| return option; |
| } |
| } |
| throw new IllegalArgumentException(name); |
| } |
| } |
| |
| private final EnumMap<AFPRendererOption, Object> params |
| = new EnumMap<AFPRendererOption, Object>(AFPRendererOption.class); |
| |
| private final EnumMap<ImagesModeOptions, Object> imageModeParams |
| = new EnumMap<ImagesModeOptions, Object>(ImagesModeOptions.class); |
| |
| private final AFPFontConfig fontConfig; |
| |
| private AFPRendererConfig(AFPFontConfig fontConfig) { |
| this.fontConfig = fontConfig; |
| } |
| |
| public AFPFontConfig getFontInfoConfig() { |
| return fontConfig; |
| } |
| |
| public Boolean isColorImages() { |
| return getParam(IMAGES_MODE, Boolean.class); |
| } |
| |
| public Boolean isCmykImagesSupported() { |
| if (!isColorImages()) { |
| throw new IllegalStateException(); |
| } |
| return Boolean.class.cast(imageModeParams.get(MODE_COLOR)); |
| } |
| |
| public Integer getBitsPerPixel() { |
| if (isColorImages()) { |
| throw new IllegalStateException(); |
| } |
| return Integer.class.cast(imageModeParams.get(MODE_GRAYSCALE)); |
| } |
| |
| public Float getDitheringQuality() { |
| return getParam(IMAGES_DITHERING_QUALITY, Float.class); |
| } |
| |
| public Boolean isNativeImagesSupported() { |
| return getParam(IMAGES_NATIVE, Boolean.class); |
| } |
| |
| public AFPShadingMode getShadingMode() { |
| return getParam(SHADING, AFPShadingMode.class); |
| } |
| |
| public Integer getResolution() { |
| return getParam(RENDERER_RESOLUTION, Integer.class); |
| } |
| |
| |
| public URI getDefaultResourceGroupUri() { |
| return getParam(RESOURCE_GROUP_URI, URI.class); |
| } |
| |
| public AFPResourceLevelDefaults getResourceLevelDefaults() { |
| return getParam(DEFAULT_RESOURCE_LEVELS, AFPResourceLevelDefaults.class); |
| } |
| |
| public Boolean isWrapPseg() { |
| return getParam(IMAGES_WRAP_PSEG, Boolean.class); |
| } |
| |
| public Boolean isFs45() { |
| return getParam(IMAGES_FS45, Boolean.class); |
| } |
| |
| public Boolean allowJpegEmbedding() { |
| return getParam(JPEG_ALLOW_JPEG_EMBEDDING, Boolean.class); |
| } |
| |
| public Float getBitmapEncodingQuality() { |
| return getParam(JPEG_BITMAP_ENCODING_QUALITY, Float.class); |
| } |
| |
| public Float getLineWidthCorrection() { |
| return getParam(LINE_WIDTH_CORRECTION, Float.class); |
| } |
| |
| public Boolean isGocaEnabled() { |
| return getParam(GOCA, Boolean.class); |
| } |
| |
| public Boolean isStrokeGocaText() { |
| return getParam(GOCA_TEXT, Boolean.class); |
| } |
| |
| private <T> T getParam(AFPRendererOption options, Class<T> type) { |
| assert options.getType().equals(type); |
| return type.cast(params.get(options)); |
| } |
| |
| private <T> void setParam(AFPRendererOption option, T value) { |
| assert option.getType().isInstance(value); |
| params.put(option, value); |
| } |
| |
| /** |
| * The parser for AFP renderer specific data in the FOP conf. |
| */ |
| public static final class AFPRendererConfigParser implements RendererConfigParser { |
| |
| private static final Log LOG = LogFactory.getLog(AFPRendererConfigParser.class); |
| |
| /** {@inheritDoc} */ |
| public AFPRendererConfig build(FOUserAgent userAgent, Configuration cfg) throws FOPException { |
| boolean strict = userAgent.validateUserConfigStrictly(); |
| AFPRendererConfig config = null; |
| AFPEventProducer eventProducer = AFPEventProducer.Provider.get(userAgent.getEventBroadcaster()); |
| try { |
| config = new ParserHelper(cfg, userAgent.getFontManager(), strict, eventProducer).config; |
| } catch (ConfigurationException e) { |
| LogUtil.handleException(LOG, e, strict); |
| } |
| return config; |
| } |
| |
| /** {@inheritDoc} */ |
| public String getMimeType() { |
| return MimeConstants.MIME_AFP; |
| } |
| } |
| |
| private static final class ParserHelper { |
| |
| private static final Log LOG = LogFactory.getLog(ParserHelper.class); |
| |
| private final AFPRendererConfig config; |
| |
| private final boolean strict; |
| |
| private final Configuration cfg; |
| |
| private ParserHelper(Configuration cfg, FontManager fontManager, boolean strict, |
| AFPEventProducer eventProducer) |
| throws ConfigurationException, FOPException { |
| this.cfg = cfg; |
| this.strict = strict; |
| if (cfg != null) { |
| config = new AFPRendererConfig(new AFPFontInfoConfigParser().parse(cfg, |
| fontManager, strict, eventProducer)); |
| configure(); |
| } else { |
| config = new AFPRendererConfig(new AFPFontInfoConfigParser().getEmptyConfig()); |
| } |
| } |
| |
| private void configure() throws ConfigurationException, FOPException { |
| configureImages(); |
| setParam(SHADING, AFPShadingMode.getValueOf( |
| cfg.getChild(SHADING.getName()).getValue(AFPShadingMode.COLOR.getName()))); |
| Configuration rendererResolutionCfg = cfg.getChild(RENDERER_RESOLUTION.getName(), false); |
| setParam(RENDERER_RESOLUTION, rendererResolutionCfg == null ? 240 |
| : rendererResolutionCfg.getValueAsInteger(240)); |
| Configuration lineWidthCorrectionCfg = cfg.getChild(LINE_WIDTH_CORRECTION.getName(), |
| false); |
| setParam(LINE_WIDTH_CORRECTION, lineWidthCorrectionCfg != null |
| ? lineWidthCorrectionCfg.getValueAsFloat() |
| : AFPConstants.LINE_WIDTH_CORRECTION); |
| Configuration gocaCfg = cfg.getChild(GOCA.getName()); |
| boolean gocaEnabled = gocaCfg.getAttributeAsBoolean("enabled", true); |
| setParam(GOCA, gocaEnabled); |
| String strokeGocaText = gocaCfg.getAttribute(GOCA_TEXT.getName(), "default"); |
| setParam(GOCA_TEXT, "stroke".equalsIgnoreCase(strokeGocaText) |
| || "shapes".equalsIgnoreCase(strokeGocaText)); |
| //TODO remove |
| createResourceGroupFile(); |
| createResourceLevel(); |
| } |
| |
| private void setParam(AFPRendererOption option, Object value) { |
| config.setParam(option, value); |
| } |
| |
| private void configureImages() throws ConfigurationException, FOPException { |
| Configuration imagesCfg = cfg.getChild(IMAGES.getName()); |
| ImagesModeOptions imagesMode = ImagesModeOptions.forName(imagesCfg.getAttribute( |
| IMAGES_MODE.getName(), MODE_GRAYSCALE.getName())); |
| boolean colorImages = MODE_COLOR == imagesMode; |
| setParam(IMAGES_MODE, colorImages); |
| if (colorImages) { |
| config.imageModeParams.put(MODE_COLOR, imagesCfg |
| .getAttributeAsBoolean(imagesMode.getModeAttribute(), false)); |
| } else { |
| config.imageModeParams.put(MODE_GRAYSCALE, |
| imagesCfg.getAttributeAsInteger(imagesMode.getModeAttribute(), 8)); |
| } |
| String dithering = imagesCfg.getAttribute(AFPRendererOption.IMAGES_DITHERING_QUALITY.getName(), "medium"); |
| float dq; |
| if (dithering.startsWith("min")) { |
| dq = 0.0f; |
| } else if (dithering.startsWith("max")) { |
| dq = 1.0f; |
| } else { |
| try { |
| dq = Float.parseFloat(dithering); |
| } catch (NumberFormatException nfe) { |
| //Default value |
| dq = 0.5f; |
| } |
| } |
| setParam(IMAGES_DITHERING_QUALITY, dq); |
| setParam(IMAGES_NATIVE, imagesCfg.getAttributeAsBoolean(IMAGES_NATIVE.getName(), false)); |
| setParam(IMAGES_WRAP_PSEG, |
| imagesCfg.getAttributeAsBoolean(IMAGES_WRAP_PSEG.getName(), false)); |
| setParam(IMAGES_FS45, imagesCfg.getAttributeAsBoolean(IMAGES_FS45.getName(), false)); |
| if ("scale-to-fit".equals(imagesCfg.getAttribute(IMAGES_MAPPING_OPTION.getName(), null))) { |
| setParam(IMAGES_MAPPING_OPTION, MappingOptionTriplet.SCALE_TO_FILL); |
| } else { |
| setParam(IMAGES_MAPPING_OPTION, AFPDataObjectInfo.DEFAULT_MAPPING_OPTION); |
| } |
| configureJpegImages(imagesCfg); |
| } |
| |
| private void configureJpegImages(Configuration imagesCfg) { |
| Configuration jpegConfig = imagesCfg.getChild(IMAGES_JPEG.getName()); |
| float bitmapEncodingQuality = 1.0f; |
| boolean allowJpegEmbedding = false; |
| if (jpegConfig != null) { |
| allowJpegEmbedding = jpegConfig.getAttributeAsBoolean( |
| JPEG_ALLOW_JPEG_EMBEDDING.getName(), |
| false); |
| String bitmapEncodingQualityStr = jpegConfig.getAttribute( |
| JPEG_BITMAP_ENCODING_QUALITY.getName(), null); |
| if (bitmapEncodingQualityStr != null) { |
| try { |
| bitmapEncodingQuality = Float.parseFloat(bitmapEncodingQualityStr); |
| } catch (NumberFormatException nfe) { |
| //ignore and leave the default above |
| } |
| } |
| } |
| setParam(JPEG_BITMAP_ENCODING_QUALITY, bitmapEncodingQuality); |
| setParam(JPEG_ALLOW_JPEG_EMBEDDING, allowJpegEmbedding); |
| } |
| |
| private void createResourceGroupFile() throws FOPException { |
| try { |
| Configuration resourceGroupUriCfg = cfg.getChild(RESOURCE_GROUP_URI.getName(), false); |
| if (resourceGroupUriCfg != null) { |
| URI resourceGroupUri = InternalResourceResolver.cleanURI(resourceGroupUriCfg.getValue()); |
| setParam(RESOURCE_GROUP_URI, resourceGroupUri); |
| } |
| } catch (ConfigurationException e) { |
| LogUtil.handleException(LOG, e, strict); |
| } catch (URISyntaxException use) { |
| LogUtil.handleException(LOG, use, strict); |
| } |
| } |
| |
| private void createResourceLevel() throws FOPException { |
| Configuration defaultResourceLevelCfg = cfg.getChild(DEFAULT_RESOURCE_LEVELS.getName(), false); |
| if (defaultResourceLevelCfg != null) { |
| AFPResourceLevelDefaults defaults = new AFPResourceLevelDefaults(); |
| String[] types = defaultResourceLevelCfg.getAttributeNames(); |
| for (String type : types) { |
| try { |
| String level = defaultResourceLevelCfg.getAttribute(type); |
| defaults.setDefaultResourceLevel(type, AFPResourceLevel.valueOf(level)); |
| } catch (IllegalArgumentException iae) { |
| LogUtil.handleException(LOG, iae, strict); |
| } catch (ConfigurationException e) { |
| LogUtil.handleException(LOG, e, strict); |
| } |
| } |
| setParam(DEFAULT_RESOURCE_LEVELS, defaults); |
| } |
| } |
| } |
| } |