Bug 60255 - createDrawingPatriarch does not take next correct next drawing index number
Summary: createDrawingPatriarch does not take next correct next drawing index number
Alias: None
Product: POI
Classification: Unclassified
Component: XSSF (show other bugs)
Version: 3.14-FINAL
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: POI Developers List
: 55516 (view as bug list)
Depends on:
Reported: 2016-10-14 08:16 UTC by Zero
Modified: 2016-10-19 07:58 UTC (History)
1 user (show)

excel file after clear content, now duplicate at /xl/drawings/drawing13.xml (254.45 KB, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
2016-10-14 09:16 UTC, Zero

Note You need to log in before you can comment on or make changes to this bug.
Description Zero 2016-10-14 08:16:39 UTC
When i create Drawing from sheet.createDrawingPatriarch()
I got Exception: org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException: A part with the name '/xl/drawings/drawing7.xml' already exists : Packages shall not contain equivalent part names and package implementers shall neither create nor recognize packages with equivalent part names. [M1.12]

I tested with 3.14 and 3.15. Problem i found maybe: in org.apache.poi.xssf.usermodel.XSSFSheet.createDrawingPatriarch, 
we get new drawing index by code line
int drawingNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()).size() + 1;
The index is count of exist drawings + 1. And correct if exist indexes are consecutive.

My Excel file containing multiple drawings, getPackagePart().getPackage().getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()) return indexes are nonconsecutive. Then I got Exception

There is another way for me to re-index exist drawing by poi library or How can I override this method to get new index = get lastest index + 1

Thank you very much for reading and support
Comment 1 Javen O'Neal 2016-10-14 08:27:46 UTC
POI should probably look through all defined drawing IDs and either pick the lowest available ID greater than 0 (fill in the gaps) or 1 greater than the largest drawing ID.

Will there be any issues with the first approach, such as drawing z-order or breaking references (hopefully no detached xml element exceptions)?

Zero, can you upload a workbook with non-consecutive drawing numbers that we could use for a unit test?
Comment 2 Zero 2016-10-14 09:16:36 UTC
Created attachment 34372 [details]
excel file after clear content, now duplicate at /xl/drawings/drawing13.xml

Thank Javen O'Neal, I upload the file
Comment 3 Zero 2016-10-14 09:37:48 UTC
I think I found the bug,
the method getPackagePart().getPackage().getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()) not load all /xl/drawings/drawing#.xml

I debug with getPackagePart().getPackage(), then I found hidden drawing, 
in partList, registerPartNameStr include
/xl/drawings/drawing1.xml, /xl/drawings/drawing2.xml, /xl/drawings/drawing3.xml, /xl/drawings/drawing4.xml, /xl/drawings/drawing5.xml, /xl/drawings/drawing6.xml, /xl/drawings/drawing7.xml, /xl/drawings/drawing8.xml, /xl/drawings/drawing9.xml, /xl/drawings/drawing10.xml, /xl/drawings/drawing11.xml, /xl/drawings/drawing12.xml, /xl/drawings/drawing13.xml, /xl/drawings/drawing14.xml, /xl/drawings/drawing15.xml, /xl/drawings/drawing16.xml, /xl/drawings/drawing17.xml, /xl/drawings/drawing18.xml, /xl/drawings/drawing19.xml, /xl/drawings/drawing20.xml, /xl/drawings/drawing21.xml, /xl/drawings/drawing22.xml, /xl/drawings/drawing23.xml, /xl/drawings/drawing24.xml, /xl/drawings/drawing25.xml, /xl/drawings/drawing26.xml, /xl/drawings/drawing27.xml, /xl/drawings/drawing28.xml

but getPackagePart().getPackage().getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()) just return 1,4,7,8,12,13,16,19,20,21,24,28
Comment 4 Zero 2016-10-14 09:48:22 UTC
I found reason why drawing2,3 not in list of getPackagePart().getPackage().getPartsByContentType(XSSFRelation.DRAWINGS.getContentType())

In function org.apache.poi.openxml4j.opc.OPCPackage.getPartsByContentType

/xl/drawings/drawing2.xml - Content Type: application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml
/xl/drawings/drawing3.xml - Content Type: application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml

not equals

XSSFRelation.DRAWINGS.getContentType() = application/vnd.openxmlformats-officedocument.drawing+xml

then retArr added

Thanks for reading
Comment 5 Zero 2016-10-14 10:06:33 UTC
edit: then part not added to retArr
Comment 6 Nick Burch 2016-10-14 10:12:35 UTC
Normally parts of type application/vnd.openxmlformats-officedocument.drawingml.chart+xml use the /xl/charts/chart#.xml naming scheme, but I guess this proves it doesn't always!
Comment 7 Nick Burch 2016-10-14 10:44:45 UTC
Fixed in r1764863 - util method added to find the next available part number even with other parts claiming the "wrong" one, and used from the drawing creation
Comment 8 Zero 2016-10-14 12:33:50 UTC
Thank you very much, Nick Burch
Comment 9 Javen O'Neal 2016-10-14 14:45:38 UTC
(In reply to Nick Burch from comment #7)
> r1764863
Is there anything special about the special 9999 and 1000? Could a workbook have more drawings than this (and then POI artificially limits drawing creation to 1000)?

I was thinking of something along the lines of

NavigableSet<Integer> takenIDs = new TreeSet<Integer>();
for (PackagePart part : packages) {
int previous = 0;
for (int id : takenIDs.tailSet(1)) {
    if (id != previous+1) {
        // a gap was found or the taken IDs did not start at 1
        return previous+1;
// there were no gaps in takenIDs. Assign the max taken ID + 1.
return takenIDs.last() + 1;
Comment 10 Nick Burch 2016-10-14 15:01:36 UTC
The most I've seen were part numberss in the double digits, so I added an order of magnitude and rounded up! If you have a cleaner solution, please feel free to replace the logic :) Unit tests should hopefully help with that too!
Comment 11 Javen O'Neal 2016-10-15 17:11:59 UTC
*** Bug 55516 has been marked as a duplicate of this bug. ***
Comment 12 Javen O'Neal 2016-10-19 07:58:45 UTC
(In reply to Nick Burch from comment #10)
> The most I've seen were part numberss in the double digits, so I added an
> order of magnitude and rounded up! If you have a cleaner solution, please
> feel free to replace the logic :)

Replaced 1000 part limit by querying the OOXML package for the number of package parts in r1765546.