I can't print my bit image without white line each 24 lines. I need to print an image, but this image have white lines each 24 lines to bits.
The epson printer print the image to the next format.
>line 23 01010101000010001010
>line 24 00001000100000000110
>line 25 --------- white line ------------
How can delete this damn white line?
Image size
width:400px
height:73px
while (offset < height)
{
//format ESC* Epson printer
String modIMG = new String(new byte[]{0x1B, 0x2A, 33, 0, 2});
img.append(modIMG);
for (int x = 0; x < width; ++x) {
for (int k = 0; k < 3; ++k) {
byte slice= 0;
for (int b = 0; b < 8; ++b) {
int y = (((offset / 8) + k) * 8) + b;
int i = (y * width) + x;
boolean v = false;
if (i < bitSet.length()) {
v = bitSet.get(i);}
slice |= (byte) ((v ? 1 : 0) << (7 - b));
}
img.slice(new String(new byte[] {slice}));
}
}
offset += 24;
img.append(new String(new String(new byte[]{0x1B,0x33,30}));
}
So I solved this problem. It is not enough to set the line spacing to 24 dots using ESC '3' 24, but you have to print the image in page mode.
To enter page mode: ESC 'L'
Then you have to set the image area using ESC 'W', here I do it in C:
h2 = h * 2 + 30;
/* Set the printing area, h * 2 because of double density */
seq[0] = 0x1b;
seq[1] = 'W';
seq[2] = 0; /* xl */
seq[3] = 0; /* xh */
seq[4] = 0; /* yl */
seq[5] = 0; /* yh */
seq[6] = 0; /* dxl */
seq[7] = 2; /* dxh */
seq[8] = h2 % 256; /* dyl */
seq[9] = h2 / 256; /* dyh */
if (write(fd, seq, 10) != 10)
goto finish;
Now send the image data and finally print with sending 0x0c, this also returns the printer to standard mode.
By using page mode, the white stripes on the image went away.
BTW, this seems to be an oddity of EPSON TM-T88 printers, I neither see these white lines on the TM-T500A nor on e.g. Aures printers. On these printers I can use standard mode to print images.
I solved it setting page mode followin Marc Balmer's example, but have to send feed for 24*2 dots (line height double density) to get it working: So after every slice of data send command ESC J n bytes {27, 74, 48}. And finally got it!
Hope it helps!
Reference (must be logged)
Try sending ESC/POS command (0x1B, '3', 24) prior to printing. This sets the line spacing to 24 dots rather than the default of 30.
Just to confirm what other people have suggested, I've successfully managed to remove the white lines between the data stripes using "ESC30".
You can see the actual code (Haskell) and the results here.
Related
I have read two posts about extracting samples from AudioInputStream and converting them in to dB.
https://stackoverflow.com/a/26576548/8428414
https://stackoverflow.com/a/26824664/8428414
As far as I understand byte[] bytes; has structure like this:
Index 0: Sample 0 (Left Channel)
Index 1: Sample 0 (Right Channel)
Index 2: Sample 1 (Left Channel)
Index 3: Sample 1 (Right Channel)
Index 4: Sample 2 (Left Channel)
Index 5: Sample 2 (Right Channel)
In the first article it shows how to get samples from one channel (mono).
So, my problem is that I want to get samples separately for the right channel and separately for the left channel in order to calculate dB for right and left channels.
Here is the code. How it can be changed to get right and left channels separately?
I can't understand how the index i changes...
final byte[] buffer = new byte[2048];
float[] samples = new float[buffer.length / 2];
for (int n = 0; n != -1; n = in.read(buffer, 0, buffer.length)) {
line.write(buffer, 0, n);
for (int i = 0, sampleIndex = 0; i < n; ) {
int sample = 0;
sample |= buffer[i++] & 0xFF; // (reverse these two lines
sample |= buffer[i++] << 8; // if the format is big endian)
// normalize to range of +/-1.0f
samples[sampleIndex++] = sample / 32768f;
}
float rms = 0f;
for (float sample : samples) {
rms += sample * sample;
}
rms = (float) Math.sqrt(rms / samples.length);
Hope you could help me. Thank you in advance.
The format the stereo signal is saved in is called interleaved. I.e., as you described correctly, it's LLRRLLRRLLRR.... SO you first need to read a left sample, then a right sample, and so on.
I have edited your code to reflect this. However, there is some room for improvement via refactoring.
Note: The code changes only deal with interleaving. I have not checked the rest of your code.
final byte[] buffer = new byte[2048];
// create two buffers. One for the left, one for the right channel.
float[] leftSamples = new float[buffer.length / 4];
float[] rightSamples = new float[buffer.length / 4];
for (int n = 0; n != -1; n = in.read(buffer, 0, buffer.length)) {
line.write(buffer, 0, n);
for (int i = 0, sampleIndex = 0; i < n; ) {
int sample = 0;
leftSample |= buffer[i++] & 0xFF; // (reverse these two lines
leftSample |= buffer[i++] << 8; // if the format is big endian)
rightSample |= buffer[i++] & 0xFF; // (reverse these two lines
rightSample |= buffer[i++] << 8; // if the format is big endian)
// normalize to range of +/-1.0f
leftSamples[sampleIndex] = leftSample / 32768f;
rightSamples[sampleIndex] = rightSample / 32768f;
sampleIndex++;
}
// now compute RMS for left
float leftRMS = 0f;
for (float sample : leftSamples) {
leftRMS += sample * sample;
}
leftRMS = (float) Math.sqrt(leftRMS / leftSamples.length);
// ...and right
float rightRMS = 0f;
for (float sample : rightSamples) {
rightRMS += sample * sample;
}
rightRMS = (float) Math.sqrt(rightRMS / rightSamples.length);
}
Here's what I'm working with right now:
for (int i = 0, numSamples = soundBytes.length / 2; i < numSamples; i += 2)
{
// Get the samples.
int sample1 = ((soundBytes[i] & 0xFF) << 8) | (soundBytes[i + 1] & 0xFF); // Automatically converts to unsigned int 0...65535
int sample2 = ((outputBytes[i] & 0xFF) << 8) | (outputBytes[i + 1] & 0xFF); // Automatically converts to unsigned int 0...65535
// Normalize for simplicity.
float normalizedSample1 = sample1 / 65535.0f;
float normalizedSample2 = sample2 / 65535.0f;
float normalizedMixedSample = 0.0f;
// Apply the algorithm.
if (normalizedSample1 < 0.5f && normalizedSample2 < 0.5f)
normalizedMixedSample = 2.0f * normalizedSample1 * normalizedSample2;
else
normalizedMixedSample = 2.0f * (normalizedSample1 + normalizedSample2) - (2.0f * normalizedSample1 * normalizedSample2) - 1.0f;
int mixedSample = (int)(normalizedMixedSample * 65535);
// Replace the sample in soundBytes array with this mixed sample.
soundBytes[i] = (byte)((mixedSample >> 8) & 0xFF);
soundBytes[i + 1] = (byte)(mixedSample & 0xFF);
}
From as far as I can tell, it's an accurate representation of the algorithm defined on this page: http://www.vttoth.com/CMS/index.php/technical-notes/68
However, just mixing a sound with silence (all 0's) results in a sound that very obviously doesn't sound right, maybe it's best to describe it as higher-pitched and louder.
Would appreciate help in determining if I'm implementing the algorithm correctly, or if I simply need to go about it a different way (different algorithm/method)?
In the linked article the author assumes A and B to represent entire streams of audio. More specifically X means the maximum abs value of all of the samples in stream X - where X is either A or B. So what his algorithm does is scans the entirety of both streams to compute the max abs sample of each and then scales things so that the output theoretically peaks at 1.0. You'll need to make multiple passes over the data in order to implement this algorithm and if your data is streaming in then it simply will not work.
Here is an example of how I think the algorithm to work. It assumes that the samples have already been converted to floating point to side step the issue of your conversion code being wrong. I'll explain what is wrong with it later:
double[] samplesA = ConvertToDoubles(samples1);
double[] samplesB = ConvertToDoubles(samples2);
double A = ComputeMax(samplesA);
double B = ComputeMax(samplesB);
// Z always equals 1 which is an un-useful bit of information.
double Z = A+B-A*B;
// really need to find a value x such that xA+xB=1, which I think is:
double x = 1 / (Math.sqrt(A) * Math.sqrt(B));
// Now mix and scale the samples
double[] samples = MixAndScale(samplesA, samplesB, x);
Mixing and scaling:
double[] MixAndScale(double[] samplesA, double[] samplesB, double scalingFactor)
{
double[] result = new double[samplesA.length];
for (int i = 0; i < samplesA.length; i++)
result[i] = scalingFactor * (samplesA[i] + samplesB[i]);
}
Computing the max peak:
double ComputeMaxPeak(double[] samples)
{
double max = 0;
for (int i = 0; i < samples.length; i++)
{
double x = Math.abs(samples[i]);
if (x > max)
max = x;
}
return max;
}
And conversion. Notice how I'm using short so that the sign bit is properly maintained:
double[] ConvertToDouble(byte[] bytes)
{
double[] samples = new double[bytes.length/2];
for (int i = 0; i < samples.length; i++)
{
short tmp = ((short)bytes[i*2])<<8 + ((short)(bytes[i*2+1]);
samples[i] = tmp / 32767.0;
}
return samples;
}
I got a WAV (32 bit sample size, 8 byte per frame, 44100 Hz, PCM_Float), which in need to create a sample array of. This is the code I have used for a Wav with 16 bit sample size, 4 byte per frame, 44100 Hz, PCM_Signed.
private float[] getSampleArray(byte[] eightBitByteArray) {
int newArrayLength = eightBitByteArray.length
/ (2 * calculateNumberOfChannels()) + 1;
float[] toReturn = new float[newArrayLength];
int index = 0;
for (int t = 0; t + 4 < eightBitByteArray.length; t += 2) // t+2 -> skip
//2nd channel
{
int low=((int) eightBitByteArray[t++]) & 0x00ff;
int high=((int) eightBitByteArray[t++]) << 8;
double value = Math.pow(low+high, 2);
double dB = 0;
if (value != 0) {
dB = 20.0 * Math.log10(value); // calculate decibel
}
toReturn[index] = getFloatValue(dB); //minorly important conversion
//to normalized values
index++;
}
return toReturn;
}
Obviously this code cant work for the 32bits sample size Wav, as I have to consider 2 more bytes in the first channel.
Does anybody know how the 2 other bytes have to be added (and shiftet) to calculate the amplitude? Unfortunately google didnt help me at all :/.
Thanks in advance.
Something like this should do the trick.
for (int t = 0; t + 4 < eightBitByteArray.length; t += 4) // t+4 -> skip
//2nd channel
{
float value = ByteBuffer.wrap(eightBitByteArray, t, 4).order(ByteOrder.LITTLE_ENDIAN).getFloat();
double dB = 0;
if (value != 0) {
dB = 20.0 * Math.log10(value); // calculate decibel
}
toReturn[index] = getFloatValue(dB); //minorly important conversion
//to normalized values
index++;
}
On another note - converting instantaneous samples to dB is nonsensical.
I've got this loop that is run thousands of times (so needs to be efficient). It changes the value of the bitmap pixel.
I want to be able to run thought the loop and "switch" a certain group of pixels to alpha and then switch them back at a later point.
My question is.
How do I switch the values? So say 0xFFCC1BE0 becomes 0x00CC1BE0 and then if I want to switch back to 0xFFCC1BE0 I simply take the 00 and turn it too FF.
I can't make two bitmaps as I run out of memory :-(
Anyhow here's what I've got so far:
private void setTransparencyOnLightMap(float WidthPercentage, float LeftPosition)
{
int blankPixel = 0x00000000;
int savedPixel = 0x00000000;
int desiredAlpha = 200; //Can also be 0x00
//Find away of turning alhpa off and on.
for(int BMx = 0; BMx < mLightMap.getWidth(); BMx++)
{
for(int BMy = 0; BMy < mLightMap.getHeight(); BMy++)
{
if(mLightMap.getPixel(BMx, BMy) != blankPixel) //Make sure don't overwrite blank transparent pixels.
{
savedPixel = mLightMap.getPixel(BMx,BMy);
savedPixel = savedPixel | (desiredAlpha << 24);
mLightMap.setPixel(BMx, BMy, savedPixel);
}
}
}
}
You could switch the alpha of a pixel like so:
savedPixel = savedPixel & 0x00FFFFFF;
savedPixel = savedPixel | (desiredAlpha << 24);
The first line zeros out the 8 most significant bits of savedPixel (these are the bits where the alpha is held). The second line sets the 8 most significant bits of savedPixel to desiredAlpha. Note that desiredAlpha must be between 0 and 255 (These are the ints that can be stored in 8 bits).
Note that this uses bitwise operators, (&, |, <<) which are very efficient.
It seems to me, to reduce memory use, you can just save the original Alpha value of each pixel rather than the whole ARGB value - to do this use a byte array which will be 1/4 the size of the original bitmap. Also use a bit-mask for the new Alpha so you can use bitwise AND (&) as described by Tristan Hull...
byte[] savedAlphaArray = new byte[mLightMap.getWidth(), mLightMap.getHeight()];
int desiredAlphaMask = 0x00FFFFFF;
int pixel;
Then to save the Alpha values and apply the bit-mask do the following...
for (int i = 0; i < mLightMap.getWidth(); i++) {
for (int j = 0; j < mLightMap.getHeight(); j++) {
pixel = mLightMap.getPixel(i, j);
savedAlphaArray[i, j] = (pixel & 0xFF000000) >> 24;
mLightMap.setPixel(i, j, desiredAlphaMask & pixel);
}
}
To 'switch' back do the following...
for (int i = 0; i < mLightMap.getWidth(); i++) {
for (int j = 0; j < mLightMap.getHeight(); j++) {
pixel = mLightMap.getPixel(i, j);
mLightMap.setPixel(i, j, savedAlphaArray[i, j] << 24 & pixel);
}
}
I am trying to get the RGB value of any given pixel on an image into 12 bit binary, with each channel represented by 4 bits. For example, if a pixel has it's red channel at '255', or in binary "11111111". I wish to convert that to "1111".
I have got a code working, but it is rather slow, and I am wondering if there is a better way to do this.
Here's what i did.
I use the method getRGB(x, y) to get the RGB value of one pixel.
e.g. -4278864
I convert that into 3 separate channels e.g. r 190 g 181 b 176
I divide that by 16 to get integer equivalent of 4 bit
representation
I convert the number to a binary.
Add 0's in front of the binary if the binary generated is less
than 4 bit.
Concatenate to a 12bit binary to represent 12bit color output. e.g. 101110111011
Here are my code:
import java.awt.Component;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class LoadImageApp extends Component {
private static int[] rgbArray;
private static double bitPerColor = 4.0;
public static void main(String[] args) {
BufferedImage img = null;
String fileName = "Image.jpg";
try {
//Read in new image file
img = ImageIO.read(new File("src/"+fileName));
}
catch (IOException e){
}
if (img == null) {
System.out.println("No image loaded");
}
else {
//Get RGB Value
int val = img.getRGB(500, 500);
System.out.println("rgbValue from getRGB is: " + val);
//Convert to three separate channels
int a = (0xff000000 & val) >>> 24;
int r = (0x00ff0000 & val) >> 16;
int g = (0x0000ff00 & val) >> 8;
int b = (0x000000ff & val);
System.out.println("rgbValue in RGB is: ");
System.out.println("a " + a + " r " + r + " g " + g + " b " + b);
double power = Math.pow(2.0, bitPerColor);
//Convert each channel to binary
String r4bit = Integer.toBinaryString((int)(r/(power)));
String g4bit = Integer.toBinaryString((int)(g/(power)));
String b4bit = Integer.toBinaryString((int)(b/(power)));
//Convert concatonate 0's in front to get desired bit count
int rDifference = (int)bitPerColor - r4bit.length();
int gDifference = (int)bitPerColor - g4bit.length();
int bDifference = (int)bitPerColor - b4bit.length();
for (int i = rDifference; i > 0; i--){
r4bit="0"+r4bit;}
for (int i = gDifference; i > 0; i--){
g4bit = "0"+g4bit;}
for (int i = bDifference; i > 0; i--){
b4bit = "0"+b4bit;}
//Concatonate three channel together to form one binary
String rgbValue = r4bit + g4bit + b4bit;
System.out.println("rgbValue in binary is: " + rgbValue);
}
}
}
It all works fine as as desired. However it's just really, really ugly, and slow, 2-3 seconds just to read one pixel. I was hoping to use the code to read a section of an image at a time, but i can imaging it taking AGES.
So any help would be very much appreciated.
Thanks in advance.
Your original code (in hex) is 0x00rrggbb. You want to convert this to 0x00000rgb. This will do it:
int rgb24 = ....;
int rgb12 = (rgb24 & 0x00f00000) >> 12 +
(rgb24 & 0x0000f000) >> 8 +
(rgb24 & 0x000000f0) >> 4;
If you wanted to "round" to the nearest color instead of truncating you could do this:
int r = (rgb24 & 0x00ff0000);
int g = (rgb24 & 0x0000ff00);
int b = (rgb24 & 0x000000ff);
r += (r >= 0x00f00000) ? 0x00080000 : 0;
g += (g >= 0x0000f000) ? 0x00000800 : 0;
b += (b >= 0x000000f0) ? 0x00000008 : 0;
int rgb12 = (r & 0x00f00000) >> 12 + (g & 0x0000f000) >> 8 + (b & 0x000000f0) >> 4;
This rounds up but only if the high-order 4 bits are not already 1111 (when you would risk overflow).
There are a few things that might be slowing it down, such as...
Getting each pixel individually from the BufferedImage
Using Math.pow() and possibly Integer.toBinaryString(), multiple times in the loop
Using Strings all the way through, rather than numbers like int or short. If you want a String, maybe do a single conversion from short --> String at the end.
I would probably try to do something like this...
// Get all the pixels
int pixelCount = imageWidth*imageHeight;
int[] pixelArray = new int[pixelCount];
img.getRGB(0,0,imageWidth,imageHeight,pixelArray,0,1);
// For storing the 4-bit data
short[] convertedArray = new short[pixelCount];
// calculate the conversion factor a single time
double power = Math.pow(2.0, bitPerColor);
// Loop over the pixels
for (int p=0;p<pixelCount;p++){
int pixel = pixelArray[p];
// Convert into separate channels
int a = (0xff000000 & val) >>> 24;
int r = (0x00ff0000 & val) >> 16;
int g = (0x0000ff00 & val) >> 8;
int b = (0x000000ff & val);
// Convert to 4-bit
a /= power;
r /= power;
g /= power;
b /= power;
// Create the short for the pixel (4 channels * 4 bits = a 2-byte short)
short newPixel = (a & 0x0000000f) << 24 | (r & 0x0000000f) << 16 | (g & 0x0000000f) << 8 | (b & 0x0000000f);
convertedArray[p] = newPixel;
// If you want to have the value as a String, do it here.
String binary = Short.toBinaryString(newPixel);
}
Offhand, I noticed you used the String plus operator for appending. I know it's simple code but that takes some work when it is in a loop. The operator calls a constructor to execute its function.
How big is the loop anyway?
Instead of using the plus operator, perhaps use other classes like StringBuilder or a Java equivalent of it. Tell me which class you end up using.
Investigate by timing your code!
When you want to see your possible bottlenecks, look at LOOPS in a heap or stack first since there are potentially many code executions. This should be a coding rule somewhere...
Try it out & have fun. Pls vote for my answer. I need a badge and more points :-)
Tommy Kwee
The value I have collected in the RGB when set using SetRGB will it provide me an image of binary for where the area where the image is present is white and the area whre the image is absent is black ?