double sin = Math.sin(Math.toRadians(rotation)); double cos = Math.cos(Math.toRadians(rotation));
double sin = Math.sin(rotation); double cos = Math.cos(rotation);
	private void writePostScriptOrPDFImage(BufferedImage image, double x, double y,		double width, double height, double rotation)		throws IOException, MapyrusException	{		int pixelWidth, pixelHeight;		int step;		String imageKey = null;		if (mPDFImageObjects != null)			imageKey = "Im" + mPDFImageObjects.size();		StringWriter sw = null;		PrintWriter pw;		if (mOutputType == PDF)			pw = new PrintWriter(sw = new StringWriter());		else			pw = mWriter;		pixelWidth = image.getWidth();		pixelHeight = image.getHeight();		/*		 * Calculate reduction in image size so that it is 		 * an appropriate size for the resolution of the page.		 */		if (pixelWidth <= 16 || pixelHeight <= 16)		{			step = 1;		}		else		{			double bestPixelWidth = width / mResolution;			double bestPixelHeight = height / mResolution;			/*			 * Keep reducing image 1/2, 1/3, 1/4, ... until it reaches the			 * resolution of the page.  Use that reduction for image.			 */			step = 1;			while (pixelHeight / (step + 1) > bestPixelHeight &&				pixelWidth / (step + 1) > bestPixelWidth)			{				step++;			}		}		int reducedPixelWidth = (pixelWidth + step - 1) / step;		int reducedPixelHeight = (pixelHeight + step - 1) / step;		/*		 * Check if image is a single color.		 * Draw single color images with transparent background		 * using PostScript 'imagemask' operator.		 * Draw other images as RGB images using 'image' operator.		 */		Color singleColor = getSingleImageColor(image);		/*		 * Write PostScript image directionary entry to draw image.		 * Taken from Adobe PostScript Language Reference Manual		 * (2nd Edition), p. 234.		 */		if (mOutputType == PDF)		{			writeLine(mPDFGeometryWriter, "q");			writeLine(mPDFGeometryWriter, "1 0 0 1 " +				mCoordinateDecimal.format(x) + " " +				mCoordinateDecimal.format(y) + " cm % translate");			double sin = Math.sin(Math.toRadians(rotation));			double cos = Math.cos(Math.toRadians(rotation));			writeLine(mPDFGeometryWriter, mCoordinateDecimal.format(cos) + " " +				mCoordinateDecimal.format(sin) + " " +				mCoordinateDecimal.format(-sin) + " " +				mCoordinateDecimal.format(cos) + " 0 0 cm % rotate " + rotation);			writeLine(mPDFGeometryWriter, mCoordinateDecimal.format(x) +				" 0 0 " + mCoordinateDecimal.format(y) + " 0 0 cm % scale");			writeLine(mPDFGeometryWriter, "1 0 0 1 -0.5 -0.5 cm % translate");			writeLine(mPDFGeometryWriter, "/" + imageKey + " Do");			writeLine(mPDFGeometryWriter, "Q");		}		else		{			writeLine(pw, "q");			writeLine(pw, "/DeviceRGB setcolorspace");			writeLine(pw, x + " " + y + " translate");			writeLine(pw, rotation + " radtodeg rotate");			writeLine(pw, width + " " + height + " scale");					/*			 * Image is centred at each point.			 * Shift image left and down half it's size so that it is displayed centred.			 */			writeLine(pw, "-0.5 -0.5 translate");		}		/*		 * Set color for drawing single color images.		 */		if (singleColor != null)		{			float []c = singleColor.getColorComponents(null);			PrintWriter pw2 = (mOutputType == PDF) ? mPDFGeometryWriter : mWriter;			writeLine(pw2, mCoordinateDecimal.format(c[0]) + " " +				mCoordinateDecimal.format(c[1]) + " " +				mCoordinateDecimal.format(c[2]) + " RG");		}		writeLine(pw, "% original image size " + pixelWidth + "x" + pixelHeight + " with reduction factor " + step);		writeLine(pw, "<<");		if (mOutputType == PDF)			writeLine(pw, "/Type /XObject /Subtype /Image /ColorSpace /DeviceRGB");		else			writeLine(pw, "/ImageType 1");		writeLine(pw, "/Width " + reducedPixelWidth);		writeLine(pw, "/Height " + reducedPixelHeight);		if (singleColor != null)		{			writeLine(pw, "/BitsPerComponent 1");			writeLine(pw, "/Decode [0 1]");			if (mOutputType == PDF)				writeLine(pw, "/ImageMask true");		}		else		{			writeLine(pw, "/BitsPerComponent 8");			writeLine(pw, "/Decode [0 1 0 1 0 1]");		}		if (mOutputType == PDF)		{			writeLine(pw, "/Filter /ASCII85Decode");		}		else		{			writeLine(pw, "/ImageMatrix [" + reducedPixelWidth + " 0 0 " +					-reducedPixelHeight + " 0 " + reducedPixelHeight + "]");			writeLine(pw, "/DataSource currentfile /ASCII85Decode filter");			writeLine(pw, ">>");			if (singleColor != null)				writeLine(pw, "imagemask");			else				writeLine(pw, "image");		}		/*		 * Write ASCII85 encoded string containing all pixel values.		 */		StringWriter ascii85sw = new StringWriter();		PrintWriter ascii85pw = (mOutputType == PDF) ? new PrintWriter(ascii85sw) : pw;		ASCII85Writer ascii85 = new ASCII85Writer(ascii85pw);		int byteValue = 0;		int bitCounter = 0;		for (int row = 0; row < pixelHeight; row += step)		{			for (int col = 0; col < pixelWidth; col += step)			{				int pixel = image.getRGB(col, row);				if (singleColor != null)				{					/*					 * Pixel is set in PostScript image if it is transparent.					 */					int nextBit = ((pixel >> 24) == 0) ? 1 : 0;					/*					 * Store next pixel value as a single bit in a byte.					 * If we've completed a byte or reached the end of a row					 * then write byte out and begin next byte.					 */					nextBit <<= (7 - bitCounter);					byteValue |= nextBit;					bitCounter++;						if (bitCounter == 8 || (col + step >= pixelWidth))					{						ascii85.write(byteValue);						byteValue = bitCounter = 0;					}				}				else				{					/*					 * Ignore transparency, we want only red, green, blue components					 * of pixel.					 */					int blue = (pixel & 0xff);					int green = ((pixel >> 8) & 0xff);					int red = ((pixel >> 16) & 0xff);						ascii85.write(red);					ascii85.write(green);					ascii85.write(blue);				}			}		}		ascii85.close();		/*		 * Write ASCII85 end-of-data marker.		 */		writeLine(ascii85pw, "~>");		if (mOutputType == PDF)		{			ascii85pw.flush();			String s = ascii85sw.toString();			writeLine(pw, "/Length " + (s.length() + 2));			writeLine(pw, ">>");			writeLine(pw, "stream");			writeLine(pw, s);			writeLine(pw, "endstream");			pw.flush();			mPDFImageObjects.put(imageKey, sw);		}		else		{			writeLine(pw, "Q");		}	}