How to render colours properly in Java Graphics - java

I was using this code placed here to generate bar-charts for my datasets. However, the colours were all the same (red in the code), so I decided to generate a colour ramp for this. I wrote the following code:
Color[] getColorRamp(int numColours)
{
Color[] colours = new Color[numColours];
int red_1 = 255;
int green_1 = 0;
int blue_1 = 0;
int red_2 = 0;
int green_2 = 0;
int blue_2 = 255;
int count = 0;
for (float t=0.0f;t<1.0f;t+=1.0/(float)numColours) {
colours[count] = new Color((int)(t*red_2 + (1-t)*red_1),
(int)(t*green_2 + (1-t)*green_1),
(int)(t*blue_2 + (1-t)*blue_1),34);
//System.out.print((int)(t*red_2 + (1-t)*red_1) +",");
//System.out.print((int)(t*green_2 + (1-t)*green_1) +",");
//System.out.println((int)(t*blue_2 + (1-t)*blue_1));
}
return colours;
}
It is here, where the problem starts. Only the first colour (pretty light blue) get rendered properly. Other colours are rendered as black! You can see that I have put System.out.println to verify the colours generated (commented in the code posted here). I saw that colours were generated as perfect RGB combinations.
The modified barchart function is posted here:
void drawBarChart(Graphics g, double[] values, String[] names, String title)
{
if (values == null || values.length == 0)
return;
double minValue = 0;
double maxValue = 0;
for (int i = 0; i < values.length; i++) {
if (minValue > values[i])
minValue = values[i];
if (maxValue < values[i])
maxValue = values[i];
}
//Graphics2D g = (Graphics2D)gg;
Dimension d = getSize();
int clientWidth = d.width;
int clientHeight = d.height;
int barWidth = clientWidth / values.length;
Font titleFont = new Font("SansSerif", Font.BOLD, 20);
FontMetrics titleFontMetrics = g.getFontMetrics(titleFont);
Font labelFont = new Font("SansSerif", Font.PLAIN, 10);
FontMetrics labelFontMetrics = g.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(title);
int y = titleFontMetrics.getAscent();
int x = (clientWidth - titleWidth) / 2;
g.setFont(titleFont);
g.drawString(title, x, y);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if (maxValue == minValue)
return;
double scale = (clientHeight - top - bottom) / (maxValue - minValue);
y = clientHeight - labelFontMetrics.getDescent();
g.setFont(labelFont);
Color[] colours = getColorRamp(values.length);
for (int i = 0; i < values.length; i++) {
int valueX = i * barWidth + 1;
int valueY = top;
int height = (int) (values[i] * scale);
if (values[i] >= 0)
valueY += (int) ((maxValue - values[i]) * scale);
else {
valueY += (int) (maxValue * scale);
height = -height;
}
g.setColor(colours[i]);
g.fillRect(valueX, valueY, barWidth - 2, height);
g.setColor(Color.black);
g.drawRect(valueX, valueY, barWidth - 2, height);
int labelWidth = labelFontMetrics.stringWidth(names[i]);
x = i * barWidth + (barWidth - labelWidth) / 2;
g.drawString(names[i], x, y);
}
//paintComponent(g);
}
I wish to know, what mistake I am making!

You're probably going to hit yourself on the head now. The reason it fails is that you forget to increase the variable count after setting the first colour, so you're constantly overwriting the first element of the Color array, and leaving all the other values in the array as their initial default (null).
Fixed code:
for (float t=0.0f;t<1.0f;t+=1.0/(float)numColours) {
colours[count++] = new Color((int)(t*red_2 + (1-t)*red_1),
(int)(t*green_2 + (1-t)*green_1),
(int)(t*blue_2 + (1-t)*blue_1),34);
}
(Notice the colours[count++])

Related

scrambled block trying to decompress BC1 texture compression

I've been trying to implement a BC1 (DXT1) decompression algorithm in Java. Everything seems to work pretty precise but I've ran into problem with some blocks around transparent ones. I've been trying to resolve it for a few hours without success.
In short, after decompressing all blocks everything looks good except for the blocks whose are around transparent ones. During the development I've been checking results with results from DirectXTex (texconv) which is written in C++.
This is my result compared to DirectXTex one:
Here is the code I'm using:
BufferedImage decompress(byte[] buffer, int width, int height)
and implementation:
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
int[] scanline = new int[4 * width]; //stores 4 horizontal lines (width/4 blocks)
RGBA[] blockPalette = new RGBA[4]; //stores RGBA values of current block
int bufferOffset = 0;
for (int row = 0; row < height / 4; row++) {
for (int col = 0; col < width / 4; col++) {
short rgb0 = Short.reverseBytes(Bytes.getShort(buffer, bufferOffset));
short rgb1 = Short.reverseBytes(Bytes.getShort(buffer, bufferOffset + 2));
int bitmap = Integer.reverseBytes(Bytes.getInt(buffer, bufferOffset + 4));
bufferOffset += 8;
blockPalette[0] = R5G6B5.decode(rgb0);
blockPalette[1] = R5G6B5.decode(rgb1);
if(rgb0 <= rgb1) {
int c2r = (blockPalette[0].getRed() + blockPalette[1].getRed()) / 2;
int c2g = (blockPalette[0].getGreen() + blockPalette[1].getGreen()) / 2;
int c2b = (blockPalette[0].getBlue() + blockPalette[1].getBlue()) / 2;
blockPalette[2] = new RGBA(c2r, c2g, c2b, 255);
blockPalette[3] = new RGBA(0, 0, 0, 0);
} else {
int c2r = (2 * blockPalette[0].getRed() + blockPalette[1].getRed()) / 3;
int c2g = (2 * blockPalette[0].getGreen() + blockPalette[1].getGreen()) / 3;
int c2b = (2 * blockPalette[0].getBlue() + blockPalette[1].getBlue()) / 3;
int c3r = (blockPalette[0].getRed() + 2 * blockPalette[1].getRed()) / 3;
int c3g = (blockPalette[0].getGreen() + 2 * blockPalette[1].getGreen()) / 3;
int c3b = (blockPalette[0].getBlue() + 2 * blockPalette[1].getBlue()) / 3;
blockPalette[2] = new RGBA(c2r, c2g, c2b, 255);
blockPalette[3] = new RGBA(c3r, c3g, c3b, 255);
}
for (int i = 0; i < 16; i++, bitmap >>= 2) {
int pi = (i / 4) * width + (col * 4 + i % 4);
int index = bitmap & 3;
scanline[pi] = A8R8G8B8.encode(blockPalette[index]);
}
}
//copy scanline to buffered image
result.setRGB(0, row * 4, width, 4, scanline, 0, width);
}
return result;
Does anyone have idea where is the problem? I've been doing exactly the same steps as specification says: Block Compression (Direct3D 10)
Is it that blockPalette[2].set(c2r, c2g, c2b); should be blockPalette[2].set(c2r, c2g, c2b, 255);? (in two locations)
For those who are interested, I've found that the problem was in comparing short values.
I've just changed:
if(rgb0 <= rgb1) {
to either
if(Short.compareUnsigned(rgb0, rgb1) <= 0) {
or
if((rgb0 & 0xffff) <= (rgb1 & 0xffff)) {
and this ensures that color values are compared as unsigned shorts (positive integers).

Custom java BarChart Scaling issues

i have been trying to make a custom BarChart in Java for a school project but for some reason it has some weird Scaling issues. Here is the Code.
static class BarChart extends JPanel
{
private int[] chartValues;
private String[] chartLabels;
private String chartTitle;
public BarChart(String title,int[] values,String[]labels)
{
this.chartTitle = title;
this.chartValues = values;
this.chartLabels = labels;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Random r = new Random();
if(this.chartValues == null || this.chartValues.length==0)
{
return;
}
Dimension chartDimension = this.getSize();
int panelWidth = chartDimension.width;
int panelHeight = chartDimension.height;
int barWidth = panelWidth / this.chartValues.length;
int maxValue = this.chartValues[0];
int minValue = this.chartValues[0];
for(int tempValue:this.chartValues)
{
maxValue = Math.max(maxValue, tempValue);
minValue = Math.min(minValue, tempValue);
}
Font titleFont = new Font("Book Antiqua", Font.BOLD, 15);
FontMetrics titleFontMetrics = g.getFontMetrics(titleFont);
Font labelFont = new Font("Book Antiqua", Font.PLAIN, 14);
FontMetrics labelFontMetrics = g.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(this.chartTitle);
int stringHeight = titleFontMetrics.getAscent();
int stringWidth = (panelWidth - titleWidth) / 2;
g.setFont(titleFont);
g.drawString(this.chartTitle, stringWidth, stringHeight);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if(maxValue==minValue)
{
return;
}
double barScale = (panelHeight - top - bottom)/(maxValue - minValue);
stringHeight = panelHeight - labelFontMetrics.getDescent();
int xPos = 5;
g.setFont(labelFont);
for(int i=0; i<this.chartValues.length;i++)
{
int tempValue = this.chartValues[i];
int barHeight = (int) ( (double)tempValue * barScale);
int yPos = top;
if(tempValue>=0)
{
yPos += (int) ((maxValue - tempValue)* barScale);
}
else
{
yPos += (int) (maxValue * barScale);
barHeight = - barHeight;
}
g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
g.fillRect(xPos, yPos, barWidth, barHeight);
g.setColor(Color.BLUE);
g.drawRect(xPos, yPos, barWidth, barHeight);
xPos += barWidth;
}
g.setColor(Color.BLACK);
g.drawString("Xronos", stringWidth, stringHeight);
}
}
But when i run this with my main with values {1,5,4,7,120} i get this depending on the screen resolution.
Wrong image (the height between bars and label is too much).
Correct height between bars and label. I really apreciate any help. And sorry if this stupid is a question.
you are doing integer division here:
double barScale = (panelHeight - top - bottom)/(maxValue - minValue);
try
double barScale = (panelHeight - top - bottom)/(double)(maxValue - minValue);
instead

Java: implementation of Gaussian Blur

I need to implement Gaussian Blur in Java for 3x3, 5x5 and 7x7 matrix. Can you correct me if I'm wrong:
I've a matrix(M) 3x3 (middle value is M(0, 0)):
1 2 1
2 4 2
1 2 1
I take one pixel(P) from image and for each nearest pixel:
s = M(-1, -1) * P(-1, -1) + M(-1, 0) * P(-1, 0) + ... + M(1, 1) * P(1, 1)
An then division it total value of matrix:
P'(i, j) = s / M(-1, -1) + M(-1, 0) + ... + M(1, 1)
That's all that my program do. I leave extreme pixels not changed.
My program:
for(int i = 1; i < height - 1; i++){
for(int j = 1; j < width - 1; j++){
int sum = 0, l = 0;
for(int m = -1; m <= 1; m++){
for(int n = -1; n <= 1; n++){
try{
System.out.print(l + " ");
sum += mask3[l++] * Byte.toUnsignedInt((byte) source[(i + m) * height + j + n]);
} catch(ArrayIndexOutOfBoundsException e){
int ii = (i + m) * height, jj = j + n;
System.out.println("Pixels[" + ii + "][" + jj + "] " + i + ", " + j);
System.exit(0);
}
}
System.out.println();
}
System.out.println();
output[i * width + j] = sum / maskSum[0];
}
}
I get source from a BufferedImage like this:
int[] source = image.getRGB(0, 0, width, height, null, 0, width);
So for this image:
Result is this:
Can you describe me, what is wrong with my program?
First of all, your formula for calculating the index in the source array is wrong. The image data is stored in the array one pixel row after the other. Therefore the index given x and y is calculated like this:
index = x + y * width
Furthermore the color channels are stored in different bits of the int cannot simply do the calculations with the whole int, since this allows channels to influence other channels.
The following solution should work (even though it just leaves the pixels at the bounds transparent):
public static BufferedImage blur(BufferedImage image, int[] filter, int filterWidth) {
if (filter.length % filterWidth != 0) {
throw new IllegalArgumentException("filter contains a incomplete row");
}
final int width = image.getWidth();
final int height = image.getHeight();
final int sum = IntStream.of(filter).sum();
int[] input = image.getRGB(0, 0, width, height, null, 0, width);
int[] output = new int[input.length];
final int pixelIndexOffset = width - filterWidth;
final int centerOffsetX = filterWidth / 2;
final int centerOffsetY = filter.length / filterWidth / 2;
// apply filter
for (int h = height - filter.length / filterWidth + 1, w = width - filterWidth + 1, y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int r = 0;
int g = 0;
int b = 0;
for (int filterIndex = 0, pixelIndex = y * width + x;
filterIndex < filter.length;
pixelIndex += pixelIndexOffset) {
for (int fx = 0; fx < filterWidth; fx++, pixelIndex++, filterIndex++) {
int col = input[pixelIndex];
int factor = filter[filterIndex];
// sum up color channels seperately
r += ((col >>> 16) & 0xFF) * factor;
g += ((col >>> 8) & 0xFF) * factor;
b += (col & 0xFF) * factor;
}
}
r /= sum;
g /= sum;
b /= sum;
// combine channels with full opacity
output[x + centerOffsetX + (y + centerOffsetY) * width] = (r << 16) | (g << 8) | b | 0xFF000000;
}
}
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
result.setRGB(0, 0, width, height, output, 0, width);
return result;
}
int[] filter = {1, 2, 1, 2, 4, 2, 1, 2, 1};
int filterWidth = 3;
BufferedImage blurred = blur(img, filter, filterWidth);

Drawing a simple 2D graph in java

I got a below java code which plots a 2D graph where x axis has values 1,2,3,......20
and y axis has values 21,14,18..........18
The code works perfectly but the only problem is that the graph does not shows the corresponding x and y values on x axis and y axis respectively. I know it could be a small addition to the code. but i am new to java graphics and i am not able to figure out where to add the relevant code considering the time constraint.
/*Sample code */
public class GraphingData extends JPanel {
int[] data = {
21, 14, 18, 03, 86, 88, 74, 87, 54, 77,
61, 55, 48, 60, 49, 36, 38, 27, 20, 18
};
final int PAD = 20;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
// Draw ordinate.
g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));
// Draw abcissa.
g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
// Draw labels.
Font font = g2.getFont();
FontRenderContext frc = g2.getFontRenderContext();
LineMetrics lm = font.getLineMetrics("0", frc);
float sh = lm.getAscent() + lm.getDescent();
// Ordinate label.
String s = "Average Byte Value";
float sy = PAD + ((h - 2*PAD) - s.length()*sh)/2 + lm.getAscent();
for(int i = 0; i < s.length(); i++) {
String letter = String.valueOf(s.charAt(i));
float sw = (float)font.getStringBounds(letter, frc).getWidth();
float sx = (PAD - sw)/2;
g2.drawString(letter, sx, sy);
sy += sh;
}
// Abcissa label.
s = "file blocks";
sy = h - PAD + (PAD - sh)/2 + lm.getAscent();
float sw = (float)font.getStringBounds(s, frc).getWidth();
float sx = (w - sw)/2;
g2.drawString(s, sx, sy);
// Draw lines.
double xInc = (double)(w - 2*PAD)/(data.length-1);
double scale = (double)(h - 2*PAD)/getMax();
g2.setPaint(Color.green.darker());
for(int i = 0; i < data.length-1; i++) {
double x1 = PAD + i*xInc;
double y1 = h - PAD - scale*data[i];
double x2 = PAD + (i+1)*xInc;
double y2 = h - PAD - scale*data[i+1];
g2.draw(new Line2D.Double(x1, y1, x2, y2));
}
// Mark data points.
g2.setPaint(Color.red);
for(int i = 0; i < data.length; i++) {
double x = PAD + i*xInc;
double y = h - PAD - scale*data[i];
g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
}
}
private int getMax() {
int max = -Integer.MAX_VALUE;
for(int i = 0; i < data.length; i++) {
if(data[i] > max)
max = data[i];
}
return max;
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new GraphingData());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
public void drawGrid(Graphics g)
{
g.setColor(Color.black);
int rows = model.maxy-model.miny+1;
int cols = model.maxx-model.minx+1;
int colWidth = (getWidth()-paddingFromRight - ylabelWidth)/cols;
int rowHeight = (getHeight()-xlabelHeight-headingHeight)/rows;
int endX = ylabelWidth + cols * colWidth;
int endY = headingHeight + rows*rowHeight;
for (int k = 0; k <= cols; k++)
{
g.drawLine(ylabelWidth+colWidth*k, headingHeight, ylabelWidth+colWidth*k, endY); //getHeight()-xlabelHeight
}
for (int k = 0; k <= rows;k++)
{
g.drawLine(ylabelWidth, headingHeight+rowHeight*k,endX, headingHeight+rowHeight*k);
}
}
public void drawLines(Graphics g)
{
ArrayList<Line> lines = model.getLines();
Random random = new Random(50);
for (int k = 0; k < lines.size(); k++)
{
g.setColor(new Color(255-50*k, 50*k, 2*50*k));
//g.setColor(Color.red);
drawLine(g, lines.get(k));
}
}
public void drawLine(Graphics g, Line line)
{
ArrayList<Point> points = line.points;
for (int k = 0; k<points.size()-1;k++)
{
//scale up points
Point p1 = points.get(k);
Point p2 = points.get(k+1);
g.drawLine(scaleUpX(p1.x), scaleUpY(p1.y), scaleUpX(p2.x), scaleUpY(p2.y));
g.fillOval(scaleUpX(p1.x)-5, scaleUpY(p1.y)-5, 10, 10);
}
Point p1 = points.get(points.size()-1);
g.fillOval(scaleUpX(p1.x)-5, scaleUpY(p1.y)-5, 10, 10);
}
public int scaleUpX(int x)
{
int cols = model.maxx-model.minx+1;
int colWidth = (getWidth()-paddingFromRight - ylabelWidth)/cols;
return ylabelWidth+colWidth*x;
}
public int scaleUpY(int y)
{
int rows = model.maxy-model.miny+1;
int rowHeight = (getHeight()-xlabelHeight-headingHeight)/(rows);
//int endY = getHeight()-xlabelHeight;
int endY = headingHeight+rows*rowHeight;
return endY - rowHeight*y;
}
public void drawLabels(Graphics g)
{
Dimension d = getSize();
//xlabel
g.drawString(model.xlabel, d.width/2, d.height-xlabelHeight/4);
//ylabel
g.drawString(model.ylabel, 0+5, d.height/2);
//xaxis
int rows = model.maxy-model.miny+1;
int cols = model.maxx-model.minx+1;
int colWidth = (getWidth()-paddingFromRight - ylabelWidth)/cols;
int rowHeight = (getHeight()-xlabelHeight-headingHeight)/rows;
for (int k = 0;k<=cols;k++)
{
g.drawString(String.valueOf(model.minx+k), ylabelWidth+k*colWidth-5, rowHeight*rows+headingHeight+15);
}
//yaxis
for (int k = 0;k<=rows;k++)
{
g.drawString(String.valueOf(model.maxy-k+1),ylabelWidth-15,headingHeight+k*rowHeight);
}
//heading
FontMetrics fm = g.getFontMetrics();
g.setFont(g.getFont().deriveFont((float)25.0));
g.drawString(model.title, d.width/2-fm.stringWidth(model.title), headingHeight/2+headingHeight/4);
}

Text added to PDF appearing bold/rough

I'm adding/replacing some page numbers on an existing PDF's contents page, but the text is coming out bold, or rough. It's not right any ways, and I can't seem to fix it!
This is what I mean:
The numbers on the right are the existing page numbers I am replacing and the text is fine. The numbers on the left are the page numbers I have added using iText in Java.
Here is the code:
private static void fixTOCPageNumbers(int i, PdfContentByte content, List<Section> sections)
throws DocumentException, IOException {
int xPositionRec;
int yPositionRec;
int xPositionText;
int yPositionText;
int xOffset = 0;
int yOffset = 0;
content.saveState();
content.setColorStroke(new Color(77,77,77));
content.beginText();
content.setFontAndSize(BaseFont.createFont("fonts/LTe50327.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED), 10f);
int count = 5;
for(int j = 4; j <= sections.size() - 2; j++)
{
int startPageIndex = sections.get(j).GetStartPageIndex();
int endPageIndex = sections.get(j).GetEndPageIndex();
xPositionRec = 281;
yPositionRec = 385;
xPositionText = 266;
yPositionText = 386;
if(j > 6)
{
yPositionRec = 195;
yPositionText = 196;
}
for(int k = startPageIndex; k <= endPageIndex; k++)
{
content.rectangle(xPositionRec+xOffset,yPositionRec-yOffset,12,12);
content.setRGBColorFill(255,255,255);
content.showTextAligned(PdfContentByte.ALIGN_CENTER, String.format("%d", count), xPositionText+xOffset, yPositionText-yOffset, 0);
content.setRGBColorFill(77,77,77);
//content.fillStroke();
yOffset += 18;
count++;
}
yOffset = 0;
if(j > 6)
{
xOffset += 229;
}
else if(j == 6)
{
xOffset = 0;
}
else
{
xOffset += 230;
}
}
xOffset = 0;
yOffset = 0;
content.restoreState();
content.endText();
}
Am I doing something wrong? This is the first time I've used iText and the code base wasn't originally mine.
Any help would be much appreciated!
You can simulate bold for example like this:
C#
cb.BeginText();
cb.SetFontAndSize(font, 11F);
cb.SetCharacterSpacing(1F);
// Fill color (stroke fill)
cb.SetRGBColorFill(0, 0, 0);
cb.SetLineWidth(0.5F);
// Fill stroke simulate bold
cb.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
cb.SetTextMatrix(x, pageSize.Height - y);
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, s, (pageSize.Width / 2F), pageSize.Height - y, 0);
cb.EndText();

Categories