<commit_before>/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2013 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the GNU Affero
 * General Public License. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */

package org.geomajas.plugin.printing.component.impl;

import java.awt.Color;
import java.awt.Font;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.ParameterBlock;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.imageio.ImageIO;
import javax.media.jai.ImageLayout;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.MosaicDescriptor;
import javax.media.jai.operator.TranslateDescriptor;

import org.geomajas.configuration.client.ClientMapInfo;
import org.geomajas.geometry.Bbox;
import org.geomajas.global.GeomajasException;
import org.geomajas.layer.RasterLayerService;
import org.geomajas.layer.tile.RasterTile;
import org.geomajas.plugin.printing.component.LayoutConstraint;
import org.geomajas.plugin.printing.component.PdfContext;
import org.geomajas.plugin.printing.component.PrintComponentVisitor;
import org.geomajas.plugin.printing.component.dto.RasterLayerComponentInfo;
import org.geomajas.plugin.printing.component.service.PrintConfigurationService;
import org.geomajas.service.DispatcherUrlService;
import org.geomajas.service.GeoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.sun.media.jai.codec.ByteArraySeekableStream;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
import com.vividsolutions.jts.geom.Envelope;

/**
 * Sub component of a map responsible for rendering raster layer.
 * 
 * @author <NAME>
 */
@Component()
@Scope(value = "prototype")
public class RasterLayerComponentImpl extends BaseLayerComponentImpl<RasterLayerComponentInfo> {

	protected static final int DOWNLOAD_MAX_ATTEMPTS = 2;

	protected static final int DOWNLOAD_MAX_THREADS = 5;

	protected static final long DOWNLOAD_TIMEOUT = 120000; // millis

	protected static final long DOWNLOAD_TIMEOUT_ONE_TILE = 100; // millis

	protected static final Font ERROR_FONT = new Font("SansSerif", Font.PLAIN, 6); //$NON-NLS-1$

	private static final String BUNDLE_NAME = "org/geomajas/extension/printing/rasterlayercomponent"; //$NON-NLS-1$

	// do not make this static, different requests might need different bundles
	@XStreamOmitField
	private final ResourceBundle resourceBundle = ResourceBundle.getBundle(BUNDLE_NAME);

	/** The calculated bounds. */
	@XStreamOmitField
	protected Envelope bbox;

	/** List of the tile images. */
	@XStreamOmitField
	protected List<RasterTile> tiles;

	/** The raster scale, may be different from map ppunit. */
	@XStreamOmitField
	protected double rasterScale;

	@XStreamOmitField
	private final Logger log = LoggerFactory.getLogger(RasterLayerComponentImpl.class);

	@Autowired
	@XStreamOmitField
	private RasterLayerService rasterLayerService;

	@Autowired
	@XStreamOmitField
	private PrintConfigurationService configurationService;

	@Autowired
	@XStreamOmitField
	private GeoService geoService;

	@Autowired
	@XStreamOmitField
	private DispatcherUrlService dispatcherUrlService;

	private float opacity = 1.0f;

	/** Constructor. */
	public RasterLayerComponentImpl() {
		getConstraint().setAlignmentX(LayoutConstraint.JUSTIFIED);
		getConstraint().setAlignmentY(LayoutConstraint.JUSTIFIED);
	}

	/**
	 * Call back visitor.
	 * 
	 * @param visitor
	 *            visitor
	 */
	public void accept(PrintComponentVisitor visitor) {
	}

	@Override
	public void render(PdfContext context) {
		if (isVisible()) {
			rasterScale = getMap().getPpUnit() * getMap().getRasterResolution() / 72;
			bbox = createBbox();
			if (log.isDebugEnabled()) {
				log.debug("rendering" + getLayerId() + " to [" + bbox.getMinX() + " " + bbox.getMinY() + " "
						+ bbox.getWidth() + " " + bbox.getHeight() + "]");
			}
			ClientMapInfo map = configurationService.getMapInfo(getMap().getMapId(), getMap().getApplicationId());
			try {
				tiles = rasterLayerService.getTiles(getLayerId(), geoService.getCrs2(map.getCrs()), bbox, rasterScale);
				if (tiles.size() > 0) {
					Collection<Callable<ImageResult>> callables = new ArrayList<Callable<ImageResult>>(tiles.size());
					// Build the image downloading threads
					for (RasterTile tile : tiles) {
						RasterImageDownloadCallable downloadThread = new RasterImageDownloadCallable(
								DOWNLOAD_MAX_ATTEMPTS, tile);
						callables.add(downloadThread);
					}
					// Loop until all images are downloaded or timeout is reached
					long totalTimeout = DOWNLOAD_TIMEOUT + DOWNLOAD_TIMEOUT_ONE_TILE * tiles.size();
					log.debug("=== total timeout (millis): {}", totalTimeout);
					ExecutorService service = Executors.newFixedThreadPool(DOWNLOAD_MAX_THREADS);
					List<Future<ImageResult>> futures = service.invokeAll(callables, totalTimeout,
							TimeUnit.MILLISECONDS);
					// determine the pixel bounds of the mosaic
					Bbox pixelBounds = getPixelBounds(tiles);
					int imageWidth = configurationService.getRasterLayerInfo(getLayerId()).getTileWidth();
					int imageHeight = configurationService.getRasterLayerInfo(getLayerId()).getTileHeight();
					// create the images for the mosaic
					List<RenderedImage> images = new ArrayList<RenderedImage>();
					for (Future<ImageResult> future : futures) {
						if (future.isDone()) {
							try {
								ImageResult result;
								result = future.get();
								// create a rendered image
								RenderedImage colored = JAI.create("stream",
										new ByteArraySeekableStream(result.getImage()));
								// convert to common direct colormodel (some images have their own indexed color model)
								// Sprint-51 If the image source is not available the java.awt.image will throw
								// a runtime error causing the printing to fail. If this happens handle the error
								// and and allow the print process to continue.
								// convert to common direct colormodel (some images have their own indexed color model)
								RenderedImage colored = null;
								try {
									colored = toDirectColorModel(image);
								} catch (Exception e) {
									String msg = getLayerId() + " returned a null image.";
									msg += " The printing plugin will not render this layer";
									log.error(msg, e);
									continue;
								}<commit_msg>Fixed build error in printing module color correction<commit_after>/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2013 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the GNU Affero
 * General Public License. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */

package org.geomajas.plugin.printing.component.impl;

import java.awt.Color;
import java.awt.Font;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.ParameterBlock;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.imageio.ImageIO;
import javax.media.jai.ImageLayout;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.MosaicDescriptor;
import javax.media.jai.operator.TranslateDescriptor;

import org.geomajas.configuration.client.ClientMapInfo;
import org.geomajas.geometry.Bbox;
import org.geomajas.global.GeomajasException;
import org.geomajas.layer.RasterLayerService;
import org.geomajas.layer.tile.RasterTile;
import org.geomajas.plugin.printing.component.LayoutConstraint;
import org.geomajas.plugin.printing.component.PdfContext;
import org.geomajas.plugin.printing.component.PrintComponentVisitor;
import org.geomajas.plugin.printing.component.dto.RasterLayerComponentInfo;
import org.geomajas.plugin.printing.component.service.PrintConfigurationService;
import org.geomajas.service.DispatcherUrlService;
import org.geomajas.service.GeoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.sun.media.jai.codec.ByteArraySeekableStream;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
import com.vividsolutions.jts.geom.Envelope;

/**
 * Sub component of a map responsible for rendering raster layer.
 * 
 * @author <NAME>
 */
@Component()
@Scope(value = "prototype")
public class RasterLayerComponentImpl extends BaseLayerComponentImpl<RasterLayerComponentInfo> {

	protected static final int DOWNLOAD_MAX_ATTEMPTS = 2;

	protected static final int DOWNLOAD_MAX_THREADS = 5;

	protected static final long DOWNLOAD_TIMEOUT = 120000; // millis

	protected static final long DOWNLOAD_TIMEOUT_ONE_TILE = 100; // millis

	protected static final Font ERROR_FONT = new Font("SansSerif", Font.PLAIN, 6); //$NON-NLS-1$

	private static final String BUNDLE_NAME = "org/geomajas/extension/printing/rasterlayercomponent"; //$NON-NLS-1$

	// do not make this static, different requests might need different bundles
	@XStreamOmitField
	private final ResourceBundle resourceBundle = ResourceBundle.getBundle(BUNDLE_NAME);

	/** The calculated bounds. */
	@XStreamOmitField
	protected Envelope bbox;

	/** List of the tile images. */
	@XStreamOmitField
	protected List<RasterTile> tiles;

	/** The raster scale, may be different from map ppunit. */
	@XStreamOmitField
	protected double rasterScale;

	@XStreamOmitField
	private final Logger log = LoggerFactory.getLogger(RasterLayerComponentImpl.class);

	@Autowired
	@XStreamOmitField
	private RasterLayerService rasterLayerService;

	@Autowired
	@XStreamOmitField
	private PrintConfigurationService configurationService;

	@Autowired
	@XStreamOmitField
	private GeoService geoService;

	@Autowired
	@XStreamOmitField
	private DispatcherUrlService dispatcherUrlService;

	private float opacity = 1.0f;

	/** Constructor. */
	public RasterLayerComponentImpl() {
		getConstraint().setAlignmentX(LayoutConstraint.JUSTIFIED);
		getConstraint().setAlignmentY(LayoutConstraint.JUSTIFIED);
	}

	/**
	 * Call back visitor.
	 * 
	 * @param visitor
	 *            visitor
	 */
	public void accept(PrintComponentVisitor visitor) {
	}

	@Override
	public void render(PdfContext context) {
		if (isVisible()) {
			rasterScale = getMap().getPpUnit() * getMap().getRasterResolution() / 72;
			bbox = createBbox();
			if (log.isDebugEnabled()) {
				log.debug("rendering" + getLayerId() + " to [" + bbox.getMinX() + " " + bbox.getMinY() + " "
						+ bbox.getWidth() + " " + bbox.getHeight() + "]");
			}
			ClientMapInfo map = configurationService.getMapInfo(getMap().getMapId(), getMap().getApplicationId());
			try {
				tiles = rasterLayerService.getTiles(getLayerId(), geoService.getCrs2(map.getCrs()), bbox, rasterScale);
				if (tiles.size() > 0) {
					Collection<Callable<ImageResult>> callables = new ArrayList<Callable<ImageResult>>(tiles.size());
					// Build the image downloading threads
					for (RasterTile tile : tiles) {
						RasterImageDownloadCallable downloadThread = new RasterImageDownloadCallable(
								DOWNLOAD_MAX_ATTEMPTS, tile);
						callables.add(downloadThread);
					}
					// Loop until all images are downloaded or timeout is reached
					long totalTimeout = DOWNLOAD_TIMEOUT + DOWNLOAD_TIMEOUT_ONE_TILE * tiles.size();
					log.debug("=== total timeout (millis): {}", totalTimeout);
					ExecutorService service = Executors.newFixedThreadPool(DOWNLOAD_MAX_THREADS);
					List<Future<ImageResult>> futures = service.invokeAll(callables, totalTimeout,
							TimeUnit.MILLISECONDS);
					// determine the pixel bounds of the mosaic
					Bbox pixelBounds = getPixelBounds(tiles);
					int imageWidth = configurationService.getRasterLayerInfo(getLayerId()).getTileWidth();
					int imageHeight = configurationService.getRasterLayerInfo(getLayerId()).getTileHeight();
					// create the images for the mosaic
					List<RenderedImage> images = new ArrayList<RenderedImage>();
					for (Future<ImageResult> future : futures) {
						if (future.isDone()) {
							try {
								ImageResult result;
								result = future.get();
								// create a rendered image
								RenderedImage image = JAI.create("stream",
										new ByteArraySeekableStream(result.getImage()));
								// convert to common direct colormodel (some images have their own indexed color model)
								// Sprint-51 If the image source is not available the java.awt.image will throw
								// a runtime error causing the printing to fail. If this happens handle the error
								// and and allow the print process to continue.
								// convert to common direct colormodel (some images have their own indexed color model)
								RenderedImage colored = null;
								try {
									colored = toDirectColorModel(image);
								} catch (Exception e) {
									String msg = getLayerId() + " returned a null image.";
									msg += " The printing plugin will not render this layer";
									log.error(msg, e);
									continue;
								}
{'fraction_non_alphanumeric': 0.09818950707017313, 'fraction_numerical': 0.00422888859521607, 'mean_word_length': 4.471800433839479, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2660333', 'n_tokens_mistral': 5078, 'n_tokens_neox': 4390, 'n_words': 1081}