Converting a specified region of a DXF to BMP, Uneven pixel distribution Problem.

When using Klayout's API save_image_with_options to save a DXF file as a BMP image, 0.4-micron lines placed in different positions sometimes appear as 1 pixel, while others become 2 or 3 pixels. How can this issue be resolved?
Here is DxfFile(jpeg format,Dxf froamt is not surpported),And Bmp as result.
Thanks a lot

Comments

  • Can you attach the abc.dxf file by zipping it to abc.dxf.zip?
    Also, please provide more details on using the save_image_with_options() function, including the clip window geometry.

  • Ok , I upload dxfFile,bmpFile and python script using save_image_with_options().Thanks for your help.

  • Ok , I upload dxfFile,bmpFile and python script using save_image_with_options().Thanks for your help.

  • edited December 2024

    Thank you for sharing the DXF file.
    Before going into the details of the code, I checked the DXF file itself.
    See the six images below.






    Observations and Questions:
    1. Some Polylines are not converted to Polygons but treated as zero-width Paths.
    2. Some Paths are overlapping Polygons. Is this design intentional? Therefore, is the file named Overlay.dxf?
    3. What is the rough chip size? About 2mm x 2mm?


    [Edit] I found a problem: My DXF Reader Option was inappropriate; it needed a scaling factor of x1000. Now, I can proceed.

    To be continued.

  • Hi @Flyingmyd,

    1. Do you pass the DXF file as input_file to def convert_gds_to_png(input_file, output_file, dbox_xmin, dbox_ymin, dbox_xmax, dbox_ymax, width, height): ? Or externally converted GDS2 file?
    2. conversion_log.txt seems to have the actual clipping geometries.
  • Cont.

    With more observations, I understood as follows:
    1. the output image size is 1080 x 1080 [pix]
    2. the top cell's bounding box is 2041.2 [um] square
    3. if the above bounding box is split into 5x5 regions, each covers 408.24 [um] square region
    4. 408.24 [um] / 1080 [pix] ---> 0.378 [um/pix], which is nearly equal to the critical dimension (0.4 [um])
    5. on the other hand, (most of) the coordinates are not on the 400 [nm] grid (see the image below)
    6. therefore, when digitizing to a bitmap, rounding off errors occur, which is the route cause of the uneven pixel distribution

    To be continued.

  • edited December 2024

    Cont.

    As I observed above, your bitmap resolution (DPI) is too small.
    So, I remade your Python script (see the attached ZIP file).
    The wrapper batch (RunKlayoutDxf2Png.bat) script is no longer required.
    I tested it on Linux Mint 20.3, Windows 11, and Mac.
    The command line parameters are as follows (modify it as you like).

    -----------------------------------------------------------------------------------------------------
    f2639.py
      << To generate monochrome image files with the help of KLayout Python Module >>
    
    $ [python3] f2639.py
       option & argument : comment on option if any                         | default value
       ---------------------------------------------------------------------+------------------
       <-i|--input <file>> : input file name *.gds, *.oas, or *.dxf         | ''
       [-f|--format <name>] : output image format 'bmp', or 'png'           | bmp
       [-n|--notmono] : not monochrome; user environment-dependent color    | disabled
       [-t|--dxftop <top cell name>] : DXF top cell name                    | TOP
       [-u|--dxfunit <value>]: DXF drawing units in [um]                    | 1000.0
       [-c|--cd <value>]: critical dimension in [um]                        | 0.4
       [-p|--pixcd <value>]: pixels per the critical dimension              | 5
       [-m|--maxcanvas <value>]: target maximum canvas size in pixels       | 5000
       [-b|--noborder] : without the image border                           | disabled
       [-d|--debug  <level>] : debug level list                             | [0]
       [-?|--?] : print this usage and exit                                 | disabled
       You may use the -i option multiple times, including a wild card.     |
           ex. -i abc.oas  -i xzy.gds -i "*.dxf" (-i '*.oas' in mac zsh)    |
    ------------------------------------------------------------------------+----------------------------
    

    My idea includes:
    1. Instead of explicitly providing the clipping window from outside, determine it internally based on...
    2. (a) the cell size, (b) the critical dimension, (c) how many pixels are allocated to the CD, and
    3. (d) the target (not fixed but variable) output canvas size

    Test Run

    $ ./f2639.py -i Overlay.dxf -b
    ### Generating Image Files from <Overlay.dxf> ###
      >>> Generated Overlay_C01_R01.bmp
      >>> Generated Overlay_C01_R02.bmp
      >>> Generated Overlay_C01_R03.bmp
      >>> Generated Overlay_C01_R04.bmp
      >>> Generated Overlay_C01_R05.bmp
      >>> Generated Overlay_C02_R01.bmp
      >>> Generated Overlay_C02_R02.bmp
      >>> Generated Overlay_C02_R03.bmp
      >>> Generated Overlay_C02_R04.bmp
      >>> Generated Overlay_C02_R05.bmp
      >>> Generated Overlay_C03_R01.bmp
      >>> Generated Overlay_C03_R02.bmp
      >>> Generated Overlay_C03_R03.bmp
      >>> Generated Overlay_C03_R04.bmp
      >>> Generated Overlay_C03_R05.bmp
      >>> Generated Overlay_C04_R01.bmp
      >>> Generated Overlay_C04_R02.bmp
      >>> Generated Overlay_C04_R03.bmp
      >>> Generated Overlay_C04_R04.bmp
      >>> Generated Overlay_C04_R05.bmp
      >>> Generated Overlay_C05_R01.bmp
      >>> Generated Overlay_C05_R02.bmp
      >>> Generated Overlay_C05_R03.bmp
      >>> Generated Overlay_C05_R04.bmp
      >>> Generated Overlay_C05_R05.bmp
    
    >>> Elapsed Time = 24.202 [sec] >>>
    


    Kazzz-S

  • edited December 2024

    Hi @sekigawa,

    thanks for this elaborate analysis, as usual! :)

    There is a related discussion here: https://www.klayout.de/forum/discussion/2630/how-to-use-the-rasterize-function-to-render-a-specified-area-of-a-gds-file#latest

    I have repeatedly made a statement regarding the use of "save_image" for manufacturing purposes. This function is meant for visualization, so it does not care about one pixel more or less. There is a lot of optimization involved, and under certain circumstances, the output maybe precise, but a little bit off things may look bad again. "save_image" is NOT intended for precision rasterization and I strongly advice against using it for generating mask data - if that is what you are trying to do.

    The mentioned alternative discussion explains how to use a different approach to get precision grayscale rasterization at the cost of higher memory consumption and runtime. It uses the "rasterize" method of Region. Please is this feature when you need predictable and production-quality rasterization.

    Matthias

  • Cont.

    The [-b|--noborder]: no image border option was inappropriately named and had a bug.
    Apologies for the inconvenience. The correct version is now:

    Modified

    -----------------------------------------------------------------------------------------------------
    f2639.py
      << To generate monochrome image files with the help of KLayout Python Module >>
    
    $ [python3] f2639.py
       option & argument : comment on option if any                         | default value
       ---------------------------------------------------------------------+------------------
       <-i|--input <file>> : input file name *.gds, *.oas, or *.dxf         | ''
       [-f|--format <name>] : output image format 'bmp', or 'png'           | bmp
       [-n|--notmono] : not monochrome; user environment-dependent color    | disabled
       [-t|--dxftop <top cell name>] : DXF top cell name                    | TOP
       [-u|--dxfunit <value>]: DXF drawing units in [um]                    | 1000.0
       [-c|--cd <value>]: critical dimension in [um]                        | 0.4
       [-p|--pixcd <value>]: pixels per the critical dimension              | 5
       [-m|--maxcanvas <value>]: target maximum canvas size in pixels       | 5000
       [-s|--single] : create a single image of the whole                   | disabled
       [-d|--debug  <level>] : debug level list                             | [0]
       [-?|--?] : print this usage and exit                                 | disabled
       You may use the -i option multiple times, including a wild card.     |
           ex. -i abc.oas  -i xzy.gds -i "*.dxf" (-i '*.oas' in mac zsh)    |
    ------------------------------------------------------------------------+----------------------------
    

    Kazzz-S

  • I think it will go best for you, if the scale factors
    are "round number" multiples / divisors. Can't do
    "fractional pixels" so you end up "notchy" in any
    conversion / resizing, unless integer multiples of
    initial DBU?

    Large DBU per UU will mimimize, but only round
    number scaling eliminate, the "width toggling".
    Like, 1000 may be good but is 1024 the magic
    number? Or maybe it's 960.

  • @sekigawa
    Happy New Year!
    Thanks For you so-detailed reply.I was so busy Recently. Now I get back.

    ' ' '
    1.Some Polylines are not converted to Polygons but treated as zero-width Paths.
    Answer: Yes, this is because the DXF image was drawn in QCAD. When opened in KLayout, some polylines remain as polylines, while others are converted to paths.

    2.Some Paths are overlapping Polygons. Is this design intentional? Therefore, is the file named Overlay.dxf?
    Answer: This DXF design is for etching purposes, and the overlapping polygons are a design requirement.

    3.What is the rough chip size? About 2mm x 2mm?
    Answer: The overall size is 2.0399mm x 2.0399mm.

    ' ' '

  • Hi ! @sekigawa
    With more observations, I understood as follows:
    ' ' '
    The output image size is 1080x1080 [pix].
    The top cell's bounding box is 2041.2 [um] square.
    If the above bounding box is split into 5x5 regions, each covers a 408.24 [um] square region.
    408.24 [um] / 1080 [pix] ---> 0.378 [um/pix], which is nearly equal to the critical dimension (0.4 [um]).
    On the other hand, (most of) the coordinates are not on the 400 [nm] grid (see the image below).
    Therefore, when digitizing to a bitmap, rounding errors occur, which is the root cause of the uneven pixel distribution.
    ' ' '

    Answer: My goal is to split the DXF image into regions of 408.24[um] each, with the output image being 1080x1080. This DXF image has 5 regions, so the total size is 408.24[um] × 5. Additionally, I need to achieve 0.378 microns per pixel.

  • @sekigawa
    ' ' '
    As I observed above, your bitmap resolution (DPI) is too small.
    So, I remade your Python script (see the attached ZIP file).
    The wrapper batch (RunKlayoutDxf2Png.bat) script is no longer required.
    I tested it on Linux Mint 20.3, Windows 11, and Mac.

    ' ' '
    Answer: Thank you for your script! You’re amazing. However, I must use the 1080x1080 split because the lower-level machine only supports 1080x1080 images. I tested your script with the 1080x1080 output, using the parameters -c=0.378 and -p=1, but I still encountered the same issue I mentioned.

    After reading comments from others(https://www.klayout.de/forum/discussion/2630/how-to-use-the-rasterize-function-to-render-a-specified-area-of-a-gds-file#latest), I found that the problem lies in the improper use of the API (save_image_with_options). Some forum users mentioned in this thread that the Region rasterize API is specifically designed for rasterizing. Using the rasterize() API, I was able to achieve the same operation as save_image_with_options() (splitting the DXF image into regions of 408.24 [um], with the output image being 1080x1080).

    The results with rasterize() are much better than with save_image_with_options(). However... almost all areas (except for two specific points I marked) became two pixels wide instead of the one-pixel width I set. I’m currently working on finding the cause of this issue.

    Below is my Python script and the generated images:

    Let me know if you need further clarification!

  • @Matthias
    Yes, thank you for your suggestion. I used the rasterize API you recommended, and the results have significantly improved. However, some issues still remain, as detailed in my reply to Sekigawa.

  • @dick_freebird
    Happy New Year!
    Yes, I agree with you. However, I must generate 1080-pixel images. A 1080p image corresponds to a 408.24 [um] field, where a line width of 0.378 [um] corresponds to 1 pixel. I’ll try discussing with the project manager whether we can use 1000 instead.

  • Hi @Flyingmyd,

    I think this is related to this post: https://www.klayout.de/forum/discussion/2653, right?

    Please see my reply there.

    Matthias

Sign In or Register to comment.