Archive for the ‘HOWTO’ Category

MegaRAID PERC 3/SC on Opensolaris

Friday, March 12th, 2010

Opensolaris (as new as snv_133) does not automatically detect disks on this hardware (specifically on an older Dell PowerEdge 6000SC). I did the following on the LiveCD to get it to work:

add_drv -i ‘pci1028,475′ lsimega

I got the numbers above from the “prtpicl” tool, using “prtpicl -v” and searching for MegaRaid:

:name      pci1028,475
sd (block, b6000002f8)
:class         scsi
:inquiry-device-type   0
:inquiry-vendor-id     MegaRAID
:inquiry-product-id    LD 0 RAID0  139G

Hope this helps someone other than myself. I also added a blank file named “ADD_DRV_IGNORE_ROOT_BASEDIR” to / as per a bug post but I do not believe that had any effect. I did stumble a bit before I found this (chasing around a PERC 5 driver) but I don’t recall trying to install this driver beforehand.

OpenSolaris – What do you do when your image-update doesn’t work?

Thursday, March 4th, 2010

I’ve been a long time user of/tinkerer with OpenSolaris on my desktop (for the obvious reasons: Time Slider, ZFS, DTrace, etc). I am going to start posting tips & tricks. To start off, here is one way I have found to “fix” a “pkg image-update” failure. All it does is create a new boot environment and install to it, which can solve a lot of the problems that might occur when running on the pkg.opensolaris.org/dev repository when you update:

beadm create osol-snv_1XX
mkdir /mnt/osol-snv_1XX
beadm mount osol-snv_1XX /mnt/osol-snv_1XX
pkg -R osol-snv_1XX install SUNWipkg
pkg -R osol-snv_1XX image-update
bootadm update-archive -R /mnt/osol-snv_1XX
beadm activate osol-snv_1XX

Notes:

  1. osol-snv_1XX is simply the name you give the new boot environment. XX being the snv version (currently 133).
  2. beadm is the command for working with boot environments in zfs. Create makes a snapshot, mount mounts it to a particular directory, and activate makes it the default on the next reboot.
  3. pkg -R does the update on the alternate boot env.
  4. bootadm adds the boot environment to grub (update the archive using that directory as the root is what we are telling it to do here, just like the pkg -R cmd).

If someone visiting this blog has alternate methods, I’d be interested in knowing about it.

HOWTO: Scanned Images to Encrypted PDF in Linux

Saturday, October 10th, 2009

I had scanned a bunch of images and needed to bundle them all up into PDF. It took about 20 minutes to figure out, which is way too long, so here’s the steps so I can remind myself in the future:

  1. scanimage –batch=”%d.tiff” –format=tiff –resolution 300 –bgcolor white –mode=Lineart
  2. ls -tr1 | xargs -Ixxx lp -d PDF -o fitplot -o page-top=0 -o page-bottom=0 -o page-left=0 -o page-right=0 “xxx”
  3. gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=finished.pdf `ls -tr1` OR pdftk `ls -tr1` cat output finished.pdf
  4. pdftk finished.pdf output enc.pdf user_pw <pass> allow CopyContents printing

Notes:

  • gs may be able to do step 2, but if it can’t you’ll need to install “cups-pdf” and restart cups.
  • gs may also be able to do 1-3 in 1 step.
  • Similarly, pdftk might be able to do most of this in 1 step, too. It just didn’t occur to me until after I used it for the encryption.

Java CMYK HOWTO

Monday, November 24th, 2008

Lately, I’ve been playing with printers-trying to control the amount of cyan, magenta, yellow, and black printed by the printer. For various reasons I’ve been doing it in Java,and I’ve run up against some brick walls. There is no good HOWTO available, so I decided to write my own…

Java supports RGB by default and it works well, but it treats everything else like the proverbial red headed step child. To get it to work you have to find an ICC_Profile (CMYK.pf), load the file dynamically, and then do all your image manipulation. I never looked far enough to find out for sure, but I believe you have to do some special work to get it to save as CMYK also. It’s a pain.

The other option is to extend ColorSpace to support CMYK. You still have to save in a funny way, but this is what I decided to do.

First, the ColorSpace extension (available here, note that the code here is all GPL):

public class CMYKColorSpace extends ColorSpace implements Serializable {

	private static final long serialVersionUID = -5982040365555064012L;

	/**
	 * Create a new CMYKColorSpace Instance.
	 */
	public CMYKColorSpace() {
		super(ColorSpace.TYPE_CMYK, 4);
	}

	/**
	 * Converts to CMYK from CIEXYZ. We cheat here, using the RGB colorspace
	 * to do the math for us. The toCIEXYZ function has a description of how
	 * this is supposed to work, which may be implemented in the future.
	 *
	 * @see java.awt.color.ColorSpace#fromCIEXYZ(float[])
	 * @see org.scantegrity.lib.CMYKColorSpace#toCIEXYZ
	 */
	@Override
	public float[] fromCIEXYZ(float[] p_colorvalue) {
		ColorSpace l_cs = ColorSpace.getInstance(ColorSpace.TYPE_RGB);
		float[] l_rgb = l_cs.toCIEXYZ(p_colorvalue);
		return fromRGB(l_rgb);
	}

	/**
	 * Converts a given RGB to CMYK. RGB doesn't really use black, so K will
	 * always be 0. On printers, the black should actually look dark brown.
	 * RGB (an additive space) is simply the backwards from CMY (a subtractive
	 * space), so all we do is:
	 *
	 * 		C = 1-R
	 * 		M = 1-G
	 * 		Y = 1-B
	 *
	 * @param p_rgbvalue - The color to translate
	 * @return a float[4] of the CMYK values.
	 * @see java.awt.color.ColorSpace#fromRGB(float[])
	 */
	@Override
	public float[] fromRGB(float[] p_rgbvalue) {
		/* TODO: Maybe we should do a better job to determine when black should
		 * be used and pulled out? -- At this time, it's not necessary for our
		 * (Scantegrity's) uses.
		 */
		float[] l_res = {0,0,0,0};
		if (p_rgbvalue.length >= 3) {
			l_res[0] = (float)1.0 - p_rgbvalue[0];
			l_res[1] = (float)1.0 - p_rgbvalue[1];
			l_res[2] = (float)1.0 - p_rgbvalue[2];
		}
		return normalize(l_res);
	}

	/**
	 * Converts the CMYK color to CIEXYZ. Because CIEXYZ is 3-component, we
	 * cheat, converting to RGB and then using the RGB colorspace function
	 * to do the conversion. Details on this colorspace are available on
	 * wikipedia:
	 *
	 * http://en.wikipedia.org/wiki/CIE_XYZ_color_space
	 *
	 * There is also an "ideal relationship" to CMYK, which might be implemented
	 * in the future (don't recall the reference we got this from, probably
	 * color.org):
	 *
	 * C = (C' - K)/(1 - K)
	 * M = (M' - K)/(1 - K)
	 * Y = (Y' - K)/(1 - K)
	 * K = Min(C', M', Y')
	 *
	 * X   41.2453 35.7580 18.0423 | 1-C'
	 * Y = 21.2671 71.5160 07.2169 | 1-M'
	 * Z   01.9334 11.9193 95.0227 | 1-Y'
	 *
	 * @see java.awt.color.ColorSpace#toCIEXYZ(float[])
	 */
	@Override
	public float[] toCIEXYZ(float[] p_colorvalue) {
		float[] l_rgb = toRGB(p_colorvalue);
		ColorSpace l_cs = ColorSpace.getInstance(ColorSpace.TYPE_RGB);
		return l_cs.toCIEXYZ(l_rgb);
	}

	/**
	 * Converts CMYK colors to RGB. Note that converting back will be lossy. The
	 * formula for this is:
	 *
	 * K = 1 - K (go to additive)
	 * R = K * (1 - C)
	 * G = K * (1 - M)
	 * B = K * (1 - Y)
	 *
	 * @param p_colorvalue The color in CMYK.
	 * @see java.awt.color.ColorSpace#toRGB(float[])
	 */
	@Override
	public float[] toRGB(float[] p_colorvalue) {
		float[] l_res = {0,0,0};
		if (p_colorvalue.length >= 4)
		{
			float l_black = (float)1.0 - p_colorvalue[3];
			l_res[0] = l_black * ((float)1.0 - p_colorvalue[0]);
			l_res[1] = l_black * ((float)1.0 - p_colorvalue[1]);
			l_res[2] = l_black * ((float)1.0 - p_colorvalue[2]);
		}
		return normalize(l_res);
	}

	/**
	 * Normalize ensures all color values returned are between 0 and 1.
	 *
	 * @param p_colors
	 * @return p_colors, with any values greater than 1 set to 1, and less than
	 * 0 set to 0.
	 */
	private float[] normalize(float[] p_colors) {
		for (int l_i = 0; l_i < p_colors.length; l_i++) {
			if (p_colors[l_i] > (float)1.0) p_colors[l_i] = (float)1.0;
			else if (p_colors[l_i] < (float)0.0) p_colors[l_i] = (float)0.0;
		}
		return p_colors;
	}
}

The color space is used to convert CMYK to RGB or CIEXYZ on demand, which is done whenever Java displays images on the screen, saves them, or copies them to any context in which the color space is different. It also allows you to create CMYK colors and to store the data in a custom color model/sample color model.

Creating CMYK Colors

This is self explanatory:

float[] l_colorComponents = {1, 0, 0, 0};
CMYKColorSpace l_cs = new CMYKColorSpace();
Color l_cyan = new Color(l_cs, l_colorComponents, 1);

Creating a BufferedImage with CMYK Colors

This piece is the most complicated becase you need to understand how Java models the colors in an Image Object. You may want something in-depth, but here’s a short explanation: Each color in java is represented as a “band,” and it is stored in a way defined by Model and stored in a generic “DataBuffer” object.  To get it working you create a (usually component) ColorModel, and then create a sample model with the specific layout (Interleaved, banded or one color per, etc). The sample model creates a Raster, which then creates the Image object.

CMYKColorSpace l_cs = new CMYKColorSpace();
ComponentColorModel l_ccm = new ComponentColorModel(l_cs, false, false,
						1, DataBuffer.TYPE_FLOAT);
int[] l_bandoff = {0, 1, 2, 3}; //Index for each color (C, is index 0, etc)
PixelInterleavedSampleModel l_sm = new PixelInterleavedSampleModel(
						   DataBuffer.TYPE_FLOAT,
						   (int)l_width, (int)l_height,
					     	   4,(int)l_width*4, l_bandoff);
WritableRaster l_raster = WritableRaster.createWritableRaster(l_sm,
							new Point(0,0));
BufferedImage l_ret = new BufferedImage(l_ccm, l_raster, false, null);

Graphics2D l_g2d = l_ret.createGraphics();

Saving CMYK Images

For this, I chose to use the iText library to save in PDF format. All you have to do is pull the DataBuffer out of the raster and save the bytes. You might also want to save in JPEG or another kind of format, which should be reasonably easy (just send the function the right bytes in the right order) once you’ve seen below:

Raster l_tmpRaster = c_img.getRaster();
DataBuffer l_db = l_tmpRaster.getDataBuffer();
byte[] l_bytes = new byte[l_db.getSize()];
for (int l_i = 0; l_i < l_bytes.length; l_i++) {
	l_bytes[l_i] = (byte)Math.round(l_db.getElemFloat(l_i)*(float)255);
}

com.lowagie.text.Image l_img = com.lowagie.text.Image.getInstance(
								l_tmpRaster.getWidth(),
								l_tmpRaster.getHeight(),
								4, 8, l_bytes);
l_img.setDpi(300, 300);
Document l_doc = new Document(new Rectangle(0,0,l_img.getWidth(), l_img.getHeight()));
l_doc.setMargins(0,0,0,0);
PdfWriter.getInstance(l_doc,
			new FileOutputStream("inkeratorout" + c_c + ".pdf"));
l_doc.open();
l_doc.add(l_img);
l_doc.close();

Everything else should work as normal (just remember that it is calling the colorspace functions to do it’s job).

I wrote this in a bit of a rush (i’m pretty busy today). I haven’t had any problems with it yet, but if you do please feel free to leave a note below.d