Click here to Skip to main content
15,881,882 members
Please Sign up or sign in to vote.
1.67/5 (5 votes)
hello everybody ,
i have a function in c++ which works correctly and its task is compress the BMP image similar to [[RLE]
but encoding is not quite same as RLE , this code is written by experienced c++ programmer to send image to some kind of printer (with specific firmware) unfortunately the guy currently is not in our office any more so we have not access to him . i have to write this code in java application because we could not put any native dll in client site , so I've started to convert code , my problem is that i could not understand what exactly happens in C++ function and how should i implement it in java, please look at this functions and help to solve the problem, unfortunately i am a beginner in c++ and Image processing
in other hand I've developed another java class that uses java features to do same as c++ ( as my perception of C++ function's algorithm ) but it is not working and i don't know why but i am sure it is because of encoding.
So i put all of them here , hope someone could help me
i am sorry because functions are long, but i think it is a good challenge for experts .

thease are my C++ functions :

C++
TPESCCOMMANDS_API int _cdecl GetMonoData(int xpos, int ypos, char *pImageFile, LPBYTE data, int * dataSize )
{
	int    bRet = TRUE;
	HANDLE hFile;
	DWORD  dwFileSize, dwReturnBytes;
	char   pBuf[512];
	char   pData[512];
	int    i, x, y, k, z;
	
	hFile = CreateFile(pImageFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		// Could not open file
        return FALSE; 
    }
	dwFileSize = GetFileSize(hFile, NULL);
	if ( dwFileSize > 0 )
	{
		char *pFileData;
		char *pTemp;
		char *pImageData;
		char *pPrintData;
		char *pDst2;
		BITMAPFILEHEADER *pbmfile;
		BITMAPINFOHEADER *pbminfo;
		int   width, height, width_bytes, src_line, fill_bits;
		BYTE  ch, zh;
		BYTE rbit_index[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
		BYTE  bit_index[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
		int   src_wid, src_hgt;

		pFileData = (char *)GlobalAlloc(GPTR, dwFileSize);
		pPrintData = (char *)GlobalAlloc(GPTR, dwFileSize * 2);
		bRet = ReadFile(hFile, pFileData, dwFileSize, &dwReturnBytes, NULL);
		wsprintf(pData,"dwFileSize = %d, dwReturnBytes = %d\r\n",dwFileSize,dwReturnBytes);	for(int i=0; i<strlen(pData); i++) dfile << pData[i]; dfile << endl;

		pTemp = pFileData;
		pbmfile = (BITMAPFILEHEADER *)pTemp;
		pTemp = pTemp + sizeof(BITMAPFILEHEADER);		
		
		pbminfo = (BITMAPINFOHEADER *)pTemp;
		pTemp = pTemp + sizeof(BITMAPINFOHEADER);
		pImageData = pTemp;

		src_wid = pbminfo->biWidth;
		src_hgt = pbminfo->biHeight;

		if ( pbminfo->biBitCount != 1 )	// Convert 24 bit -> 1 bit 
		{
			dfile << "STEP -1" << endl;
			int sw, sh, si, step;
			int dw, dh, di, k;
			BYTE *pSrc, *pDst;

			step = pbminfo->biBitCount / 8;
			sw = src_wid;
			sh = src_hgt;
			si = (sw * step);
			si = ((si + 3) / 4) * 4;

			pbminfo->biBitCount = 1;
			dw = sw;
			dh = sh;
			di = (((dw + 31) / 32) * (32/8));
		
			pSrc = (BYTE *)pImageData;
			pSrc += si;	// last line
			pDst = (BYTE *)pImageData;
			pDst += di;	// last line
			dfile << "STEP -6" << endl;
			for ( y=0; y < (sh-2); y++ )
			{
				for (x=0,k=0; x < si; x+=step, k++ )
				{
					ch = INTENSITY(pSrc[x+0],pSrc[x+1],pSrc[x+2]);
					if ( ch > (BYTE)128 ) pDst[k/8] |= rbit_index[k%8];
					else                  pDst[k/8] &=~rbit_index[k%8];
				}
				wsprintf(pData,"y = %d, x = %d, k = %d, pSrc = [%p], pDst = [%p]\r\n",y,x,k,pSrc,pDst);	for(int i=0; i<strlen(pData); i++) dfile << pData[i]; dfile << endl;
				pSrc += si;	// next line
				pDst += di;	// next line
			}
			dfile << "STEP -7" << endl;
		}
		
		dfile << "STEP -8" << endl;
		width = src_wid;
		height = src_hgt;
		src_line = (((width + 31) / 32) * (32/8));
		wsprintf(pData,"width = %d, height = %d, src_line = %d\r\n",width,height,src_line);	for(int i=0; i<strlen(pData); i++) dfile << pData[i]; dfile << endl;

		width = src_wid;
		height = src_hgt;
	//	width_bytes = (((width + 31) / 32) * (32/8));	// bug
		width_bytes = (((width + 7) / 8) * (8/8));
		width = width_bytes * 8;
		if ( (xpos + width ) > 648  ) width  = 648  - xpos;
		if ( (ypos + height) > 1013 ) height = 1013 - ypos;
		fill_bits = width - src_wid;		

		pTemp = pDst2;// pImageData;
		dfile << "STEP 1" << endl;
		i = 0;
		//Some special meaning for device firmware
		pPrintData[i++] = 0x1B; 
		//Some special meaning for device firmware
		pPrintData[i++] = 'Z';	// 0x5A;
		pTemp = pDst2;// pImageData;
		//pTemp = pDst2;
		pTemp += src_line;	// last line
		for ( y = 0; y < height && y < src_hgt; y++ )
		{
			dfile << "f";
			z = 0;
			zh = 0;	// clear
			if ( width_bytes <= src_line )
			{
				x = width_bytes - 1;
			}
			else
			{
				x = width_bytes - 1;
				for ( ; x > src_line; x-- )
				{
					dfile << zh;
					pData[z++] = zh;
				}
			}
			for (  ; x >= 0; x-- )
			{
				ch = ~pTemp[x];
				zh = 0;
				for ( k = 0; k < 8; k++ )
				{
					if ( ch & bit_index[k] ) zh |= rbit_index[k];
				}
				dfile << zh;
				pData[z++] = zh;
			}
			i = Comp2MMonoRegin((LPBYTE)pPrintData, i, (LPBYTE)pData, width_bytes);

			pTemp += src_line;	// next line
		}
		//this is the data which most important to us, this will be send to printer to print
		pPrintData[i++] = 0x0D;
		*dataSize = i;	

		GlobalFree(pFileData);
		GlobalFree(pPrintData);
		dfile.close();
	}
	CloseHandle(hFile);

	return bRet;
}


int Comp2MMonoRegin( LPBYTE pOutput, int pos, LPBYTE pInput, int nDataSize)
{
	int i, r, j, k;

	i = 0;
	r = 0;
	while ( i < nDataSize )
	{		
        j = i + 1;
		k = 2;
		if ( i == (nDataSize - 1) )    /* Last byte alone. */
		{
			
			if ((pInput[i] == 0x5B) || (pInput[i] ==  0x0D ) || (pInput[i] == 0x1B) )
			{
				pOutput[pos++] = (BYTE)0x01;
				pOutput[pos++] = (BYTE)0x5B;
				pOutput[pos++] = (BYTE)pInput[i];
			}
			else
			{
				pOutput[pos++] = (BYTE)0x01;
				pOutput[pos++] = (BYTE)pInput[i];
			}
			i++;
		}
		else if(pInput[i] == pInput[j])    // Run. 
		{
			while((j < nDataSize-1) && (k < (WORD)TP9_COMP_LENGTH) && (pInput[j] == pInput[j+1]) ) 
			{
				j++;
				k++;
			}
			if ((pInput[i] == 0x5B) || (pInput[i] ==  0x0d ) || (pInput[i] == 0x1B) )
			{
				pOutput[pos++] = (BYTE)((BYTE)k | (BYTE)0x80);
				pOutput[pos++] = (BYTE)0x5B;
				pOutput[pos++] = (BYTE)pInput[i];
			}
			else
			{
				pOutput[pos++] = (BYTE)((BYTE)k | (BYTE)0x80);
				pOutput[pos++] = (BYTE)pInput[i];
			}
			i = j+1;
		}
		else
		{
			while((j < nDataSize-1) && (k < (WORD)TP9_COMP_LENGTH) && (pInput[j] != pInput[j+1]) ) 
			{
				j++;
				k++;
			}
			pOutput[pos++] = (BYTE)(k-1&0x7F);
			for(r=0; r < k-1; r++)
			{
				if ((pInput[i+r] == 0x5B) || (pInput[i+r] ==  0x0d ) || (pInput[i+r] == 0x1B) )
				{					
					pOutput[pos++] = (BYTE)0x5B;
					pOutput[pos++] = (BYTE)pInput[i+r];
				}
				else
				{
					
					pOutput[pos++] = (BYTE)pInput[i+r];
				}
			}
			i = j;
		}
	}
	return pos;
}


this is my java class
Java
package com.kkpl.Printer;

import java.awt.Graphics2D;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

public class PictureUtil {

	private enum Rotation {
		CLOCK_WISE_90_DEGREE, COUNTER_CLOCK_WISE_90_DEGREE, NONE,
	}

	private Rotation rotation = Rotation.CLOCK_WISE_90_DEGREE;

	public byte[] getSendingImageDataCommand(BufferedImage image) {

		int xPOs = 0, yPos = 0, width = image.getWidth(), height = image.getHeight();
		rotate(image);
		convertTo1Bit(image);
		byte[] compressedImage = monoCompress(getBytes(image));
		return compressedImage;
	}

	private void convertTo1Bit(BufferedImage img) {
		ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
		op.filter(img, img);
	}

	private BufferedImage rotate(BufferedImage img) {

		int w = img.getWidth();
		int h = img.getHeight();

		if (w < h) {
			BufferedImage root = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
			double theta = 0.00d;
			switch (rotation) {
			case CLOCK_WISE_90_DEGREE:
				theta = Math.PI / 2;
				break;
			case COUNTER_CLOCK_WISE_90_DEGREE:
				theta = -Math.PI / 2;
			default:
				break;
			}

			AffineTransform transform = AffineTransform.getQuadrantRotateInstance((int) theta, w / 2, h / 2);

			transform.translate(0.5 * h, 0.5 * w);
			transform.rotate(theta);
			transform.translate(-0.5 * w, -0.5 * h);

			Graphics2D g = (Graphics2D) root.createGraphics();
			g.drawImage(img, transform, null);
			g.dispose();
			return root;
		}
		return img;
	}

	private byte[] getBytes(BufferedImage image) {
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ImageIO.write(image, "bmp", baos);
			baos.flush();
			byte[] tmp = baos.toByteArray();
			baos.close();
			
			return tmp;// imageArray;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public byte[] monoCompress(byte[] img) {

		byte first, second;
		first = img[0];
		second = img[1];

		List<Byte> result = new ArrayList<Byte>();
		result.add((byte) 0x1B);
		result.add((byte) 0x5A); // 'Z'

		for (int i = 0; i < img.length - 1;) {
			byte ctr = 1;
			if (first == second) {
				// count repeats
				int top = img.length > i + 15 + 1 ? i + 15 + 1 : img.length;
				for (int j = i + 1; j < top; j++) {
					if (img[j] == first)
						ctr++;
					else
						break;
				}
				result.add((byte) (0x80 | ctr));
				result.add(first);

			} else {
				// count not repeats
				int top = img.length > i + 15 + 1 ? i + 15 + 1 : img.length;
				for (int j = i; j < top - 1; j++) {

					if (img[j] != img[j + 1])
						ctr++;
					else
						break;
				}
				result.add((byte) (0x00 | ctr));
				// copy not repeated bytes to result
				for (int j = i; j < i + ctr; j++) {
					result.add(img[j]);
				}
			}
			i += ctr;
			if (i < img.length - 1) {
				first = img[i];
				second = img[i + 1];
			}
		}
		result.add((byte) 0x1D);
		byte[] temp = new byte[result.size()];
		int ctr = 0;
		for (byte b : result) {
			temp[ctr++] = b;
		}
		return temp;
	}
}
Posted
Updated 17-Oct-12 10:47am
v2
Comments
[no name] 17-Oct-12 8:44am    
I believe that you meant to post this at www.vworker.com so you could hire someone to do this work for you.
Areff 17-Oct-12 8:59am    
i will be glad to do , but my problem is that i am in Iran and we have not access to international banking system to pay to do this job
[no name] 17-Oct-12 9:38am    
So you expect someone to do all this work for you for free? Do not expect it to happen.
Areff 18-Oct-12 3:14am    
no, but i hope to someone could give a concise explain about the whole algorithm of this C++ function.
Stefan_Lang 25-Oct-12 9:46am    
On a sidenote, this isn't C++, it isn't even ANSI C. It is merely some old Windows C code that could have been written and used 20 years ago.

(well ok, it is C/C++ in the sense that current compilers (on windows) will accept it. My point is that the code doesn't use any feature of C++. nor newer features of ANSI C, such as the bool type)

1 solution

You can plug the C++ functions into your Java class as methods. The two languages share much of the syntax and semantics.

The Java compiler will tell you where you should adapt the code.

When all compiles, if you don't get the same behavior, you can step-by-step the two versions in parallel and spot the places where processing diverges.

The original code indeed looks like run-length coding, but it supports special characters ([, CR, ESC - possibly escape sequences) that must be interpreted appropriately. I don't recognize this in your own code.
 
Share this answer
 
v2
Comments
Areff 25-Oct-12 14:05pm    
first of all, tank you for paying attention to this problem and then, what do you mean plug the c++ function into java class ?
YvesDaoust 25-Oct-12 14:16pm    
You are welcome.

Just copy/paste the code and do the required adaptations to turn it to valid Java.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900