ASPOSE.barcode and ASPOSE.Cells, center barcode in cell

I’m using Aspose.Cells to create reports. We have a need to insert a barcode centered in a specific cell. I am using Aspose.BarCode to generate that.

However, the barcode has a changing length to it (maybe it is 10 digits, maybe up to 20) so I don’t have a specific length it could be. The cell is the full width of the report.

However, it seems barcodes when placed into cells, are automatically left aligned. Even if the cell itself is center aligned, the barcode is still on the left.

I know I can add left padding to the left side barcode to artificially shift it to the center, but I don’t have a fixed barcode width since they can be wildly different lengths. So I would need to calculate how much padding to add for each barcode.

I’m hoping there is a better way? Am I missing something here? Can I make the barcode centered in the cell in some other way?

Thanks for your assistance.

@cstaub,

Could you please share the following:

  1. Barocde image generated by Aspose.BarCode.
  2. Template Excel file containing the specific cell where you want to place the barcode image via Aspose.Cells.
  3. Sample code (runnable) that you are using to accomplish the task with Aspose.Cells API.
  4. Output Excel file containing the image (in the cell) which is undesired.

As soon as we have your resource files and other artifacts, we will start investigating your issue/requirements.

PS. please zip the files and other resources prior attaching here.

So, I’m not using a template file, I am making the excel file programmatically. I am generating the barcode as such below:

    Workbook Doc = new Workbook();
    Worksheet Sheet = Doc.Worksheets[0];

    BarcodeGenerator Generator = new BarcodeGenerator(EncodeTypes.Code39Standard, "TestBarcodeFont");
    Generator.Parameters.Resolution = 300;
    Generator.Parameters.Barcode.CodeTextParameters.Location = CodeLocation.None;

    MemoryStream BarCodeStream = new MemoryStream();
    Generator.Save(BarCodeStream, BarCodeImageFormat.Bmp);

    Aspose.Cells.Cell cell = Sheet.Cells["A1"];
    Aspose.Cells.Style style = cell.GetStyle();
    style.HorizontalAlignment = TextAlignmentType.Center;
    cell.SetStyle(style);
    Sheet.Cells.Merge(0, 0, 1, 6);
    Sheet.Cells.SetRowHeight(0, 45);
    

    Aspose.Cells.Drawing.Picture BarCodePicture = Sheet.Pictures[Sheet.Pictures.Add(0, 0, 1, 6, BarCodeStream)];
    BarCodePicture.Placement = Aspose.Cells.Drawing.PlacementType.Move;

    Sheet.PageSetup.FitToPagesWide = 1;

    Doc.Save(DataDir + " barcode test.xlsx");

There are other things that happen (adding values using Cells.PutValue) but the behavior can be seen with above code alone.

Make DataDir be your desired save directory. This will give you the current, undesired result.

With this, you can open the file and see the barcode does not center in the cell A1, it is placed in the full width of the cell(s) specified even if doing so spaces out the bars (or squishes them) as to be unreadable.

I have tried “BarCodePicture.Placement = Aspose.Cells.Drawing.PlacementType.MoveAndSize” but the barcode still fills the entire cell range and may be stretched too far or squished too close.

I have also tried PlacementType.Move and PlacementType.FreeFloating but this means the barcode is not tied to the cell and has some weird behavior as other parts of the report may be resized and inserted above/around the barcode.

What I am hoping for is to place the barcode at a readable width in the cell, centered. Please see "Desired Result"Desired Result.zip (7.5 KB) attached. The barcode is placed readable in the middle of the cell, but can still be adjusted by changing the cells width and height. And if the barcode is longer or shorter it has room to expand.

My merge cell is sized so it fits the widest barcode we can possibly make, but our shortest one is too spaced out as to be unreadable. If I adjust cell size to our shortest code, the longest one is too crowded.

I hope this makes sense to you. I just want to place the barcode centered in the cell at a standard, readable width regardless of how wide the cell is. Thanks.

@cstaub,

Thanks for the sample file.

Please note, pictures are saved a separate entities in MS Excel, so specifying style alignment of the underlying cell (e.g., A1) is out of context. In short, only data/values inserted into the cell will be effective for alignment or other style/formatting settings. Since you are inserting barcode picture into some merged cell (e.g., A1:F1), so you have to first gather the width of each column involved, calculate the center place considering the image’s width/height intact (using your own logic) and then place the barcode image to the place accordingly. For your requirements, I think you may simply insert barcode (generated) image into your desired cell while using 100% width/height scale. Now extend the cell’s width and height with respect to barcode image size. This will make the image into the center of the cell well. See the update code segment for your reference:
e.g.
Sample code:

Workbook Doc = new Workbook();
Worksheet Sheet = Doc.Worksheets[0];

Aspose.BarCode.Generation.BarcodeGenerator Generator = new Aspose.BarCode.Generation.BarcodeGenerator(Aspose.BarCode.Generation.EncodeTypes.Code39Standard, "TestBarcodeFont");
Generator.Parameters.Resolution = 300;
Generator.Parameters.Barcode.CodeTextParameters.Location = Aspose.BarCode.Generation.CodeLocation.None;

MemoryStream BarCodeStream = new MemoryStream();
Generator.Save(BarCodeStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);

Aspose.Cells.Cell cell = Sheet.Cells["A1"];

Aspose.Cells.Drawing.Picture BarCodePicture = Sheet.Pictures[Sheet.Pictures.Add(0, 0, BarCodeStream,100,100)];

BarCodePicture.Placement = Aspose.Cells.Drawing.PlacementType.FreeFloating;

Sheet.Cells.SetRowHeightPixel(cell.Row, BarCodePicture.Height);
Sheet.Cells.SetColumnWidthPixel(cell.Column, BarCodePicture.Width);

Sheet.PageSetup.FitToPagesWide = 1;

Doc.Save("e:\\test2\\barcode test1.xlsx");

Hope, this helps a bit.

That is helpful, but sadly in my full report the barcode is not in cell A1 and the columns may be resized etc. which then moves the barcode out of place.

The columns used for the barcode are also used for other types of data (and the columns on the left and right as well). And so resizing the column itself can cause issues with the data in those columns (truncating it or placing too much spacing between).

I have generated an empty report file here EmptyTemplate.zip (9.5 KB)

  • you can see all the fields done like <> will be populated with data, and the row 13 is for the barcode.

A data table fills the info after the barcode (at row 15) and auto-resizes the columns to fit the data populated from the DT.

So my hope is to get the barcode centered in Row 13, without knowing what width the columns are since it depends on the data table, and no way of knowing which column is the center one.

If I place the DT first, then the barcode, it resizes the DT columns and the data can become unreadable.

If I place the barcode first, the columns are resized around it and it ends up misplaced across the report.

Changing the row size is no issue since the barcode is by itself on the row, but the column size change causes issues.

This whole report is done programmatically (there is no template) so I made this empty report instead. I hope it helps better.

@cstaub,

As I told you to insert barcode image into the merged cell, you would need to calculate the total width of each column (involved) for the merged cell, also taking image’s width/height into account. You have to specify some algorithm to calculate the center point considering the image’s width/height intact (using your own logic) and then place the barcode image @ a place accordingly. Anyways, we will check it in details and get back to you later on.

1 Like

While working on this, I thought back to what you said -

Since you are inserting barcode picture into some merged cell (e.g., A1:F1), so you have to first gather the width of each column involved, calculate the center place considering the image’s width/height intact (using your own logic) and then place the barcode image to the place accordingly.

If I do this, would I need to generate the barcode twice?

The way it seems, I’d have to do something like

  • Generate barcode (so I can get the width) and calculate barcode width
  • Calculate sheet width
  • subtract barcode with from sheet width and divide by 2
  • result of that is the left padding needed to make barcode centered
  • remove 1st generated barcode
  • regenerate barcode with specified padding

Since there isn’t a clear column that can be used as center. Is this right?

All the reports will have 1 barcode max, so this might be feasible.

I have the following code to try that, but I’m having an issue since if I use Sheet.Cells.GetColumnWidth though all my columns I can get the page width in “points” (1/72 of an inch) but the BarCodePicture.Width is in Pixels. How can I do the conversion between these?

One I can figure out the conversion, I figure I can do something similar to this:

Workbook Doc = new Workbook();
Worksheet Sheet = Doc.Worksheets[0];

    //Merge barcode cell and add testing to get accurate page width
    Sheet.Cells.Merge(12, 0, 1, 9);
    Sheet.Cells["A1"].PutValue("Testing");
    Sheet.Cells["J1"].PutValue("Testing");

    //make first barcode to get width
    Aspose.BarCode.Generation.BarcodeGenerator Generator = new Aspose.BarCode.Generation.BarcodeGenerator(Aspose.BarCode.Generation.EncodeTypes.Code39Standard, "TestBarcodeFont");
    Generator.Parameters.Resolution = 300;
    Generator.Parameters.Barcode.CodeTextParameters.Location = Aspose.BarCode.Generation.CodeLocation.None;

    //Create memorystream
    MemoryStream BarCodeStream = new MemoryStream();
    Generator.Save(BarCodeStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);

    //Row 13 to place barcode
    Aspose.Cells.Cell cell = Sheet.Cells["A13"];

    //Place temporarily to get width
    Aspose.Cells.Drawing.Picture BarCodePicture = Sheet.Pictures[Sheet.Pictures.Add(12, 0, BarCodeStream, 100, 100)];

    //math to get left padding for centered barcode
    int MaxCount = Sheet.Cells.MaxColumn;
    double CurrentWidth;
    double PageWidth = 0;
    double SheetWidth = 0;
    float PaddingSize;
    for(int i=0; i<MaxCount; i++)
    {
        CurrentWidth = Sheet.Cells.GetColumnWidth(i);
        SheetWidth = PageWidth + CurrentWidth;
        PageWidth = SheetWidth;
    }
    //This is broken since PageWidth is Points and BarCodePicture.Width is in Pixels, I end up with a negative number that trunicates the barcode
    PaddingSize = (float)((PageWidth - BarCodePicture.Width) / 2);

    //Add padding to generator
    Generator.Parameters.Barcode.Padding.Left.Point = PaddingSize;

    //Create memorystream
    MemoryStream BarCodeWithPaddingStream = new MemoryStream();
    Generator.Save(BarCodeWithPaddingStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);

    //Re-save the new barcode and place again in report - Need some way to remove first barcode
    Generator.Save(BarCodeWithPaddingStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);
    Aspose.Cells.Drawing.Picture BarCodePictureWithPadding = Sheet.Pictures[Sheet.Pictures.Add(12, 0, BarCodeWithPaddingStream, 100, 100)];
    BarCodePictureWithPadding.Placement = Aspose.Cells.Drawing.PlacementType.FreeFloating;

    //Set row height to barcode height
    Sheet.Cells.SetRowHeightPixel(cell.Row, BarCodePictureWithPadding.Height);
    //Set column width to barcode with WARNING: bad times in report if enabled :(
    //Sheet.Cells.SetColumnWidthPixel(cell.Column, BarCodePicture.Width);

    //Fit report to 1 page wide
    Sheet.PageSetup.FitToPagesWide = 1;

    Doc.Save(DataDir + " barcode test.xlsx");

It doesn’t work currently due to PaddingSize ending up negative since I’m comparing Points to pixels… also I can’t figure out how to remove the first picture either. I end up (understandably) with 2 barcodes in the file.

So my question is: Is there a way to get the ColumnWidth in pixels, or convert it? I know I’m probably not going to get the “point size” out of an image.

Also, how can I get the width without placing the barcode in the report OR remove it later once I have the width?

Thanks for your help.

EDIT: just saw your previous post. Thanks for the quick replies. I still have the two questions above though, thanks!

Trying this some more

And I found perhaps an error in padding calculation?

I found you can get BarcodeWidth in Pixels as well as column width in pixels, so my math formula should work now.

So, the following shows the test I have been running:

    Workbook Doc = new Workbook();
    Worksheet Sheet = Doc.Worksheets[0];

    //Merge barcode cell
    Sheet.Cells.Merge(12, 0, 1, 10);
    Sheet.Cells["A1"].PutValue("Testing");
    Sheet.Cells["J1"].PutValue("Testing");

    //make first barcode to get width
    Aspose.BarCode.Generation.BarcodeGenerator Generator = new Aspose.BarCode.Generation.BarcodeGenerator(Aspose.BarCode.Generation.EncodeTypes.Code39Standard, "TestBarcodeFont");
    Generator.Parameters.Resolution = 300;
    Generator.Parameters.Barcode.CodeTextParameters.Location = Aspose.BarCode.Generation.CodeLocation.None;

    //Create memorystream
    MemoryStream BarCodeStream = new MemoryStream();
    Generator.Save(BarCodeStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);

    //Row 13 to place barcode
    Aspose.Cells.Cell cell = Sheet.Cells["A13"];

    //Place temporarily to get width
    Aspose.Cells.Drawing.Picture BarCodePicture = Sheet.Pictures[Sheet.Pictures.Add(12, 0, BarCodeStream, 100, 100)];

    //math to get left padding for centered barcode
    int MaxCount = Sheet.Cells.MaxColumn;
    float CurrentWidth;
    float PageWidth = 0;
    float SheetWidth;
    float PaddingSize;
    for(int i=0; i<MaxCount; i++)
    {
        CurrentWidth = Sheet.Cells.GetColumnWidthPixel(i);
        SheetWidth = PageWidth + CurrentWidth;
        PageWidth = SheetWidth;
    }
    PaddingSize = ((PageWidth - BarCodePicture.Width) / 2);
    Sheet.Cells["C1"].PutValue("PageWidth" + PageWidth);
    Sheet.Cells["D2"].PutValue("Padding Size" + PaddingSize);
    Sheet.Cells["E3"].PutValue("BarCode Width" + BarCodePicture.Width);

    //Add padding to generator
    Generator.Parameters.Barcode.Padding.Left.Pixels = PaddingSize;

    //Remove all pics
    Sheet.Pictures.Clear();

    //Create memorystream
    MemoryStream BarCodeWithPaddingStream = new MemoryStream();
    Generator.Save(BarCodeWithPaddingStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);

    //place again in report
    Aspose.Cells.Drawing.Picture BarCodePictureWithPadding = Sheet.Pictures[Sheet.Pictures.Add(12, 0, BarCodeWithPaddingStream, 100, 100)];
    BarCodePictureWithPadding.Placement = Aspose.Cells.Drawing.PlacementType.FreeFloating;


    //Set row height to barcode height
    Sheet.Cells.SetRowHeightPixel(cell.Row, BarCodePictureWithPadding.Height);
    //Set column width to barcode with WARNING: bad times if enabled :(
    //Sheet.Cells.SetColumnWidthPixel(cell.Column, BarCodePicture.Width);

    //Fit report to 1 page wide
    Sheet.PageSetup.FitToPagesWide = 1;

    Doc.Save(DataDir + " barcode test.xlsx");

In this test, you can see in the result file that PageWidth is 576 pixels
BarCodeWidth is 193 pixels
And Padding is 191 pixels

I made sure it puts the values in the file itself for troubleshooting purposes

Which means the padding should be just about the same width size as the barcode, but as you can see from the result, it isn’t…The padding in pixels is much less than the width of the barcode. Meaning the barcode width and padding must not be the same “pixels”?

What is happening with the discrepancy in pixel size of the barcode vs the pixel size of the padding? Have I misunderstood the pixel measurement of the columns vs the barcode vs the padding?

thanks for your help

@cstaub
Please set Shape.Left and Shape.Top property to set padding as the following :
Aspose.Cells.Cell cell = Sheet.Cells[“A13”];

            //Place temporarily to get width
            Aspose.Cells.Drawing.Picture BarCodePicture = Sheet.Pictures[Sheet.Pictures.Add(12, 0, BarCodeStream, 100, 100)];

            int leftPadding = 20;//pix
            BarCodePicture.Left = leftPadding;
            int topPadding = 10;
            BarCodePicture.Top = topPadding;


            //Set row height to barcode height
            Sheet.Cells.SetRowHeightPixel(cell.Row, BarCodePicture.Height + topPadding * 2);
            //Set column width to barcode with WARNING: bad times if enabled :(
            Sheet.Cells.SetColumnWidthPixel(cell.Column, BarCodePicture.Width + leftPadding * 2);

Hi @simon.zhao

I tried adding the padding as you specified, but it didn’t change the final report. The output still has the padding on the left too small.

1234567890 Barcode Test barcode test.zip (8.0 KB)

You can see the result here - the padding on the left is still much too small. It should be 191 pixels with the barcode itself being 193 pixels wide, but it is clearly not 191 pixels of padding.

I hope this makes sense, you can see the output dimensions.
Page is 576 pixels wide.
Barcode is 193 pixels wide.
Which means I need 191 pixels of padding on the left side to center the barcode.

However, the padding is clearly not 191 pixels. If it was, the padding would be very close to the same size as the barcode, and it isn’t, it’s about half the size.

What am I doing wrong?

EDIT: There is definitely an issue. While trying to test, I just went ahead and explicitly set

Generator.Parameters.Barcode.Padding.Left.Pixels = BarCodePicture.Width

Since for my test, the two are pretty much the same.

And yet the padding is not the width of the barcode. I feel like I’m missing some sort of conversion. Padding size and barcode width is said to both be in pixels, but it definitely is not.

@cstaub,

Could you please create a sample console application (source code without compilation errors), zip the project and post us to reproduce the issue. Also, share a sample Excel file which shows expected results. We will check your issue soon.

PS. please exclude Aspose.Cells.Dll and Aspose.BarCode.Dll to minimize the size of the zipped archive.

The code I am currently using is thus:

    Workbook Doc = new Workbook();
    Worksheet Sheet = Doc.Worksheets[0];

    //Merge barcode cell
    Sheet.Cells.Merge(12, 0, 1, 10);
    Sheet.Cells["A1"].PutValue("Testing");
    Sheet.Cells["J1"].PutValue("Testing");

    //make first barcode to get width
    Aspose.BarCode.Generation.BarcodeGenerator Generator = new Aspose.BarCode.Generation.BarcodeGenerator(Aspose.BarCode.Generation.EncodeTypes.Code39Standard, "TestBarcodeFont");
    Generator.Parameters.Resolution = 300;
    Generator.Parameters.Barcode.CodeTextParameters.Location = Aspose.BarCode.Generation.CodeLocation.None;

    //Create memorystream
    MemoryStream BarCodeStream = new MemoryStream();
    Generator.Save(BarCodeStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);

    //Row 13 to place barcode
    Aspose.Cells.Cell cell = Sheet.Cells["A13"];

    //Place temporarily to get width
    Aspose.Cells.Drawing.Picture BarCodePicture = Sheet.Pictures[Sheet.Pictures.Add(12, 0, BarCodeStream, 100, 100)];

    //math to get left padding for centered barcode
    int MaxCount = Sheet.Cells.MaxColumn;
    float CurrentWidth;
    float PageWidth = 0;
    float SheetWidth;
    float PaddingSize;
    for(int i=0; i<MaxCount; i++)
    {
        CurrentWidth = Sheet.Cells.GetColumnWidthPixel(i);
        SheetWidth = PageWidth + CurrentWidth;
        PageWidth = SheetWidth;
    }
    PaddingSize = ((PageWidth - BarCodePicture.Width) / 2);
    Sheet.Cells["C1"].PutValue("PageWidth" + PageWidth);
    Sheet.Cells["D2"].PutValue("Padding Size" + PaddingSize);
    Sheet.Cells["E3"].PutValue("BarCode Width" + BarCodePicture.Width);

    //Add padding to generator
    Generator.Parameters.Barcode.Padding.Left.Pixels = PaddingSize;

    //Remove all pics
    Sheet.Pictures.Clear();

    //Create memorystream
    MemoryStream BarCodeWithPaddingStream = new MemoryStream();
    Generator.Save(BarCodeWithPaddingStream, Aspose.BarCode.Generation.BarCodeImageFormat.Bmp);

    //place again in report
    Aspose.Cells.Drawing.Picture BarCodePictureWithPadding = Sheet.Pictures[Sheet.Pictures.Add(12, 0, BarCodeWithPaddingStream, 100, 100)];
    BarCodePictureWithPadding.Placement = Aspose.Cells.Drawing.PlacementType.FreeFloating;


    //Set row height to barcode height
    Sheet.Cells.SetRowHeightPixel(cell.Row, BarCodePictureWithPadding.Height);
    //Set column width to barcode with WARNING: bad times if enabled :(
    //Sheet.Cells.SetColumnWidthPixel(cell.Column, BarCodePicture.Width);

    //Fit report to 1 page wide
    Sheet.PageSetup.FitToPagesWide = 1;

    Doc.Save(DataDir + " barcode test.xlsx");

You can run this to get the undesired result. DataDir should be your desired save location.

What I want is the barcode centered on the merged cell.

So, I know that means I need to add padding to the left (since the barcode is inserted on the left).

But, when I add the necessary padding, the padding doesn’t seem to be enough.

The logic I am using to get this is:

(All units in Pixels)

PageWidth - BarcodeWidth = Total padding (left and right)
Total padding / 2 = padding for one side only (the left side)

But when I add that padding number (in pixels) to the left, it is not adjusting the barcode properly.

In my example page that is generated with the above code, you can see :
Page is 576 pixels wide.
Barcode is 193 pixels wide.
Padding works out to 191 pixels of padding on the left side to center the barcode.

So, I add Padding (in pixels) to the left of the barcode.

However, the padding is clearly not 191 pixels. If it was, the padding would be very close to the same size as the barcode, and it isn’t, it’s about half the size.

Desired Result is attached to my earlier post, I want the barcode centered in the row.

So, I found an error in my PageWidth calculation.

My old code was

    //math to get left padding for centered barcode
    int MaxCount = Sheet.Cells.MaxColumn;
    double CurrentWidth;
    double PageWidth = 0;
    double SheetWidth;
    double PaddingSize;
    for(int i=0; i<MaxCount; i++)
    {
        CurrentWidth = Sheet.Cells.GetColumnWidthInch(i);
        SheetWidth = PageWidth + CurrentWidth;
        PageWidth = SheetWidth;
    }
    PaddingSize = ((PageWidth - BarCodePicture.WidthInch) / 2);

…Can you see where I messed up? It’s subtle…

    for(int i=0; i<MaxCount; i++)

Should actually be

    for(int i=0; i<=MaxCount; i++)

I was missing one of the columns in my count.

Notice something else though - even with this change, the Pixel width still isn’t being calculated or added correctly. I changed the unit of measure to Inch, and it works perfectly.

So, the Pixel padding is definitely not being calculated correctly. But as of now, since using Inch and correcting my for statement, my report is working and the barcode is being generated properly.

I am left with one question only:

I am using

    //Remove all pics
    Sheet.Pictures.Clear();

To remove my 1st barcode, but this is also removing (naturally) any other pics that are inserted into the report.

Is there code to remove specifically BarCodePicture only? If I can do that, I’ll be set!

@cstaub,

Good to know that you have sorted it out now.

Yes, PictureCollection.Clear will remove all the pictures in the worksheet. To remove specific images in the worksheet cells, you may try using PictureCollection.RemoveAt() method. Please note, in MS Excel file formats, images/pictures are stored separately. That’s why you might not detect them directly using its corresponding cell/row/column, etc. You may use Shape/Picture specific attributes (e.g. UpperLeftRow, UpperLeftColumn, LowerRightColumn, LowerRightRow, etc.) accordingly to accomplish the task. See the sample code that will guide you on how to remove the picture from a cell for your reference. So, you may write your own code accordingly for your needs:
e.g.
Sample code:

......
            PictureCollection pictures = Sheet.Pictures;

            for (int i = pictures.Count - 1; i >= 0; i--)
            {
                
                    //If the picture is contained (starting drawn from) in the A13 cell.
                    if (pictures[i].UpperLeftColumn == 0 && pictures[i].UpperLeftRow == 12)
                    {
                        pictures.RemoveAt(i);
                    }

                                
            }

Hope, this helps a bit.

1 Like

That is perfect!!

My result is exactly what I wanted, you are amazing.

@cstaub,

You are welcome.