Image is not being padded correctly - image-processing

Output
I think the following code isn't giving the correct result.
What's wrong withe following code?
public class ImagePadder
{
public static Bitmap Pad(Bitmap image, int newWidth, int newHeight)
{
int width = image.Width;
int height = image.Height;
if (width >= newWidth) throw new Exception("New width must be larger than the old width");
if (height >= newHeight) throw new Exception("New height must be larger than the old height");
Bitmap paddedImage = Grayscale.CreateGrayscaleImage(newWidth, newHeight);
BitmapLocker inputImageLocker = new BitmapLocker(image);
BitmapLocker paddedImageLocker = new BitmapLocker(paddedImage);
inputImageLocker.Lock();
paddedImageLocker.Lock();
//Reading row by row
for (int y = 0; y < image.Height; y++)
{
for (int x = 0; x < image.Width; x++)
{
Color col = inputImageLocker.GetPixel(x, y);
paddedImageLocker.SetPixel(x, y, col);
}
}
string str = string.Empty;
paddedImageLocker.Unlock();
inputImageLocker.Unlock();
return paddedImage;
}
}
Relevant Source Code:
public class BitmapLocker : IDisposable
{
//private properties
Bitmap _bitmap = null;
BitmapData _bitmapData = null;
private byte[] _imageData = null;
//public properties
public bool IsLocked { get; set; }
public IntPtr IntegerPointer { get; private set; }
public int Width { get { return _bitmap.Width; } }
public int Height { get { return _bitmap.Height; } }
public int Stride { get { return _bitmapData.Stride; } }
public int ColorDepth { get { return Bitmap.GetPixelFormatSize(_bitmap.PixelFormat); } }
public int Channels { get { return ColorDepth / 8; } }
public int PaddingOffset { get { return _bitmapData.Stride - (_bitmap.Width * Channels); } }
public PixelFormat ImagePixelFormat { get { return _bitmap.PixelFormat; } }
public bool IsGrayscale { get { return Grayscale.IsGrayscale(_bitmap); } }
//Constructor
public BitmapLocker(Bitmap source)
{
IsLocked = false;
IntegerPointer = IntPtr.Zero;
this._bitmap = source;
}
/// Lock bitmap
public void Lock()
{
if (IsLocked == false)
{
try
{
// Lock bitmap (so that no movement of data by .NET framework) and return bitmap data
_bitmapData = _bitmap.LockBits(
new Rectangle(0, 0, _bitmap.Width, _bitmap.Height),
ImageLockMode.ReadWrite,
_bitmap.PixelFormat);
// Create byte array to copy pixel values
int noOfBitsNeededForStorage = _bitmapData.Stride * _bitmapData.Height;
int noOfBytesNeededForStorage = noOfBitsNeededForStorage / 8;
_imageData = new byte[noOfBytesNeededForStorage * ColorDepth];//# of bytes needed for storage
IntegerPointer = _bitmapData.Scan0;
// Copy data from IntegerPointer to _imageData
Marshal.Copy(IntegerPointer, _imageData, 0, _imageData.Length);
IsLocked = true;
}
catch (Exception)
{
throw;
}
}
else
{
throw new Exception("Bitmap is already locked.");
}
}
/// Unlock bitmap
public void Unlock()
{
if (IsLocked == true)
{
try
{
// Copy data from _imageData to IntegerPointer
Marshal.Copy(_imageData, 0, IntegerPointer, _imageData.Length);
// Unlock bitmap data
_bitmap.UnlockBits(_bitmapData);
IsLocked = false;
}
catch (Exception)
{
throw;
}
}
else
{
throw new Exception("Bitmap is not locked.");
}
}
public Color GetPixel(int x, int y)
{
Color clr = Color.Empty;
// Get color components count
int cCount = ColorDepth / 8;
// Get start index of the specified pixel
int i = (Height - y - 1) * Stride + x * cCount;
int dataLength = _imageData.Length - cCount;
if (i > dataLength)
{
throw new IndexOutOfRangeException();
}
if (ColorDepth == 32) // For 32 bpp get Red, Green, Blue and Alpha
{
byte b = _imageData[i];
byte g = _imageData[i + 1];
byte r = _imageData[i + 2];
byte a = _imageData[i + 3]; // a
clr = Color.FromArgb(a, r, g, b);
}
if (ColorDepth == 24) // For 24 bpp get Red, Green and Blue
{
byte b = _imageData[i];
byte g = _imageData[i + 1];
byte r = _imageData[i + 2];
clr = Color.FromArgb(r, g, b);
}
if (ColorDepth == 8)
// For 8 bpp get color value (Red, Green and Blue values are the same)
{
byte c = _imageData[i];
clr = Color.FromArgb(c, c, c);
}
return clr;
}
public void SetPixel(int x, int y, Color color)
{
// Get color components count
int cCount = ColorDepth / 8;
// Get start index of the specified pixel
int i = (Height - y - 1) * Stride + x * cCount;
try
{
if (ColorDepth == 32) // For 32 bpp set Red, Green, Blue and Alpha
{
_imageData[i] = color.B;
_imageData[i + 1] = color.G;
_imageData[i + 2] = color.R;
_imageData[i + 3] = color.A;
}
if (ColorDepth == 24) // For 24 bpp set Red, Green and Blue
{
_imageData[i] = color.B;
_imageData[i + 1] = color.G;
_imageData[i + 2] = color.R;
}
if (ColorDepth == 8)
// For 8 bpp set color value (Red, Green and Blue values are the same)
{
_imageData[i] = color.B;
}
}
catch (Exception ex)
{
throw new Exception("(" + x + ", " + y + "), " + _imageData.Length + ", " + ex.Message + ", i=" + i);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
_bitmap = null;
_bitmapData = null;
_imageData = null;
IntegerPointer = IntPtr.Zero;
}
}
}

The layout of a Windows bitmap is different than you might expect. The bottom line of the image is the first line in memory, and continues backwards from there. It can also be laid out the other way when the height is negative, but those aren't often encountered.
Your calculation of an offset into the bitmap appears to take that into account, so your problem must be more subtle.
int i = (Height - y - 1) * Stride + x * cCount;
The problem is that the BitmapData class already takes this into account and tries to fix it for you. The bitmap I described above is a bottom-up bitmap. From the documentation for BitmapData.Stride:
The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
It is intended to be used with the Scan0 property to access the bitmap in a consistent fashion whether it's top-down or bottom-up.

Related

Image printing with Epson compatible Thermal printer problem

I am using C# and write code for print contents for the Thermal ticket printer.
There are codes that people use for image print, and it indeed prints images, but something goes wrong. This is my code for image print class, it is widely using open source (I googled and found it, and people successfully implement this code to theirs without problem).
public static class ImagePrint
{
/// <summary>
/// Image convert to Byte Array
/// </summary>
/// <param name="LogoPath">Image Path</param>
/// <param name="printWidth">Image print Horizontal Length</param>
/// <returns></returns>
public static byte[] GetLogo(string LogoPath, int printWidth)
{
List<byte> byteList = new List<byte>();
if (!File.Exists(LogoPath))
return null;
BitmapData data = GetBitmapData(LogoPath, printWidth);
BitArray dots = data.Dots;
byte[] width = BitConverter.GetBytes(data.Width);
int offset = 0;
// Initialize Printer
byteList.Add(Convert.ToByte(Convert.ToChar(0x1B)));
byteList.Add(Convert.ToByte('#'));
// Line Spacing Adjust (24/180 inch)
byteList.Add(Convert.ToByte(Convert.ToChar(0x1B)));
byteList.Add(Convert.ToByte('3'));
byteList.Add((byte)24);
while (offset < data.Height)
{
byteList.Add(Convert.ToByte(Convert.ToChar(0x1B)));
byteList.Add(Convert.ToByte('*'));
byteList.Add((byte)33);
byteList.Add(width[0]);
byteList.Add(width[1]);
for (int x = 0; x < data.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 * data.Width) + x;
bool v = false;
if (i < dots.Length)
v = dots[i];
slice |= (byte)((v ? 1 : 0) << (7 - b));
}
byteList.Add(slice);
}
}
offset += 24;
byteList.Add(Convert.ToByte(0x0A));
}
// Return to normal line spacing (30/160 inch)
byteList.Add(Convert.ToByte(0x1B));
byteList.Add(Convert.ToByte('3'));
byteList.Add((byte)30);
return byteList.ToArray();
}
private static BitmapData GetBitmapData(string bmpFileName, int width)
{
using (var bitmap = (Bitmap)Bitmap.FromFile(bmpFileName))
{
var threshold = 127;
var index = 0;
double multiplier = width; // 이미지 width조정
double scale = (double)(multiplier / (double)bitmap.Width);
int xheight = (int)(bitmap.Height * scale);
int xwidth = (int)(bitmap.Width * scale);
var dimensions = xwidth * xheight;
var dots = new BitArray(dimensions);
for (var y = 0; y < xheight; y++)
{
for (var x = 0; x < xwidth; x++)
{
var _x = (int)(x / scale);
var _y = (int)(y / scale);
var color = bitmap.GetPixel(_x, _y);
var luminance = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
dots[index] = (luminance < threshold);
index++;
}
}
return new BitmapData()
{
Dots = dots,
Height = (int)(bitmap.Height * scale),
Width = (int)(bitmap.Width * scale)
};
}
}
private class BitmapData
{
public BitArray Dots
{
get;
set;
}
public int Height
{
get;
set;
}
public int Width
{
get;
set;
}
}
}
And I use this code like this on my code for image print:
string Image_File_Path = #"D:\TEST\TESTImage.bmp";
int Image_Size_I_Want = 100;
byte[] img = ImagePrint.GetLogo(Image_File_Path, Image_Size_I_Want);
port.Write(img, 0, img.Length);
You can see the result in the attached picture.
There are white space lines on the image.
This class automatically adds a line spacing command, but it seems does not work.
Please suggest any solution.
Using 'mike42/escpos-php' package in laravel
use Mike42\Escpos\Printer;
use Mike42\Escpos\EscposImage;
$tux = EscposImage::load(public_path()."\assets\img\path-to-file.jpg");
$printer->setJustification(Printer::JUSTIFY_CENTER);
$printer->bitImage($tux, 0);
$printer -> setJustification();

Libgdx Pixmap Memory Leak

I am codeing a little project where i need a Line from a given Object to my Mouse. I made things work and came up with this quick and dirty code:
addListener(new ClickListener() {
Image lineImage;
Pixmap pixmap;
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
// Get Actor Origin
// Get local Origin
int x2 = (int) event.getListenerActor().getX(Align.center);
int y2 = (int) event.getListenerActor().getY(Align.center);
// Make it global
x2 = (int) event.getListenerActor().getParent().getX() + x2;
y2 = (int) event.getListenerActor().getParent().getY() + y2;
// Get Stage Coordinates
Vector2 v = localToStageCoordinates(new Vector2(x, y));
Vector2 v2 = new Vector2(x2, y2);
Stage stage = event.getStage();
int width = (int) stage.getWidth();
int height = (int) stage.getHeight();
if (pixmap == null) {
pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
} else {
pixmap.setColor(1, 1, 1, 0);
pixmap.fill();
}
pixmap.setColor(Color.BLUE);
// line
for (int m = -2; m <= 2; m++) {// x
for (int n = -2; n <= 2; n++) {// y
pixmap.drawLine((int) (v2.x+m), (int) (height-v2.y+n) , (int) (v.x+m), (int) (height-v.y+n));
}
}
if (lineImage != null) {
/*lineImage.clear();
lineImage.remove();
*/
lineImage.setDrawable(new SpriteDrawable(new Sprite(new Texture(pixmap))));
} else {
lineImage = new Image(new Texture(pixmap));
}
lineImage.setPosition(0,0);
stage.addActor(lineImage);
// super.touchDragged(event, x, y, pointer);
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
if (lineImage != null) {
lineImage.clear();
lineImage.remove();
}
lineImage = null;
super.touchUp(event, x, y, pointer, button);
}
});
The Problem with this is, when i use this Listener on a Image and i activate touchdragged for about 20 seconds, there will be a memory leak.
I have no idea why this happens, i tried a lot of things but nothing seams to help me fix this. Do you have any ideas?
#noone is right. Add the line where is commented to dispose your pixmap after you assigned the drawable to the lineImage.
if (lineImage != null) {
/*lineImage.clear();
lineImage.remove();
*/
lineImage.setDrawable(new SpriteDrawable(new Sprite(new Texture(pixmap))));
} else {
lineImage = new Image(new Texture(pixmap));
}
pixmap.dispose(); // <-----------Add this line here!!!
lineImage.setPosition(0,0);
stage.addActor(lineImage);

How to download online image after display list data?

For my current code, it will download the images first then only display data and cause the device like lagging.
public Custom_ListField(Vector content, boolean islatest) {
this.content = content;
this.islatest = islatest;
newsid = new int[content.size()];
title = new String[content.size()];
category = new String[content.size()];
date = new String[content.size()];
imagepath = new String[content.size()];
catsid = new int[content.size()];
imagebitmap = new Bitmap[content.size()];
ischeck = new boolean[content.size()];
for (int i = 0; i < content.size(); i++) {
newslist = (List_News) content.elementAt(i);
newsid[i] = newslist.getID();
title[i] = newslist.getNtitle();
category[i] = newslist.getNewCatName();
date[i] = newslist.getNArticalD();
imagepath[i] = newslist.getImagePath();
catsid[i] = newslist.getCatID();
ischeck[i] = false;
if (!imagepath[i].toString().equals("no picture")) {
if (Config_GlobalFunction.isConnected())
imagebitmap[i] = Util_ImageLoader.loadImage(imagepath[i]);
else
imagebitmap[i] = localimage;
}
}
initCallbackListening();
}
private void initCallbackListening() {
callback = new ListCallback();
this.setCallback(callback);
this.setRowHeight(-2);
}
private class ListCallback implements ListFieldCallback {
public ListCallback() {
}
public void drawListRow(ListField listField, Graphics graphics,
final int index, int y, int width) {
currentPosition = index;
if (!imagepath[index].toString().equals("no picture")) {
float ratio = (float) ((float) localimage.getHeight() / (float) imagebitmap[index]
.getHeight());
Bitmap temp = new Bitmap(
(int) (imagebitmap[index].getWidth() * ratio),
(int) (imagebitmap[index].getHeight() * ratio));
imagebitmap[index].scaleInto(temp, Bitmap.FILTER_BILINEAR,
Bitmap.SCALE_TO_FIT);
imagebitmap[index] = temp;
graphics.drawBitmap(
Display.getWidth()
- localimage.getWidth()
- 5
+ ((localimage.getWidth() - imagebitmap[index]
.getWidth()) / 2),
y
+ (listField.getRowHeight(index) - imagebitmap[index]
.getHeight()) / 2,
imagebitmap[index].getWidth(),
imagebitmap[index].getHeight(), imagebitmap[index], 0,
0);
graphics.setColor(Color.BLACK);
text = Config_GlobalFunction
.wrap(title[index], Display.getWidth()
- imagebitmap[index].getWidth() - 15);
for (int i = 0; i < text.size(); i++) {
int liney = y + (i * Font.getDefault().getHeight());
graphics.drawText(
(String) text.elementAt(i),
5,
liney + 3,
DrawStyle.TOP | DrawStyle.LEFT | DrawStyle.ELLIPSIS,
Display.getWidth() - imagebitmap[index].getWidth()
- 10);
}
} else {
graphics.setColor(Color.BLACK);
text = Config_GlobalFunction.wrap(title[index],
Display.getWidth() - 10);
for (int i = 0; i < text.size(); i++) {
int liney = y + (i * Font.getDefault().getHeight());
graphics.drawText(
(String) text.elementAt(i),
5,
liney + 3,
DrawStyle.TOP | DrawStyle.LEFT | DrawStyle.ELLIPSIS,
Display.getWidth() - 10);
}
}
if (text.size() == 2) {
graphics.setColor(Color.GRAY);
graphics.drawText(date[index], 5, y
+ Font.getDefault().getHeight() + 3);
if (islatest) {
graphics.setColor(Color.RED);
graphics.drawText(category[index], Font.getDefault()
.getAdvance(date[index]) + 15, y
+ Font.getDefault().getHeight() + 3);
}
} else if (text.size() == 3) {
graphics.setColor(Color.GRAY);
graphics.drawText(date[index], 5, y
+ Font.getDefault().getHeight() * 2 + 3);
if (islatest) {
graphics.setColor(Color.RED);
graphics.drawText(category[index], Font.getDefault()
.getAdvance(date[index]) + 15, y
+ Font.getDefault().getHeight() * 2 + 3);
}
}
if (!imagepath[index].toString().equals("no picture"))
setRowHeight(index, imagebitmap[index].getHeight() + 10);
else {
if (text.size() == 2)
setRowHeight(index, getRowHeight() + 9);
else if (text.size() == 3) {
setRowHeight(index, getRowHeight() * 15 / 10 + 9);
}
}
graphics.setColor(Color.WHITE);
graphics.drawRect(0, y, width, listField.getRowHeight(index));
ischeck[index] = true;
}
}
I want this imagebitmap[i] = Util_ImageLoader.loadImage(imagepath[i]); run after display data so that no need stuck there. However, I tried to put inside drawListRow, it works but very slow because initially display it will run 0-8 times then when i scroll the listfield, it run again. It was download and download again.
Update
public class Util_LazyLoader implements Runnable {
String url = null;
BitmapDowloadListener listener = null;
public Util_LazyLoader(String url, BitmapDowloadListener listener) {
this.url = url;
this.listener = listener;
}
public void run() {
Bitmap bmpImage = getImageFromWeb(url);
listener.ImageDownloadCompleted(bmpImage);
}
private Bitmap getImageFromWeb(String url) {
HttpConnection connection = null;
InputStream inputStream = null;
EncodedImage bitmap;
byte[] dataArray = null;
try {
connection = (HttpConnection) (new ConnectionFactory())
.getConnection(url + Database_Webservice.ht_params)
.getConnection();
int responseCode = connection.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
inputStream = connection.openDataInputStream();
dataArray = IOUtilities.streamToBytes(inputStream);
}
} catch (Exception ex) {
} finally {
try {
inputStream.close();
connection.close();
} catch (Exception e) {
}
}
if (dataArray != null) {
bitmap = EncodedImage.createEncodedImage(dataArray, 0,
dataArray.length);
return bitmap.getBitmap();
} else {
return null;
}
}
}
I created a new class but i don't know how to use it.
You need to use lazy loading concept here.
For ex:
http://supportforums.blackberry.com/t5/Java-Development/How-to-load-images-quickly-like-android/m-p/1487995#M187253
http://supportforums.blackberry.com/t5/Java-Development/Lazy-loading-issue-in-blackberry/m-p/1835127
You need to download images in a separate thread (not in UI Thread). Actually what happens when you render a list row , it looks for bitmap image.
So what you can do once you are creating your List view. Provide a default loading bitmap image, start a thread to download image ,
you should create method on thread where you are putting the data from Url to vector. this could be in your connection class where you have extend as thread.
like this>>>>
getimagemethod(image[i]);
after you declare your method get the image string url to the method. like this>>
private void getimagemethod(String image2)
{
this.imageforlist = image2;
// you should declare imageforlist string as global string..
newBitmap1 = Util_ImageLoader.getImageFromUrl(imageforlist);
//newBitmap1 is also global Bitmap..**
}
after this put your bitmap which is newBitmap1 to the Vector like this>>
imagevct.addElement(newBitmap1);
here imagevct is vector which is also global**
**inorder to create global vector use this....
private Vector imagevct = new Vector();
now you are ready to draw the bitmap on your list
for that do it like this...
public void drawListRow(ListField list, Graphics g, int index, int y, int w) {
Bitmap imagee = (Bitmap) imagevct.elementAt(index);
g.drawBitmap(HPADDING, 15 + y, 60, 60, imagee , 0, 0);
}
Here HPADDING is>>>>
private static final int HPADDING = Display.getWidth() <= 320 ? 6 : 8;
this is just tutorial sample step by step..
if any query then you can post here...

Using zxing in Blackberry 5.0

I'm stucked when implementing Barcode scanning in Blackberry 5.0 SDK, since I'm look into deep search on the internet, and found no clue.
Then I started to write my own class to provide Barcode Scanning (using zxing core)
then I need to implements BitmapLuminanceSource (rim version not Android version)
public class BitmapLuminanceSource extends LuminanceSource {
private final Bitmap bitmap;
public BitmapLuminanceSource(Bitmap bitmap){
super(bitmap.getWidth(),bitmap.getHeight());
this.bitmap = bitmap;
}
public byte[] getRow(int y, byte[] row) {
//how to implement this method
return null;
}
public byte[] getMatrix() {
//how to implement this method
return null;
}
}
Well, the javadoc in LuminanceSource tells you what it returns. And you have implementations like PlanarYUVLuminanceSource in android/ that show you an example of it in action. Did you look at these at all?
The quick answer though is that both return one row of the image, or the entire image, as an array of luminance values. There is one byte value per pixel and it should be treated as an unsigned value.
I've solved this problem.
Here's the BitmapLuminanceSource implementation
import net.rim.device.api.system.Bitmap;
import com.google.zxing.LuminanceSource;
public class BitmapLuminanceSource extends LuminanceSource {
private final Bitmap bitmap;
private byte[] matrix;
public BitmapLuminanceSource(Bitmap bitmap) {
super(bitmap.getWidth(), bitmap.getHeight());
int width = bitmap.getWidth();
int height = bitmap.getHeight();
this.bitmap = bitmap;
int area = width * height;
matrix = new byte[area];
int[] rgb = new int[area];
bitmap.getARGB(rgb, 0, width, 0, 0, width, height);
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
int pixel = rgb[offset + x];
int luminance = (306 * ((pixel >> 16) & 0xFF) + 601
* ((pixel >> 8) & 0xFF) + 117 * (pixel & 0xFF)) >> 10;
matrix[offset + x] = (byte) luminance;
}
}
rgb = null;
}
public byte[] getRow(int y, byte[] row) {
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException(
"Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
int offset = y * width;
System.arraycopy(this.matrix, offset, row, 0, width);
return row;
}
public byte[] getMatrix() {
return matrix;
}
}
I added com.google.zxing (library for Barcode encode/decode) to my project

Add a label to a BlackBerry ListField

I have a implemented a ListField on BlackBerry. How do I add 3 labels to the list?
Follow this tutorial:
http://berrytutorials.blogspot.com/2009/11/create-custom-listfield-change.html
After completed, modify the extended ListField class by adding some extra components to your list (graphics.drawText(CALLBACK OBJECT, X, Y)). Change the String callback to an object of your type(or just an Array) with the availability for more elements.
EXAMPLE OF THE PAINT METHOD INSIDE THE EXTENDED LISTFIELD CLASS:
public void paint(Graphics graphics) {
int width = (int) (300 * resizeWidthFactor);
// Get the current clipping region
XYRect redrawRect = graphics.getClippingRect();
// Side lines
// graphics.setColor(Color.GRAY);
// graphics.drawLine(0, 0, 0, redrawRect.height);
// graphics.setColor(Color.GRAY);
// graphics.drawLine(redrawRect.width-1, 0, redrawRect.width-1,
// redrawRect.height);
if (redrawRect.y < 0) {
throw new IllegalStateException("Error with clipping rect.");
}
// Determine the start location of the clipping region and end.
int rowHeight = getRowHeight();
int curSelected;
// If the ListeField has focus determine the selected row.
if (hasFocus) {
curSelected = getSelectedIndex();
} else {
curSelected = -1;
}
int startLine = redrawRect.y / rowHeight;
int endLine = (redrawRect.y + redrawRect.height - 1) / rowHeight;
endLine = Math.min(endLine, getSize() - 1);
int y = (startLine * rowHeight) + heightMargin;
// Setup the data used for drawing.
int[] yInds = new int[] { y, y, y + rowHeight, y + rowHeight };
int[] xInds = new int[] { 0, width, width, 0 };
// Set the callback - assuming String values.
ListFieldCallback callBack = this.getCallback();
// Draw each row
for (; startLine <= endLine; ++startLine) {
// If the line we're drawing is the currentlySelected line then draw the
// fill path in LIGHTYELLOW and the
// font text in Black.
//OBJECT OF OWN TYPE FOR MULTIPLE PARAMETERS
ProductDetails data = (ProductDetails) callBack.get(this, startLine);
String productDescription = "";
String errorDescription = "";
if (data.isError()) {
errorDescription = TextLineSplitter.wrapString1Line(data.getErrorMessage(), (int) ((300 - (2 * widthMargin)) * resizeWidthFactor), getFont());
} else {
productDescription = TextLineSplitter.wrapString1Line(data.getProductDesc(), (int) ((300 - (2 * widthMargin)) * resizeWidthFactor), getFont());
}
// Set differences by row (selected or not)
if (startLine == curSelected) {
graphics.setColor(Color.WHITE);
} else {
// Draw the odd or selected rows.
graphics.setColor(Color.BLACK);
}
// Set text values
if (!data.isError()) {
// If no error found
//FIRST LABEL
graphics.setFont(getFont().derive(Font.BOLD));
graphics.drawText("Result search " + Integer.toString(data.getSearchId()) + ":", widthMargin, yInds[0]);
graphics.drawText(data.getManufacturerItemIdentifier(), widthMargin + (int) (140 * resizeWidthFactor), yInds[0]);
//SECOND LABEL
graphics.setFont(getFont().derive(Font.PLAIN));
graphics.drawText(productDescription, widthMargin, yInds[0] + (int) (20 * resizeHeightFactor));
} else {
// Error found
graphics.setColor(Color.GRAY);
graphics.setFont(getFont().derive(Font.BOLD));
graphics.drawText("Result search " + Integer.toString(data.getSearchId()) + ":", widthMargin, yInds[0]);
graphics.setFont(getFont().derive(Font.PLAIN));
graphics.drawText(errorDescription, widthMargin, yInds[0] + (int) (20 * resizeHeightFactor));
}
// Bottom line
if (startLine == endLine) {
graphics.setColor(Color.GRAY);
graphics.drawLine(0, yInds[2] - (heightMargin + 1), (int) (300 * resizeWidthFactor), yInds[2] - (heightMargin + 1));
}
// Horizontal lines
graphics.setColor(Color.GRAY);
graphics.drawLine(0, yInds[0] - heightMargin, (int) (300 * resizeWidthFactor), yInds[0] - heightMargin);
// Assign new values to the y axis moving one row down.
y += rowHeight;
yInds[0] = y;
yInds[1] = yInds[0];
yInds[2] = y + rowHeight;
yInds[3] = yInds[2];
}
// super.paint(graphics);
}

Resources