[{"data":1,"prerenderedAt":2823},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python":2789,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python":2798,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python":2803,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python":2804},{"id":4,"title":5,"body":6,"dateModified":2758,"datePublished":2758,"description":2759,"extension":2760,"faq":2761,"keyword":2770,"kind":2771,"meta":2772,"navigation":189,"path":2780,"seo":2781,"slug":2783,"stem":2784,"topics":2785,"type":2787,"__hash__":2788},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python\u002Findex.md","Extract Images from an Excel File with Python",{"type":7,"value":8,"toc":2745},"minimark",[9,19,112,117,149,152,537,541,551,742,752,756,767,1062,1065,1178,1182,1217,1981,1996,2010,2014,2017,2277,2280,2363,2367,2370,2517,2523,2526,2530,2640,2644,2651,2655,2670,2674,2681,2687,2693,2699,2703,2741],[10,11,12,13,18],"p",{},"Workbooks collect pictures: product photos pasted into a catalogue, scanned receipts attached to an\nexpenses sheet, signatures on an approval form. Sooner or later someone needs them out — to load into\na product database, to archive, or to check that every row has one. Excel's own answer is to save the\nworkbook as a web page and dig through a folder. Python can do better, and can keep the link between each\npicture and the row it belongs to. This guide, part of\n",[14,15,17],"a",{"href":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002F","Inserting Images and Logos into Excel",",\ncovers the three levels of detail you might need.",[20,21,29,30,29,34,29,38,29,45,29,54,29,61,29,66,29,71,29,76,29,80,29,85,29,90,29,93,29,98,29,103,29,106],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"0 0 720 316","img",[25,26],"ext-layers-t","ext-layers-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:720px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[31,32,33],"title",{"id":25},"Where pictures live inside an xlsx file",[35,36,37],"desc",{"id":26},"An xlsx file is a zip archive. Every picture is stored under xl\u002Fmedia. Floating pictures are positioned by drawing parts linked to each worksheet. Pictures in cells are referenced through cell metadata and rich value parts under xl\u002FrichData.",[39,40],"rect",{"x":41,"y":41,"width":42,"height":43,"fill":44},"0","720","316","#ffffff",[39,46],{"x":47,"y":47,"width":48,"height":49,"rx":50,"fill":51,"stroke":52,"style":53},"20","680","52","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[55,56,60],"text",{"x":57,"y":58,"style":59},"40","51","font-size:14px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:start","the zip archive",[55,62,65],{"x":63,"y":58,"style":64},"250","font-size:12px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:start","an .xlsx is a zip of XML parts and media files",[39,67],{"x":47,"y":68,"width":48,"height":49,"rx":50,"fill":69,"stroke":70,"style":53},"84","#d9f4f1","var(--teal,#0f9488)",[55,72,75],{"x":57,"y":73,"style":74},"115","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","xl\u002Fmedia\u002F",[55,77,79],{"x":63,"y":73,"style":78},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","every image file, whatever kind of picture it is",[39,81],{"x":47,"y":82,"width":48,"height":49,"rx":50,"fill":83,"stroke":84,"style":53},"148","#fdefd8","var(--gold,#b4740a)",[55,86,89],{"x":57,"y":87,"style":88},"179","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","xl\u002Fdrawings\u002F",[55,91,92],{"x":63,"y":87,"style":78},"floating pictures: anchors to a cell, size, offset",[39,94],{"x":47,"y":95,"width":48,"height":49,"rx":50,"fill":96,"stroke":97,"style":53},"212","#f0f4ff","var(--brand,#5b5cf0)",[55,99,102],{"x":57,"y":100,"style":101},"243","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","xl\u002FrichData\u002F",[55,104,105],{"x":63,"y":100,"style":78},"pictures in cells: linked from the cell value metadata",[55,107,111],{"x":108,"y":109,"style":110},"360","296","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","the media folder has the bytes; the other parts say where they go",[113,114,116],"h2",{"id":115},"prerequisites","Prerequisites",[118,119,124],"pre",{"className":120,"code":121,"language":122,"meta":123,"style":123},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pillow xlsxwriter\n","bash","",[125,126,127],"code",{"__ignoreMap":123},[128,129,132,136,140,143,146],"span",{"class":130,"line":131},"line",1,[128,133,135],{"class":134},"sMTad","pip",[128,137,139],{"class":138},"srMev"," install",[128,141,142],{"class":138}," openpyxl",[128,144,145],{"class":138}," pillow",[128,147,148],{"class":138}," xlsxwriter\n",[10,150,151],{},"This builds a workbook containing one floating logo and two pictures placed inside cells, so every technique on the page has something to find:",[118,153,157],{"className":154,"code":155,"language":156,"meta":123,"style":123},"language-python shiki shiki-themes github-light github-dark-high-contrast","import xlsxwriter\nfrom PIL import Image, ImageDraw\n\nfor name, colour in [(\"logo\", \"#4338ca\"), (\"widget\", \"#0f9488\"), (\"gadget\", \"#b4740a\")]:\n    picture = Image.new(\"RGB\", (200, 200), \"white\")\n    ImageDraw.Draw(picture).ellipse((20, 20, 180, 180), fill=colour)\n    picture.save(f\"{name}.png\")\n\nbook = xlsxwriter.Workbook(\"catalog.xlsx\")\nsheet = book.add_worksheet(\"Products\")\nsheet.insert_image(\"F1\", \"logo.png\", {\"x_scale\": 0.3, \"y_scale\": 0.3})\nsheet.write_row(0, 0, [\"SKU\", \"Name\", \"Photo\"])\nfor row, (sku, name) in enumerate([(\"W-100\", \"widget\"), (\"G-200\", \"gadget\")], start=1):\n    sheet.set_row(row, 60)\n    sheet.write_row(row, 0, [sku, name])\n    sheet.embed_image(row, 2, f\"{name}.png\")\nbook.close()\n","python",[125,158,159,168,184,191,239,273,305,332,337,353,369,407,438,484,495,506,531],{"__ignoreMap":123},[128,160,161,165],{"class":130,"line":131},[128,162,164],{"class":163},"s-kum","import",[128,166,148],{"class":167},"skGVy",[128,169,171,174,178,181],{"class":130,"line":170},2,[128,172,173],{"class":163},"from",[128,175,177],{"class":176},"sP0c6"," PIL",[128,179,180],{"class":163}," import",[128,182,183],{"class":167}," Image, ImageDraw\n",[128,185,187],{"class":130,"line":186},3,[128,188,190],{"emptyLinePlaceholder":189},true,"\n",[128,192,194,197,200,203,206,209,212,215,218,221,223,226,228,231,233,236],{"class":130,"line":193},4,[128,195,196],{"class":163},"for",[128,198,199],{"class":167}," name, colour ",[128,201,202],{"class":163},"in",[128,204,205],{"class":167}," [(",[128,207,208],{"class":138},"\"logo\"",[128,210,211],{"class":167},", ",[128,213,214],{"class":138},"\"#4338ca\"",[128,216,217],{"class":167},"), (",[128,219,220],{"class":138},"\"widget\"",[128,222,211],{"class":167},[128,224,225],{"class":138},"\"#0f9488\"",[128,227,217],{"class":167},[128,229,230],{"class":138},"\"gadget\"",[128,232,211],{"class":167},[128,234,235],{"class":138},"\"#b4740a\"",[128,237,238],{"class":167},")]:\n",[128,240,242,245,248,251,254,257,260,262,264,267,270],{"class":130,"line":241},5,[128,243,244],{"class":167},"    picture ",[128,246,247],{"class":163},"=",[128,249,250],{"class":167}," Image.new(",[128,252,253],{"class":138},"\"RGB\"",[128,255,256],{"class":167},", (",[128,258,259],{"class":176},"200",[128,261,211],{"class":167},[128,263,259],{"class":176},[128,265,266],{"class":167},"), ",[128,268,269],{"class":138},"\"white\"",[128,271,272],{"class":167},")\n",[128,274,276,279,281,283,285,287,290,292,294,296,300,302],{"class":130,"line":275},6,[128,277,278],{"class":167},"    ImageDraw.Draw(picture).ellipse((",[128,280,47],{"class":176},[128,282,211],{"class":167},[128,284,47],{"class":176},[128,286,211],{"class":167},[128,288,289],{"class":176},"180",[128,291,211],{"class":167},[128,293,289],{"class":176},[128,295,266],{"class":167},[128,297,299],{"class":298},"sa561","fill",[128,301,247],{"class":163},[128,303,304],{"class":167},"colour)\n",[128,306,308,311,314,317,321,324,327,330],{"class":130,"line":307},7,[128,309,310],{"class":167},"    picture.save(",[128,312,313],{"class":163},"f",[128,315,316],{"class":138},"\"",[128,318,320],{"class":319},"sSjpA","{",[128,322,323],{"class":167},"name",[128,325,326],{"class":319},"}",[128,328,329],{"class":138},".png\"",[128,331,272],{"class":167},[128,333,335],{"class":130,"line":334},8,[128,336,190],{"emptyLinePlaceholder":189},[128,338,340,343,345,348,351],{"class":130,"line":339},9,[128,341,342],{"class":167},"book ",[128,344,247],{"class":163},[128,346,347],{"class":167}," xlsxwriter.Workbook(",[128,349,350],{"class":138},"\"catalog.xlsx\"",[128,352,272],{"class":167},[128,354,356,359,361,364,367],{"class":130,"line":355},10,[128,357,358],{"class":167},"sheet ",[128,360,247],{"class":163},[128,362,363],{"class":167}," book.add_worksheet(",[128,365,366],{"class":138},"\"Products\"",[128,368,272],{"class":167},[128,370,372,375,378,380,383,386,389,392,395,397,400,402,404],{"class":130,"line":371},11,[128,373,374],{"class":167},"sheet.insert_image(",[128,376,377],{"class":138},"\"F1\"",[128,379,211],{"class":167},[128,381,382],{"class":138},"\"logo.png\"",[128,384,385],{"class":167},", {",[128,387,388],{"class":138},"\"x_scale\"",[128,390,391],{"class":167},": ",[128,393,394],{"class":176},"0.3",[128,396,211],{"class":167},[128,398,399],{"class":138},"\"y_scale\"",[128,401,391],{"class":167},[128,403,394],{"class":176},[128,405,406],{"class":167},"})\n",[128,408,410,413,415,417,419,422,425,427,430,432,435],{"class":130,"line":409},12,[128,411,412],{"class":167},"sheet.write_row(",[128,414,41],{"class":176},[128,416,211],{"class":167},[128,418,41],{"class":176},[128,420,421],{"class":167},", [",[128,423,424],{"class":138},"\"SKU\"",[128,426,211],{"class":167},[128,428,429],{"class":138},"\"Name\"",[128,431,211],{"class":167},[128,433,434],{"class":138},"\"Photo\"",[128,436,437],{"class":167},"])\n",[128,439,441,443,446,448,451,454,457,459,461,463,466,468,470,473,476,478,481],{"class":130,"line":440},13,[128,442,196],{"class":163},[128,444,445],{"class":167}," row, (sku, name) ",[128,447,202],{"class":163},[128,449,450],{"class":176}," enumerate",[128,452,453],{"class":167},"([(",[128,455,456],{"class":138},"\"W-100\"",[128,458,211],{"class":167},[128,460,220],{"class":138},[128,462,217],{"class":167},[128,464,465],{"class":138},"\"G-200\"",[128,467,211],{"class":167},[128,469,230],{"class":138},[128,471,472],{"class":167},")], ",[128,474,475],{"class":298},"start",[128,477,247],{"class":163},[128,479,480],{"class":176},"1",[128,482,483],{"class":167},"):\n",[128,485,487,490,493],{"class":130,"line":486},14,[128,488,489],{"class":167},"    sheet.set_row(row, ",[128,491,492],{"class":176},"60",[128,494,272],{"class":167},[128,496,498,501,503],{"class":130,"line":497},15,[128,499,500],{"class":167},"    sheet.write_row(row, ",[128,502,41],{"class":176},[128,504,505],{"class":167},", [sku, name])\n",[128,507,509,512,515,517,519,521,523,525,527,529],{"class":130,"line":508},16,[128,510,511],{"class":167},"    sheet.embed_image(row, ",[128,513,514],{"class":176},"2",[128,516,211],{"class":167},[128,518,313],{"class":163},[128,520,316],{"class":138},[128,522,320],{"class":319},[128,524,323],{"class":167},[128,526,326],{"class":319},[128,528,329],{"class":138},[128,530,272],{"class":167},[128,532,534],{"class":130,"line":533},17,[128,535,536],{"class":167},"book.close()\n",[113,538,540],{"id":539},"step-1-extract-every-image-from-the-archive","Step 1 — Extract every image from the archive",[10,542,543,544,547,548,550],{},"An ",[125,545,546],{},".xlsx"," file is a zip archive, and every picture in it — floating or in a cell, on any sheet — is stored as an ordinary image file under\n",[125,549,75],{},". When you only need the files, the standard library is enough.",[118,552,554],{"className":154,"code":553,"language":156,"meta":123,"style":123},"import zipfile\nfrom pathlib import Path\n\ndef extract_all_media(xlsx: str, out_dir: str) -> list[Path]:\n    target = Path(out_dir)\n    target.mkdir(parents=True, exist_ok=True)\n    saved = []\n    with zipfile.ZipFile(xlsx) as archive:\n        for info in archive.infolist():\n            if info.filename.startswith(\"xl\u002Fmedia\u002F\"):\n                path = target \u002F Path(info.filename).name\n                path.write_bytes(archive.read(info))\n                saved.append(path)\n    return saved\n\nprint(extract_all_media(\"catalog.xlsx\", \"media_out\"))\n",[125,555,556,563,575,579,602,612,636,646,660,673,686,702,707,712,720,724],{"__ignoreMap":123},[128,557,558,560],{"class":130,"line":131},[128,559,164],{"class":163},[128,561,562],{"class":167}," zipfile\n",[128,564,565,567,570,572],{"class":130,"line":170},[128,566,173],{"class":163},[128,568,569],{"class":167}," pathlib ",[128,571,164],{"class":163},[128,573,574],{"class":167}," Path\n",[128,576,577],{"class":130,"line":186},[128,578,190],{"emptyLinePlaceholder":189},[128,580,581,584,588,591,594,597,599],{"class":130,"line":193},[128,582,583],{"class":163},"def",[128,585,587],{"class":586},"s_Opv"," extract_all_media",[128,589,590],{"class":167},"(xlsx: ",[128,592,593],{"class":176},"str",[128,595,596],{"class":167},", out_dir: ",[128,598,593],{"class":176},[128,600,601],{"class":167},") -> list[Path]:\n",[128,603,604,607,609],{"class":130,"line":241},[128,605,606],{"class":167},"    target ",[128,608,247],{"class":163},[128,610,611],{"class":167}," Path(out_dir)\n",[128,613,614,617,620,622,625,627,630,632,634],{"class":130,"line":275},[128,615,616],{"class":167},"    target.mkdir(",[128,618,619],{"class":298},"parents",[128,621,247],{"class":163},[128,623,624],{"class":176},"True",[128,626,211],{"class":167},[128,628,629],{"class":298},"exist_ok",[128,631,247],{"class":163},[128,633,624],{"class":176},[128,635,272],{"class":167},[128,637,638,641,643],{"class":130,"line":307},[128,639,640],{"class":167},"    saved ",[128,642,247],{"class":163},[128,644,645],{"class":167}," []\n",[128,647,648,651,654,657],{"class":130,"line":334},[128,649,650],{"class":163},"    with",[128,652,653],{"class":167}," zipfile.ZipFile(xlsx) ",[128,655,656],{"class":163},"as",[128,658,659],{"class":167}," archive:\n",[128,661,662,665,668,670],{"class":130,"line":339},[128,663,664],{"class":163},"        for",[128,666,667],{"class":167}," info ",[128,669,202],{"class":163},[128,671,672],{"class":167}," archive.infolist():\n",[128,674,675,678,681,684],{"class":130,"line":355},[128,676,677],{"class":163},"            if",[128,679,680],{"class":167}," info.filename.startswith(",[128,682,683],{"class":138},"\"xl\u002Fmedia\u002F\"",[128,685,483],{"class":167},[128,687,688,691,693,696,699],{"class":130,"line":371},[128,689,690],{"class":167},"                path ",[128,692,247],{"class":163},[128,694,695],{"class":167}," target ",[128,697,698],{"class":163},"\u002F",[128,700,701],{"class":167}," Path(info.filename).name\n",[128,703,704],{"class":130,"line":409},[128,705,706],{"class":167},"                path.write_bytes(archive.read(info))\n",[128,708,709],{"class":130,"line":440},[128,710,711],{"class":167},"                saved.append(path)\n",[128,713,714,717],{"class":130,"line":486},[128,715,716],{"class":163},"    return",[128,718,719],{"class":167}," saved\n",[128,721,722],{"class":130,"line":497},[128,723,190],{"emptyLinePlaceholder":189},[128,725,726,729,732,734,736,739],{"class":130,"line":508},[128,727,728],{"class":176},"print",[128,730,731],{"class":167},"(extract_all_media(",[128,733,350],{"class":138},[128,735,211],{"class":167},[128,737,738],{"class":138},"\"media_out\"",[128,740,741],{"class":167},"))\n",[10,743,744,745,211,748,751],{},"This is fast and reliable, but it loses context: files are named ",[125,746,747],{},"image1.png",[125,749,750],{},"image2.png"," in the order the writing application chose, and one\npicture used in many cells appears only once. For an archive or a quick audit that is fine; for loading photos against products it is not.",[113,753,755],{"id":754},"step-2-extract-floating-images-with-their-cell-anchors","Step 2 — Extract floating images with their cell anchors",[10,757,758,759,762,763,766],{},"Floating pictures are tied to a cell through an anchor in the sheet's drawing part. openpyxl loads them onto each worksheet, where the (private but\nstable) ",[125,760,761],{},"_images"," list gives access to both the bytes and the anchor. The anchor's ",[125,764,765],{},"_from"," marker holds zero-based row and column numbers.",[118,768,770],{"className":154,"code":769,"language":156,"meta":123,"style":123},"from openpyxl import load_workbook\nfrom openpyxl.utils import get_column_letter\n\ndef extract_floating(xlsx: str, out_dir: str) -> list[dict]:\n    target = Path(out_dir)\n    target.mkdir(parents=True, exist_ok=True)\n    found = []\n    for ws in load_workbook(xlsx).worksheets:\n        for number, image in enumerate(ws._images, start=1):\n            marker = image.anchor._from\n            cell = f\"{get_column_letter(marker.col + 1)}{marker.row + 1}\"\n            path = target \u002F f\"{ws.title}_{cell}_{number}.{image.format}\"\n            path.write_bytes(image._data())\n            found.append({\"sheet\": ws.title, \"cell\": cell, \"file\": path.name})\n    return found\n\nprint(extract_floating(\"catalog.xlsx\", \"floating_out\"))\n# [{'sheet': 'Products', 'cell': 'F1', 'file': 'Products_F1_1.png'}]\n",[125,771,772,784,796,800,824,832,852,861,874,896,906,947,1000,1005,1028,1035,1039,1055],{"__ignoreMap":123},[128,773,774,776,779,781],{"class":130,"line":131},[128,775,173],{"class":163},[128,777,778],{"class":167}," openpyxl ",[128,780,164],{"class":163},[128,782,783],{"class":167}," load_workbook\n",[128,785,786,788,791,793],{"class":130,"line":170},[128,787,173],{"class":163},[128,789,790],{"class":167}," openpyxl.utils ",[128,792,164],{"class":163},[128,794,795],{"class":167}," get_column_letter\n",[128,797,798],{"class":130,"line":186},[128,799,190],{"emptyLinePlaceholder":189},[128,801,802,804,807,809,811,813,815,818,821],{"class":130,"line":193},[128,803,583],{"class":163},[128,805,806],{"class":586}," extract_floating",[128,808,590],{"class":167},[128,810,593],{"class":176},[128,812,596],{"class":167},[128,814,593],{"class":176},[128,816,817],{"class":167},") -> list[",[128,819,820],{"class":176},"dict",[128,822,823],{"class":167},"]:\n",[128,825,826,828,830],{"class":130,"line":241},[128,827,606],{"class":167},[128,829,247],{"class":163},[128,831,611],{"class":167},[128,833,834,836,838,840,842,844,846,848,850],{"class":130,"line":275},[128,835,616],{"class":167},[128,837,619],{"class":298},[128,839,247],{"class":163},[128,841,624],{"class":176},[128,843,211],{"class":167},[128,845,629],{"class":298},[128,847,247],{"class":163},[128,849,624],{"class":176},[128,851,272],{"class":167},[128,853,854,857,859],{"class":130,"line":307},[128,855,856],{"class":167},"    found ",[128,858,247],{"class":163},[128,860,645],{"class":167},[128,862,863,866,869,871],{"class":130,"line":334},[128,864,865],{"class":163},"    for",[128,867,868],{"class":167}," ws ",[128,870,202],{"class":163},[128,872,873],{"class":167}," load_workbook(xlsx).worksheets:\n",[128,875,876,878,881,883,885,888,890,892,894],{"class":130,"line":339},[128,877,664],{"class":163},[128,879,880],{"class":167}," number, image ",[128,882,202],{"class":163},[128,884,450],{"class":176},[128,886,887],{"class":167},"(ws._images, ",[128,889,475],{"class":298},[128,891,247],{"class":163},[128,893,480],{"class":176},[128,895,483],{"class":167},[128,897,898,901,903],{"class":130,"line":355},[128,899,900],{"class":167},"            marker ",[128,902,247],{"class":163},[128,904,905],{"class":167}," image.anchor._from\n",[128,907,908,911,913,916,918,920,923,926,929,932,935,938,940,942,944],{"class":130,"line":371},[128,909,910],{"class":167},"            cell ",[128,912,247],{"class":163},[128,914,915],{"class":163}," f",[128,917,316],{"class":138},[128,919,320],{"class":319},[128,921,922],{"class":167},"get_column_letter(marker.col ",[128,924,925],{"class":163},"+",[128,927,928],{"class":176}," 1",[128,930,931],{"class":167},")",[128,933,934],{"class":319},"}{",[128,936,937],{"class":167},"marker.row ",[128,939,925],{"class":163},[128,941,928],{"class":176},[128,943,326],{"class":319},[128,945,946],{"class":138},"\"\n",[128,948,949,952,954,956,958,960,962,964,967,969,972,974,977,979,981,983,986,988,991,993,996,998],{"class":130,"line":409},[128,950,951],{"class":167},"            path ",[128,953,247],{"class":163},[128,955,695],{"class":167},[128,957,698],{"class":163},[128,959,915],{"class":163},[128,961,316],{"class":138},[128,963,320],{"class":319},[128,965,966],{"class":167},"ws.title",[128,968,326],{"class":319},[128,970,971],{"class":138},"_",[128,973,320],{"class":319},[128,975,976],{"class":167},"cell",[128,978,326],{"class":319},[128,980,971],{"class":138},[128,982,320],{"class":319},[128,984,985],{"class":167},"number",[128,987,326],{"class":319},[128,989,990],{"class":138},".",[128,992,320],{"class":319},[128,994,995],{"class":167},"image.format",[128,997,326],{"class":319},[128,999,946],{"class":138},[128,1001,1002],{"class":130,"line":440},[128,1003,1004],{"class":167},"            path.write_bytes(image._data())\n",[128,1006,1007,1010,1013,1016,1019,1022,1025],{"class":130,"line":486},[128,1008,1009],{"class":167},"            found.append({",[128,1011,1012],{"class":138},"\"sheet\"",[128,1014,1015],{"class":167},": ws.title, ",[128,1017,1018],{"class":138},"\"cell\"",[128,1020,1021],{"class":167},": cell, ",[128,1023,1024],{"class":138},"\"file\"",[128,1026,1027],{"class":167},": path.name})\n",[128,1029,1030,1032],{"class":130,"line":497},[128,1031,716],{"class":163},[128,1033,1034],{"class":167}," found\n",[128,1036,1037],{"class":130,"line":508},[128,1038,190],{"emptyLinePlaceholder":189},[128,1040,1041,1043,1046,1048,1050,1053],{"class":130,"line":533},[128,1042,728],{"class":176},[128,1044,1045],{"class":167},"(extract_floating(",[128,1047,350],{"class":138},[128,1049,211],{"class":167},[128,1051,1052],{"class":138},"\"floating_out\"",[128,1054,741],{"class":167},[128,1056,1058],{"class":130,"line":1057},18,[128,1059,1061],{"class":1060},"s-wDw","# [{'sheet': 'Products', 'cell': 'F1', 'file': 'Products_F1_1.png'}]\n",[10,1063,1064],{},"The anchor is the top-left cell the picture is attached to, which is what a person means by \"the picture in F1\". A picture that spans several cells still\nreports only its top-left corner. openpyxl needs Pillow installed to load images at all; without it, the images are silently skipped.",[20,1066,29,1072,29,1075,29,1078,29,1082,29,1086,29,1091,29,1095,29,1099,29,1102,29,1107,29,1112,29,1117,29,1122,29,1127,29,1131,29,1133,29,1136,29,1139,29,1143,29,1147,29,1150,29,1153,29,1155,29,1158,29,1161,29,1165,29,1168,29,1171,29,1174],{"viewBox":1067,"role":23,"ariaLabelledBy":1068,"xmlns":27,"style":1071},"0 0 760 282",[1069,1070],"ext-choose-t","ext-choose-d","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[31,1073,1074],{"id":1069},"Choosing an extraction method",[35,1076,1077],{"id":1070},"If you only need the image files, read xl\u002Fmedia from the zip. If you need to know which cell a floating picture is attached to, use openpyxl image anchors. If pictures are placed inside cells, follow the cell metadata to the rich value relationships.",[39,1079],{"x":41,"y":41,"width":1080,"height":1081,"fill":44},"760","282",[39,1083],{"x":1084,"y":47,"width":1085,"height":49,"rx":50,"fill":96,"stroke":97,"style":53},"230","300",[55,1087,1090],{"x":1088,"y":49,"style":1089},"380","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","what do you need to know?",[130,1092],{"x1":1088,"y1":1093,"x2":1088,"y2":1094,"stroke":97,"style":53},"72","100",[130,1096],{"x1":1097,"y1":1094,"x2":1098,"y2":1094,"stroke":97,"style":53},"133.3","626.7",[130,1100],{"x1":1097,"y1":1094,"x2":1097,"y2":1101,"stroke":97,"style":53},"124",[1103,1104],"polygon",{"points":1105,"fill":1106},"133.3,127 128.3,118 138.3,118","#5b5cf0",[39,1108],{"x":47,"y":1109,"width":1110,"height":1111,"rx":50,"fill":69,"stroke":70,"style":53},"128","226.7","104",[55,1113,1116],{"x":1097,"y":1114,"style":1115},"150","font-size:11px;font-weight:600;fill:var(--teal-ink,#0b6157);text-anchor:middle","just the files",[55,1118,1121],{"x":1097,"y":1119,"style":1120},"174","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","zip xl\u002Fmedia",[55,1123,1126],{"x":1097,"y":1124,"style":1125},"196","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","fast, no context,",[55,1128,1130],{"x":1097,"y":1129,"style":1125},"216","duplicates merged",[130,1132],{"x1":1088,"y1":1094,"x2":1088,"y2":1101,"stroke":97,"style":53},[1103,1134],{"points":1135,"fill":1106},"380,127 375,118 385,118",[39,1137],{"x":1138,"y":1109,"width":1110,"height":1111,"rx":50,"fill":83,"stroke":84,"style":53},"266.7",[55,1140,1142],{"x":1088,"y":1114,"style":1141},"font-size:11px;font-weight:600;fill:var(--gold-ink,#7a4e06);text-anchor:middle","floating picture cell",[55,1144,1146],{"x":1088,"y":1119,"style":1145},"font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","openpyxl anchors",[55,1148,1149],{"x":1088,"y":1124,"style":1125},"ws._images,",[55,1151,1152],{"x":1088,"y":1129,"style":1125},"anchor._from",[130,1154],{"x1":1098,"y1":1094,"x2":1098,"y2":1101,"stroke":97,"style":53},[1103,1156],{"points":1157,"fill":1106},"626.7,127 621.7,118 631.7,118",[39,1159],{"x":1160,"y":1109,"width":1110,"height":1111,"rx":50,"fill":96,"stroke":97,"style":53},"513.3",[55,1162,1164],{"x":1098,"y":1114,"style":1163},"font-size:11px;font-weight:600;fill:var(--brand-strong,#4338ca);text-anchor:middle","picture in a cell",[55,1166,1167],{"x":1098,"y":1119,"style":1089},"rich value parts",[55,1169,1170],{"x":1098,"y":1124,"style":1125},"vm attribute →",[55,1172,1173],{"x":1098,"y":1129,"style":1125},"metadata → media",[55,1175,1177],{"x":1088,"y":1176,"style":110},"266","openpyxl does not see pictures placed in cells",[113,1179,1181],{"id":1180},"step-3-map-pictures-in-cells-to-their-cells","Step 3 — Map pictures in cells to their cells",[10,1183,1184,1185,1188,1189,1192,1193,1196,1197,1200,1201,1204,1205,1208,1209,1212,1213,1216],{},"Pictures placed ",[1186,1187,202],"em",{}," cells are invisible to openpyxl: the cell's value reads as ",[125,1190,1191],{},"#VALUE!"," and there is no image object. The link from cell to picture runs\nthrough four small XML parts. The cell carries a ",[125,1194,1195],{},"vm"," attribute (value metadata index, one-based); ",[125,1198,1199],{},"xl\u002Fmetadata.xml"," maps that to a rich value index;\n",[125,1202,1203],{},"xl\u002FrichData\u002Frdrichvalue.xml"," gives the relationship index for that rich value; and ",[125,1206,1207],{},"xl\u002FrichData\u002FrichValueRel.xml"," with its ",[125,1210,1211],{},".rels"," file resolves that to a\nmedia file. Following the chain with ",[125,1214,1215],{},"xml.etree"," is short.",[118,1218,1220],{"className":154,"code":1219,"language":156,"meta":123,"style":123},"import re\nimport xml.etree.ElementTree as ET\n\nNS = {\n    \"m\": \"http:\u002F\u002Fschemas.openxmlformats.org\u002Fspreadsheetml\u002F2006\u002Fmain\",\n    \"rd\": \"http:\u002F\u002Fschemas.microsoft.com\u002Foffice\u002Fspreadsheetml\u002F2017\u002Frichdata\",\n    \"rv\": \"http:\u002F\u002Fschemas.microsoft.com\u002Foffice\u002Fspreadsheetml\u002F2022\u002Frichvaluerel\",\n    \"r\": \"http:\u002F\u002Fschemas.openxmlformats.org\u002FofficeDocument\u002F2006\u002Frelationships\",\n    \"pr\": \"http:\u002F\u002Fschemas.openxmlformats.org\u002Fpackage\u002F2006\u002Frelationships\",\n}\n\ndef in_cell_image_map(xlsx: str, sheet_part: str = \"xl\u002Fworksheets\u002Fsheet1.xml\") -> dict[str, str]:\n    with zipfile.ZipFile(xlsx) as z:\n        names = set(z.namelist())\n        if \"xl\u002FrichData\u002Frdrichvalue.xml\" not in names:\n            return {}\n        meta = ET.fromstring(z.read(\"xl\u002Fmetadata.xml\"))\n        future = [bk.find(\".\u002F\u002Frd:rvb\", NS).get(\"i\") for bk in meta.find(\"m:futureMetadata\", NS).findall(\"m:bk\", NS)]\n        value_meta = [int(bk.find(\"m:rc\", NS).get(\"v\")) for bk in meta.find(\"m:valueMetadata\", NS).findall(\"m:bk\", NS)]\n\n        structures = ET.fromstring(z.read(\"xl\u002FrichData\u002Frdrichvaluestructure.xml\")).findall(\"rd:s\", NS)\n        values = ET.fromstring(z.read(\"xl\u002FrichData\u002Frdrichvalue.xml\")).findall(\"rd:rv\", NS)\n        rel_ids = [rel.get(f\"{{{NS['r']}}}id\") for rel in ET.fromstring(z.read(\"xl\u002FrichData\u002FrichValueRel.xml\"))]\n        targets = {rel.get(\"Id\"): rel.get(\"Target\")\n                   for rel in ET.fromstring(z.read(\"xl\u002FrichData\u002F_rels\u002FrichValueRel.xml.rels\")).findall(\"pr:Relationship\", NS)}\n\n        sheet_xml = z.read(sheet_part).decode(\"utf-8\")\n        mapping = {}\n        for ref, vm in re.findall(r'\u003Cc r=\"([A-Z]+[0-9]+)\"[^>]*\\bvm=\"([0-9]+)\"', sheet_xml):\n            rich_index = int(future[value_meta[int(vm) - 1]])\n            rich_value = values[rich_index]\n            keys = [k.get(\"n\") for k in structures[int(rich_value.get(\"s\"))].findall(\"rd:k\", NS)]\n            rel_position = int(rich_value.findall(\"rd:v\", NS)[keys.index(\"_rvRel:LocalImageIdentifier\")].text)\n            mapping[ref] = \"xl\u002F\" + targets[rel_ids[rel_position]].replace(\"..\u002F\", \"\")\n        return mapping\n\nprint(in_cell_image_map(\"catalog.xlsx\"))\n# {'C2': 'xl\u002Fmedia\u002Fimage1.png', 'C3': 'xl\u002Fmedia\u002Fimage2.png'}\n",[125,1221,1222,1229,1241,1245,1256,1269,1281,1293,1305,1317,1322,1326,1358,1369,1382,1399,1407,1425,1481,1538,1543,1570,1596,1650,1672,1701,1706,1722,1732,1809,1836,1847,1893,1922,1949,1958,1963,1975],{"__ignoreMap":123},[128,1223,1224,1226],{"class":130,"line":131},[128,1225,164],{"class":163},[128,1227,1228],{"class":167}," re\n",[128,1230,1231,1233,1236,1238],{"class":130,"line":170},[128,1232,164],{"class":163},[128,1234,1235],{"class":167}," xml.etree.ElementTree ",[128,1237,656],{"class":163},[128,1239,1240],{"class":176}," ET\n",[128,1242,1243],{"class":130,"line":186},[128,1244,190],{"emptyLinePlaceholder":189},[128,1246,1247,1250,1253],{"class":130,"line":193},[128,1248,1249],{"class":176},"NS",[128,1251,1252],{"class":163}," =",[128,1254,1255],{"class":167}," {\n",[128,1257,1258,1261,1263,1266],{"class":130,"line":241},[128,1259,1260],{"class":138},"    \"m\"",[128,1262,391],{"class":167},[128,1264,1265],{"class":138},"\"http:\u002F\u002Fschemas.openxmlformats.org\u002Fspreadsheetml\u002F2006\u002Fmain\"",[128,1267,1268],{"class":167},",\n",[128,1270,1271,1274,1276,1279],{"class":130,"line":275},[128,1272,1273],{"class":138},"    \"rd\"",[128,1275,391],{"class":167},[128,1277,1278],{"class":138},"\"http:\u002F\u002Fschemas.microsoft.com\u002Foffice\u002Fspreadsheetml\u002F2017\u002Frichdata\"",[128,1280,1268],{"class":167},[128,1282,1283,1286,1288,1291],{"class":130,"line":307},[128,1284,1285],{"class":138},"    \"rv\"",[128,1287,391],{"class":167},[128,1289,1290],{"class":138},"\"http:\u002F\u002Fschemas.microsoft.com\u002Foffice\u002Fspreadsheetml\u002F2022\u002Frichvaluerel\"",[128,1292,1268],{"class":167},[128,1294,1295,1298,1300,1303],{"class":130,"line":334},[128,1296,1297],{"class":138},"    \"r\"",[128,1299,391],{"class":167},[128,1301,1302],{"class":138},"\"http:\u002F\u002Fschemas.openxmlformats.org\u002FofficeDocument\u002F2006\u002Frelationships\"",[128,1304,1268],{"class":167},[128,1306,1307,1310,1312,1315],{"class":130,"line":339},[128,1308,1309],{"class":138},"    \"pr\"",[128,1311,391],{"class":167},[128,1313,1314],{"class":138},"\"http:\u002F\u002Fschemas.openxmlformats.org\u002Fpackage\u002F2006\u002Frelationships\"",[128,1316,1268],{"class":167},[128,1318,1319],{"class":130,"line":355},[128,1320,1321],{"class":167},"}\n",[128,1323,1324],{"class":130,"line":371},[128,1325,190],{"emptyLinePlaceholder":189},[128,1327,1328,1330,1333,1335,1337,1340,1342,1344,1347,1350,1352,1354,1356],{"class":130,"line":409},[128,1329,583],{"class":163},[128,1331,1332],{"class":586}," in_cell_image_map",[128,1334,590],{"class":167},[128,1336,593],{"class":176},[128,1338,1339],{"class":167},", sheet_part: ",[128,1341,593],{"class":176},[128,1343,1252],{"class":163},[128,1345,1346],{"class":138}," \"xl\u002Fworksheets\u002Fsheet1.xml\"",[128,1348,1349],{"class":167},") -> dict[",[128,1351,593],{"class":176},[128,1353,211],{"class":167},[128,1355,593],{"class":176},[128,1357,823],{"class":167},[128,1359,1360,1362,1364,1366],{"class":130,"line":440},[128,1361,650],{"class":163},[128,1363,653],{"class":167},[128,1365,656],{"class":163},[128,1367,1368],{"class":167}," z:\n",[128,1370,1371,1374,1376,1379],{"class":130,"line":486},[128,1372,1373],{"class":167},"        names ",[128,1375,247],{"class":163},[128,1377,1378],{"class":176}," set",[128,1380,1381],{"class":167},"(z.namelist())\n",[128,1383,1384,1387,1390,1393,1396],{"class":130,"line":497},[128,1385,1386],{"class":163},"        if",[128,1388,1389],{"class":138}," \"xl\u002FrichData\u002Frdrichvalue.xml\"",[128,1391,1392],{"class":163}," not",[128,1394,1395],{"class":163}," in",[128,1397,1398],{"class":167}," names:\n",[128,1400,1401,1404],{"class":130,"line":508},[128,1402,1403],{"class":163},"            return",[128,1405,1406],{"class":167}," {}\n",[128,1408,1409,1412,1414,1417,1420,1423],{"class":130,"line":533},[128,1410,1411],{"class":167},"        meta ",[128,1413,247],{"class":163},[128,1415,1416],{"class":176}," ET",[128,1418,1419],{"class":167},".fromstring(z.read(",[128,1421,1422],{"class":138},"\"xl\u002Fmetadata.xml\"",[128,1424,741],{"class":167},[128,1426,1427,1430,1432,1435,1438,1440,1442,1445,1448,1451,1453,1456,1458,1461,1464,1466,1468,1471,1474,1476,1478],{"class":130,"line":1057},[128,1428,1429],{"class":167},"        future ",[128,1431,247],{"class":163},[128,1433,1434],{"class":167}," [bk.find(",[128,1436,1437],{"class":138},"\".\u002F\u002Frd:rvb\"",[128,1439,211],{"class":167},[128,1441,1249],{"class":176},[128,1443,1444],{"class":167},").get(",[128,1446,1447],{"class":138},"\"i\"",[128,1449,1450],{"class":167},") ",[128,1452,196],{"class":163},[128,1454,1455],{"class":167}," bk ",[128,1457,202],{"class":163},[128,1459,1460],{"class":167}," meta.find(",[128,1462,1463],{"class":138},"\"m:futureMetadata\"",[128,1465,211],{"class":167},[128,1467,1249],{"class":176},[128,1469,1470],{"class":167},").findall(",[128,1472,1473],{"class":138},"\"m:bk\"",[128,1475,211],{"class":167},[128,1477,1249],{"class":176},[128,1479,1480],{"class":167},")]\n",[128,1482,1484,1487,1489,1492,1495,1498,1501,1503,1505,1507,1510,1513,1515,1517,1519,1521,1524,1526,1528,1530,1532,1534,1536],{"class":130,"line":1483},19,[128,1485,1486],{"class":167},"        value_meta ",[128,1488,247],{"class":163},[128,1490,1491],{"class":167}," [",[128,1493,1494],{"class":176},"int",[128,1496,1497],{"class":167},"(bk.find(",[128,1499,1500],{"class":138},"\"m:rc\"",[128,1502,211],{"class":167},[128,1504,1249],{"class":176},[128,1506,1444],{"class":167},[128,1508,1509],{"class":138},"\"v\"",[128,1511,1512],{"class":167},")) ",[128,1514,196],{"class":163},[128,1516,1455],{"class":167},[128,1518,202],{"class":163},[128,1520,1460],{"class":167},[128,1522,1523],{"class":138},"\"m:valueMetadata\"",[128,1525,211],{"class":167},[128,1527,1249],{"class":176},[128,1529,1470],{"class":167},[128,1531,1473],{"class":138},[128,1533,211],{"class":167},[128,1535,1249],{"class":176},[128,1537,1480],{"class":167},[128,1539,1541],{"class":130,"line":1540},20,[128,1542,190],{"emptyLinePlaceholder":189},[128,1544,1546,1549,1551,1553,1555,1558,1561,1564,1566,1568],{"class":130,"line":1545},21,[128,1547,1548],{"class":167},"        structures ",[128,1550,247],{"class":163},[128,1552,1416],{"class":176},[128,1554,1419],{"class":167},[128,1556,1557],{"class":138},"\"xl\u002FrichData\u002Frdrichvaluestructure.xml\"",[128,1559,1560],{"class":167},")).findall(",[128,1562,1563],{"class":138},"\"rd:s\"",[128,1565,211],{"class":167},[128,1567,1249],{"class":176},[128,1569,272],{"class":167},[128,1571,1573,1576,1578,1580,1582,1585,1587,1590,1592,1594],{"class":130,"line":1572},22,[128,1574,1575],{"class":167},"        values ",[128,1577,247],{"class":163},[128,1579,1416],{"class":176},[128,1581,1419],{"class":167},[128,1583,1584],{"class":138},"\"xl\u002FrichData\u002Frdrichvalue.xml\"",[128,1586,1560],{"class":167},[128,1588,1589],{"class":138},"\"rd:rv\"",[128,1591,211],{"class":167},[128,1593,1249],{"class":176},[128,1595,272],{"class":167},[128,1597,1599,1602,1604,1607,1609,1611,1614,1616,1619,1622,1625,1628,1631,1633,1635,1638,1640,1642,1644,1647],{"class":130,"line":1598},23,[128,1600,1601],{"class":167},"        rel_ids ",[128,1603,247],{"class":163},[128,1605,1606],{"class":167}," [rel.get(",[128,1608,313],{"class":163},[128,1610,316],{"class":138},[128,1612,1613],{"class":319},"{{{",[128,1615,1249],{"class":176},[128,1617,1618],{"class":167},"[",[128,1620,1621],{"class":138},"'r'",[128,1623,1624],{"class":167},"]",[128,1626,1627],{"class":319},"}}}",[128,1629,1630],{"class":138},"id\"",[128,1632,1450],{"class":167},[128,1634,196],{"class":163},[128,1636,1637],{"class":167}," rel ",[128,1639,202],{"class":163},[128,1641,1416],{"class":176},[128,1643,1419],{"class":167},[128,1645,1646],{"class":138},"\"xl\u002FrichData\u002FrichValueRel.xml\"",[128,1648,1649],{"class":167},"))]\n",[128,1651,1653,1656,1658,1661,1664,1667,1670],{"class":130,"line":1652},24,[128,1654,1655],{"class":167},"        targets ",[128,1657,247],{"class":163},[128,1659,1660],{"class":167}," {rel.get(",[128,1662,1663],{"class":138},"\"Id\"",[128,1665,1666],{"class":167},"): rel.get(",[128,1668,1669],{"class":138},"\"Target\"",[128,1671,272],{"class":167},[128,1673,1675,1678,1680,1682,1684,1686,1689,1691,1694,1696,1698],{"class":130,"line":1674},25,[128,1676,1677],{"class":163},"                   for",[128,1679,1637],{"class":167},[128,1681,202],{"class":163},[128,1683,1416],{"class":176},[128,1685,1419],{"class":167},[128,1687,1688],{"class":138},"\"xl\u002FrichData\u002F_rels\u002FrichValueRel.xml.rels\"",[128,1690,1560],{"class":167},[128,1692,1693],{"class":138},"\"pr:Relationship\"",[128,1695,211],{"class":167},[128,1697,1249],{"class":176},[128,1699,1700],{"class":167},")}\n",[128,1702,1704],{"class":130,"line":1703},26,[128,1705,190],{"emptyLinePlaceholder":189},[128,1707,1709,1712,1714,1717,1720],{"class":130,"line":1708},27,[128,1710,1711],{"class":167},"        sheet_xml ",[128,1713,247],{"class":163},[128,1715,1716],{"class":167}," z.read(sheet_part).decode(",[128,1718,1719],{"class":138},"\"utf-8\"",[128,1721,272],{"class":167},[128,1723,1725,1728,1730],{"class":130,"line":1724},28,[128,1726,1727],{"class":167},"        mapping ",[128,1729,247],{"class":163},[128,1731,1406],{"class":167},[128,1733,1735,1737,1740,1742,1745,1748,1751,1754,1757,1759,1761,1763,1766,1768,1770,1772,1774,1776,1779,1782,1784,1787,1790,1793,1795,1797,1799,1801,1803,1806],{"class":130,"line":1734},29,[128,1736,664],{"class":163},[128,1738,1739],{"class":167}," ref, vm ",[128,1741,202],{"class":163},[128,1743,1744],{"class":167}," re.findall(",[128,1746,1747],{"class":163},"r",[128,1749,1750],{"class":138},"'\u003Cc r=\"",[128,1752,1753],{"class":176},"([",[128,1755,1756],{"class":319},"A-Z",[128,1758,1624],{"class":176},[128,1760,925],{"class":163},[128,1762,1618],{"class":176},[128,1764,1765],{"class":319},"0-9",[128,1767,1624],{"class":176},[128,1769,925],{"class":163},[128,1771,931],{"class":176},[128,1773,316],{"class":138},[128,1775,1618],{"class":176},[128,1777,1778],{"class":163},"^",[128,1780,1781],{"class":319},">",[128,1783,1624],{"class":176},[128,1785,1786],{"class":163},"*",[128,1788,1789],{"class":176},"\\b",[128,1791,1792],{"class":138},"vm=\"",[128,1794,1753],{"class":176},[128,1796,1765],{"class":319},[128,1798,1624],{"class":176},[128,1800,925],{"class":163},[128,1802,931],{"class":176},[128,1804,1805],{"class":138},"\"'",[128,1807,1808],{"class":167},", sheet_xml):\n",[128,1810,1812,1815,1817,1820,1823,1825,1828,1831,1833],{"class":130,"line":1811},30,[128,1813,1814],{"class":167},"            rich_index ",[128,1816,247],{"class":163},[128,1818,1819],{"class":176}," int",[128,1821,1822],{"class":167},"(future[value_meta[",[128,1824,1494],{"class":176},[128,1826,1827],{"class":167},"(vm) ",[128,1829,1830],{"class":163},"-",[128,1832,928],{"class":176},[128,1834,1835],{"class":167},"]])\n",[128,1837,1839,1842,1844],{"class":130,"line":1838},31,[128,1840,1841],{"class":167},"            rich_value ",[128,1843,247],{"class":163},[128,1845,1846],{"class":167}," values[rich_index]\n",[128,1848,1850,1853,1855,1858,1861,1863,1865,1868,1870,1873,1875,1878,1881,1884,1887,1889,1891],{"class":130,"line":1849},32,[128,1851,1852],{"class":167},"            keys ",[128,1854,247],{"class":163},[128,1856,1857],{"class":167}," [k.get(",[128,1859,1860],{"class":138},"\"n\"",[128,1862,1450],{"class":167},[128,1864,196],{"class":163},[128,1866,1867],{"class":167}," k ",[128,1869,202],{"class":163},[128,1871,1872],{"class":167}," structures[",[128,1874,1494],{"class":176},[128,1876,1877],{"class":167},"(rich_value.get(",[128,1879,1880],{"class":138},"\"s\"",[128,1882,1883],{"class":167},"))].findall(",[128,1885,1886],{"class":138},"\"rd:k\"",[128,1888,211],{"class":167},[128,1890,1249],{"class":176},[128,1892,1480],{"class":167},[128,1894,1896,1899,1901,1903,1906,1909,1911,1913,1916,1919],{"class":130,"line":1895},33,[128,1897,1898],{"class":167},"            rel_position ",[128,1900,247],{"class":163},[128,1902,1819],{"class":176},[128,1904,1905],{"class":167},"(rich_value.findall(",[128,1907,1908],{"class":138},"\"rd:v\"",[128,1910,211],{"class":167},[128,1912,1249],{"class":176},[128,1914,1915],{"class":167},")[keys.index(",[128,1917,1918],{"class":138},"\"_rvRel:LocalImageIdentifier\"",[128,1920,1921],{"class":167},")].text)\n",[128,1923,1925,1928,1930,1933,1936,1939,1942,1944,1947],{"class":130,"line":1924},34,[128,1926,1927],{"class":167},"            mapping[ref] ",[128,1929,247],{"class":163},[128,1931,1932],{"class":138}," \"xl\u002F\"",[128,1934,1935],{"class":163}," +",[128,1937,1938],{"class":167}," targets[rel_ids[rel_position]].replace(",[128,1940,1941],{"class":138},"\"..\u002F\"",[128,1943,211],{"class":167},[128,1945,1946],{"class":138},"\"\"",[128,1948,272],{"class":167},[128,1950,1952,1955],{"class":130,"line":1951},35,[128,1953,1954],{"class":163},"        return",[128,1956,1957],{"class":167}," mapping\n",[128,1959,1961],{"class":130,"line":1960},36,[128,1962,190],{"emptyLinePlaceholder":189},[128,1964,1966,1968,1971,1973],{"class":130,"line":1965},37,[128,1967,728],{"class":176},[128,1969,1970],{"class":167},"(in_cell_image_map(",[128,1972,350],{"class":138},[128,1974,741],{"class":167},[128,1976,1978],{"class":130,"line":1977},38,[128,1979,1980],{"class":1060},"# {'C2': 'xl\u002Fmedia\u002Fimage1.png', 'C3': 'xl\u002Fmedia\u002Fimage2.png'}\n",[10,1982,1983,1984,1987,1988,1991,1992,1995],{},"Notice that the media file numbers say nothing about position: here the in-cell pictures took ",[125,1985,1986],{},"image1"," and ",[125,1989,1990],{},"image2"," and the floating logo\ntook ",[125,1993,1994],{},"image3",", purely because of the order in which the writing library stored them. Another application saving the same workbook could\nrenumber everything. That is the whole reason to follow the chain from the cell rather than guessing from file names.",[10,1997,1998,1999,2002,2003,2006,2007,990],{},"The lookup of ",[125,2000,2001],{},"_rvRel:LocalImageIdentifier"," by name in the value's structure, rather than assuming it is the first value, keeps the function working for\nfiles saved by Excel as well as by xlsxwriter, since the order of keys in a structure is not guaranteed. The ",[125,2004,2005],{},"sheet_part"," argument names the worksheet's XML\npart; for workbooks with several sheets, resolve each sheet's part from ",[125,2008,2009],{},"xl\u002F_rels\u002Fworkbook.xml.rels",[113,2011,2013],{"id":2012},"step-4-save-files-named-after-the-row-they-belong-to","Step 4 — Save files named after the row they belong to",[10,2015,2016],{},"With a map from cell to media path, extraction can name each file after something meaningful in the same row — a SKU, an employee ID, a receipt number — which\nis what a downstream import needs.",[118,2018,2020],{"className":154,"code":2019,"language":156,"meta":123,"style":123},"def extract_by_key(xlsx: str, key_column: str, out_dir: str) -> list[str]:\n    target = Path(out_dir)\n    target.mkdir(parents=True, exist_ok=True)\n    sheet = load_workbook(xlsx).worksheets[0]\n    written = []\n    with zipfile.ZipFile(xlsx) as z:\n        for ref, media in in_cell_image_map(xlsx).items():\n            row = int(re.sub(r\"[A-Z]+\", \"\", ref))\n            key = sheet[f\"{key_column}{row}\"].value or f\"row{row}\"\n            path = target \u002F f\"{key}{Path(media).suffix}\"\n            path.write_bytes(z.read(media))\n            written.append(path.name)\n    return written\n\nprint(extract_by_key(\"catalog.xlsx\", \"A\", \"photos_by_sku\"))\n# ['W-100.png', 'G-200.png']\n",[125,2021,2022,2048,2056,2076,2091,2100,2110,2122,2155,2202,2230,2235,2240,2247,2251,2272],{"__ignoreMap":123},[128,2023,2024,2026,2029,2031,2033,2036,2038,2040,2042,2044,2046],{"class":130,"line":131},[128,2025,583],{"class":163},[128,2027,2028],{"class":586}," extract_by_key",[128,2030,590],{"class":167},[128,2032,593],{"class":176},[128,2034,2035],{"class":167},", key_column: ",[128,2037,593],{"class":176},[128,2039,596],{"class":167},[128,2041,593],{"class":176},[128,2043,817],{"class":167},[128,2045,593],{"class":176},[128,2047,823],{"class":167},[128,2049,2050,2052,2054],{"class":130,"line":170},[128,2051,606],{"class":167},[128,2053,247],{"class":163},[128,2055,611],{"class":167},[128,2057,2058,2060,2062,2064,2066,2068,2070,2072,2074],{"class":130,"line":186},[128,2059,616],{"class":167},[128,2061,619],{"class":298},[128,2063,247],{"class":163},[128,2065,624],{"class":176},[128,2067,211],{"class":167},[128,2069,629],{"class":298},[128,2071,247],{"class":163},[128,2073,624],{"class":176},[128,2075,272],{"class":167},[128,2077,2078,2081,2083,2086,2088],{"class":130,"line":193},[128,2079,2080],{"class":167},"    sheet ",[128,2082,247],{"class":163},[128,2084,2085],{"class":167}," load_workbook(xlsx).worksheets[",[128,2087,41],{"class":176},[128,2089,2090],{"class":167},"]\n",[128,2092,2093,2096,2098],{"class":130,"line":241},[128,2094,2095],{"class":167},"    written ",[128,2097,247],{"class":163},[128,2099,645],{"class":167},[128,2101,2102,2104,2106,2108],{"class":130,"line":275},[128,2103,650],{"class":163},[128,2105,653],{"class":167},[128,2107,656],{"class":163},[128,2109,1368],{"class":167},[128,2111,2112,2114,2117,2119],{"class":130,"line":307},[128,2113,664],{"class":163},[128,2115,2116],{"class":167}," ref, media ",[128,2118,202],{"class":163},[128,2120,2121],{"class":167}," in_cell_image_map(xlsx).items():\n",[128,2123,2124,2127,2129,2131,2134,2136,2138,2140,2142,2144,2146,2148,2150,2152],{"class":130,"line":334},[128,2125,2126],{"class":167},"            row ",[128,2128,247],{"class":163},[128,2130,1819],{"class":176},[128,2132,2133],{"class":167},"(re.sub(",[128,2135,1747],{"class":163},[128,2137,316],{"class":138},[128,2139,1618],{"class":176},[128,2141,1756],{"class":319},[128,2143,1624],{"class":176},[128,2145,925],{"class":163},[128,2147,316],{"class":138},[128,2149,211],{"class":167},[128,2151,1946],{"class":138},[128,2153,2154],{"class":167},", ref))\n",[128,2156,2157,2160,2162,2165,2167,2169,2171,2174,2176,2179,2181,2183,2186,2189,2191,2194,2196,2198,2200],{"class":130,"line":339},[128,2158,2159],{"class":167},"            key ",[128,2161,247],{"class":163},[128,2163,2164],{"class":167}," sheet[",[128,2166,313],{"class":163},[128,2168,316],{"class":138},[128,2170,320],{"class":319},[128,2172,2173],{"class":167},"key_column",[128,2175,934],{"class":319},[128,2177,2178],{"class":167},"row",[128,2180,326],{"class":319},[128,2182,316],{"class":138},[128,2184,2185],{"class":167},"].value ",[128,2187,2188],{"class":163},"or",[128,2190,915],{"class":163},[128,2192,2193],{"class":138},"\"row",[128,2195,320],{"class":319},[128,2197,2178],{"class":167},[128,2199,326],{"class":319},[128,2201,946],{"class":138},[128,2203,2204,2206,2208,2210,2212,2214,2216,2218,2221,2223,2226,2228],{"class":130,"line":355},[128,2205,951],{"class":167},[128,2207,247],{"class":163},[128,2209,695],{"class":167},[128,2211,698],{"class":163},[128,2213,915],{"class":163},[128,2215,316],{"class":138},[128,2217,320],{"class":319},[128,2219,2220],{"class":167},"key",[128,2222,934],{"class":319},[128,2224,2225],{"class":167},"Path(media).suffix",[128,2227,326],{"class":319},[128,2229,946],{"class":138},[128,2231,2232],{"class":130,"line":371},[128,2233,2234],{"class":167},"            path.write_bytes(z.read(media))\n",[128,2236,2237],{"class":130,"line":409},[128,2238,2239],{"class":167},"            written.append(path.name)\n",[128,2241,2242,2244],{"class":130,"line":440},[128,2243,716],{"class":163},[128,2245,2246],{"class":167}," written\n",[128,2248,2249],{"class":130,"line":486},[128,2250,190],{"emptyLinePlaceholder":189},[128,2252,2253,2255,2258,2260,2262,2265,2267,2270],{"class":130,"line":497},[128,2254,728],{"class":176},[128,2256,2257],{"class":167},"(extract_by_key(",[128,2259,350],{"class":138},[128,2261,211],{"class":167},[128,2263,2264],{"class":138},"\"A\"",[128,2266,211],{"class":167},[128,2268,2269],{"class":138},"\"photos_by_sku\"",[128,2271,741],{"class":167},[128,2273,2274],{"class":130,"line":508},[128,2275,2276],{"class":1060},"# ['W-100.png', 'G-200.png']\n",[10,2278,2279],{},"Sanitise the key before using it in a filename if it can contain slashes or other characters that paths do not allow. And check for duplicates: two rows with the\nsame SKU would overwrite each other's photo, which is itself a data problem worth reporting.",[20,2281,29,2286,29,2289,29,2292,29,2295,29,2298,29,2304,29,2308,29,2313,29,2316,29,2319,29,2323,29,2326,29,2330,29,2333,29,2336,29,2340,29,2343,29,2347,29,2350,29,2353,29,2357,29,2359],{"viewBox":2282,"role":23,"ariaLabelledBy":2283,"xmlns":27,"style":1071},"0 0 760 136",[2284,2285],"ext-chain-t","ext-chain-d",[31,2287,2288],{"id":2284},"Following an in-cell picture from its cell to the image file",[35,2290,2291],{"id":2285},"The cell carries a vm attribute, metadata maps it to a rich value index, the rich value gives a relationship position, and the relationship file points at an image in the media folder.",[39,2293],{"x":41,"y":41,"width":1080,"height":2294,"fill":44},"136",[39,2296],{"x":47,"y":47,"width":1114,"height":2297,"rx":50,"fill":51,"stroke":52,"style":53},"66",[55,2299,2303],{"x":2300,"y":2301,"style":2302},"95","50","font-size:14px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","cell C2",[55,2305,2307],{"x":2300,"y":1093,"style":2306},"font-size:11.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","vm=\"1\"",[130,2309],{"x1":2310,"y1":2311,"x2":2312,"y2":2311,"stroke":97,"style":53},"175","53","204",[1103,2314],{"points":2315,"fill":1106},"207,53 198,48 198,58",[39,2317],{"x":2318,"y":47,"width":1114,"height":2297,"rx":50,"fill":96,"stroke":97,"style":53},"210",[55,2320,2322],{"x":2321,"y":2301,"style":1089},"285","metadata.xml",[55,2324,2325],{"x":2321,"y":1093,"style":1125},"value → rich index",[130,2327],{"x1":2328,"y1":2311,"x2":2329,"y2":2311,"stroke":97,"style":53},"365","394",[1103,2331],{"points":2332,"fill":1106},"397,53 388,48 388,58",[39,2334],{"x":2335,"y":47,"width":1114,"height":2297,"rx":50,"fill":96,"stroke":97,"style":53},"400",[55,2337,2339],{"x":2338,"y":2301,"style":1089},"475","rdrichvalue",[55,2341,2342],{"x":2338,"y":1093,"style":1125},"rich → rel position",[130,2344],{"x1":2345,"y1":2311,"x2":2346,"y2":2311,"stroke":97,"style":53},"555","584",[1103,2348],{"points":2349,"fill":1106},"587,53 578,48 578,58",[39,2351],{"x":2352,"y":47,"width":1114,"height":2297,"rx":50,"fill":69,"stroke":70,"style":53},"590",[55,2354,2356],{"x":2355,"y":2301,"style":1120},"665","xl\u002Fmedia",[55,2358,750],{"x":2355,"y":1093,"style":1125},[55,2360,2362],{"x":1088,"y":2361,"style":110},"120","four small XML parts link a cell to its picture",[113,2364,2366],{"id":2365},"step-5-verify-what-you-extracted","Step 5 — Verify what you extracted",[10,2368,2369],{},"Image files pulled from office documents are occasionally truncated, in an unexpected format, or far larger than they appear on screen. Open each with Pillow\nbefore handing the folder to another system, and record the dimensions alongside the key.",[118,2371,2373],{"className":154,"code":2372,"language":156,"meta":123,"style":123},"from PIL import Image\n\ndef audit(folder: str) -> list[dict]:\n    report = []\n    for path in sorted(Path(folder).iterdir()):\n        with Image.open(path) as picture:\n            picture.verify()\n        with Image.open(path) as picture:\n            report.append({\"file\": path.name, \"format\": picture.format, \"size\": picture.size})\n    return report\n\nfor entry in audit(\"photos_by_sku\"):\n    print(entry)\n",[125,2374,2375,2386,2390,2408,2417,2432,2445,2450,2460,2482,2489,2493,2509],{"__ignoreMap":123},[128,2376,2377,2379,2381,2383],{"class":130,"line":131},[128,2378,173],{"class":163},[128,2380,177],{"class":176},[128,2382,180],{"class":163},[128,2384,2385],{"class":167}," Image\n",[128,2387,2388],{"class":130,"line":170},[128,2389,190],{"emptyLinePlaceholder":189},[128,2391,2392,2394,2397,2400,2402,2404,2406],{"class":130,"line":186},[128,2393,583],{"class":163},[128,2395,2396],{"class":586}," audit",[128,2398,2399],{"class":167},"(folder: ",[128,2401,593],{"class":176},[128,2403,817],{"class":167},[128,2405,820],{"class":176},[128,2407,823],{"class":167},[128,2409,2410,2413,2415],{"class":130,"line":193},[128,2411,2412],{"class":167},"    report ",[128,2414,247],{"class":163},[128,2416,645],{"class":167},[128,2418,2419,2421,2424,2426,2429],{"class":130,"line":241},[128,2420,865],{"class":163},[128,2422,2423],{"class":167}," path ",[128,2425,202],{"class":163},[128,2427,2428],{"class":176}," sorted",[128,2430,2431],{"class":167},"(Path(folder).iterdir()):\n",[128,2433,2434,2437,2440,2442],{"class":130,"line":275},[128,2435,2436],{"class":163},"        with",[128,2438,2439],{"class":167}," Image.open(path) ",[128,2441,656],{"class":163},[128,2443,2444],{"class":167}," picture:\n",[128,2446,2447],{"class":130,"line":307},[128,2448,2449],{"class":167},"            picture.verify()\n",[128,2451,2452,2454,2456,2458],{"class":130,"line":334},[128,2453,2436],{"class":163},[128,2455,2439],{"class":167},[128,2457,656],{"class":163},[128,2459,2444],{"class":167},[128,2461,2462,2465,2467,2470,2473,2476,2479],{"class":130,"line":339},[128,2463,2464],{"class":167},"            report.append({",[128,2466,1024],{"class":138},[128,2468,2469],{"class":167},": path.name, ",[128,2471,2472],{"class":138},"\"format\"",[128,2474,2475],{"class":167},": picture.format, ",[128,2477,2478],{"class":138},"\"size\"",[128,2480,2481],{"class":167},": picture.size})\n",[128,2483,2484,2486],{"class":130,"line":355},[128,2485,716],{"class":163},[128,2487,2488],{"class":167}," report\n",[128,2490,2491],{"class":130,"line":371},[128,2492,190],{"emptyLinePlaceholder":189},[128,2494,2495,2497,2500,2502,2505,2507],{"class":130,"line":409},[128,2496,196],{"class":163},[128,2498,2499],{"class":167}," entry ",[128,2501,202],{"class":163},[128,2503,2504],{"class":167}," audit(",[128,2506,2269],{"class":138},[128,2508,483],{"class":167},[128,2510,2511,2514],{"class":130,"line":440},[128,2512,2513],{"class":176},"    print",[128,2515,2516],{"class":167},"(entry)\n",[10,2518,2519,2522],{},[125,2520,2521],{},"verify()"," detects corrupt files without decoding the whole image, but leaves the image object unusable, which is why the file is opened a second time to read\nits size.",[10,2524,2525],{},"The audit is also the natural place to compare against the sheet. Count the rows that should have a picture — every product with a SKU, every expense line above a\nthreshold — and compare with the number of files written. A catalogue where 212 of 220 products produced a photo tells you exactly which eight rows need attention,\nwhich is usually the real question behind \"can you get the pictures out of this spreadsheet?\". Writing the missing keys to a small CSV next to the image folder gives\nwhoever owns the workbook a precise list to fix, instead of a vague report that some photos are missing.",[113,2527,2529],{"id":2528},"common-pitfalls","Common pitfalls",[2531,2532,2533,2549],"table",{},[2534,2535,2536],"thead",{},[2537,2538,2539,2543,2546],"tr",{},[2540,2541,2542],"th",{},"Symptom",[2540,2544,2545],{},"Cause",[2540,2547,2548],{},"Fix",[2550,2551,2552,2567,2578,2594,2605,2623],"tbody",{},[2537,2553,2554,2561,2564],{},[2555,2556,2557,2560],"td",{},[125,2558,2559],{},"ws._images"," is empty",[2555,2562,2563],{},"Pillow not installed, or pictures are in cells",[2555,2565,2566],{},"Install Pillow; use the rich value map for in-cell pictures",[2537,2568,2569,2572,2575],{},[2555,2570,2571],{},"Fewer files than pictures on screen",[2555,2573,2574],{},"The same image is reused in several places",[2555,2576,2577],{},"Use anchors or the cell map to see every placement",[2537,2579,2580,2585,2588],{},[2555,2581,2582],{},[125,2583,2584],{},"KeyError: xl\u002Fmetadata.xml",[2555,2586,2587],{},"Workbook has no pictures in cells",[2555,2589,2590,2591,2593],{},"Check for ",[125,2592,102],{}," first, as the function does",[2537,2595,2596,2599,2602],{},[2555,2597,2598],{},"Wrong row for a floating picture",[2555,2600,2601],{},"Anchor is the top-left corner only",[2555,2603,2604],{},"Treat the anchor as the picture's owning cell",[2537,2606,2607,2617,2620],{},[2555,2608,2609,2610,2613,2614],{},"Extracted images are ",[125,2611,2612],{},".emf"," or ",[125,2615,2616],{},".wmf",[2555,2618,2619],{},"Pasted from older Office content",[2555,2621,2622],{},"Convert with a tool such as LibreOffice or Inkscape",[2537,2624,2625,2631,2634],{},[2555,2626,2627,2630],{},[125,2628,2629],{},".xls"," files yield nothing",[2555,2632,2633],{},"Legacy binary format, not a zip",[2555,2635,2636,2637,2639],{},"Convert to ",[125,2638,546],{}," first",[113,2641,2643],{"id":2642},"performance-and-scale-notes","Performance and scale notes",[10,2645,2646,2647,2650],{},"Reading from the zip archive is fast regardless of workbook size, because the media files are read directly without parsing any cell data. The openpyxl route loads\nevery cell of every sheet, which is slow for large workbooks when all you want is a handful of pictures. For a big workbook with in-cell pictures, the rich value\nmap above avoids openpyxl for the images entirely — use a ",[125,2648,2649],{},"read_only"," openpyxl load, or pandas, just to read the key column.",[113,2652,2654],{"id":2653},"conclusion","Conclusion",[10,2656,2657,2658,2660,2661,2663,2664,2666,2667,2669],{},"Every picture in an ",[125,2659,546],{}," sits in ",[125,2662,75],{},", so a zip read extracts the files instantly. When the position matters, use openpyxl's image anchors for floating\npictures, and follow the cell's ",[125,2665,1195],{}," attribute through ",[125,2668,2322],{}," and the rich value parts for pictures placed in cells, which openpyxl does not load. Name the\nextracted files after a key from the same row, check for duplicate keys, and verify each image with Pillow before passing the folder on.",[113,2671,2673],{"id":2672},"frequently-asked-questions","Frequently asked questions",[10,2675,2676,2680],{},[2677,2678,2679],"strong",{},"Can pandas extract images from Excel?","\nNo. pandas reads cell values only; picture cells come back as missing values. Use zipfile or openpyxl as shown on this page.",[10,2682,2683,2686],{},[2677,2684,2685],{},"Does this work for charts?","\nCharts are not images; they are stored as chart XML parts and drawn by Excel. To get a chart as a picture, export it from Excel, or regenerate it with matplotlib from the underlying data.",[10,2688,2689,2692],{},[2677,2690,2691],{},"How do I extract images from every sheet?","\nFor floating pictures the openpyxl loop already covers all worksheets. For pictures in cells, map each sheet name to its XML part through xl\u002Fworkbook.xml and xl\u002F_rels\u002Fworkbook.xml.rels, then call the map function per part.",[10,2694,2695,2698],{},[2677,2696,2697],{},"Why do some extracted images have a different resolution from what I see?","\nExcel scales pictures for display but stores the original. The extracted file is the stored original, which is usually the better version to keep.",[113,2700,2702],{"id":2701},"related","Related",[2704,2705,2706,2713,2720,2727,2734],"ul",{},[2707,2708,2709,2710,2712],"li",{},"Up one level: ",[14,2711,17],{"href":16}," — adding pictures to workbooks.",[2707,2714,2715,2719],{},[14,2716,2718],{"href":2717},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fembed-images-inside-cells-with-xlsxwriter\u002F","Embed Images Inside Cells with xlsxwriter"," — how pictures in cells are written.",[2707,2721,2722,2726],{},[14,2723,2725],{"href":2724},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fresize-and-position-images-in-excel-with-openpyxl\u002F","Resize and Position Images in Excel with openpyxl"," — the anchors read in Step 2.",[2707,2728,2729,2733],{},[14,2730,2732],{"href":2731},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-badzipfile-error-when-reading-excel-in-python\u002F","Fix BadZipFile When Reading an Excel File in Python"," — when the archive itself is damaged.",[2707,2735,2736,2740],{},[14,2737,2739],{"href":2738},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-cell-colours-and-font-styles-as-data-with-openpyxl\u002F","Read Cell Colours and Font Styles as Data with openpyxl"," — other information stored outside cell values.",[2742,2743,2744],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":123,"searchDepth":170,"depth":170,"links":2746},[2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757],{"id":115,"depth":170,"text":116},{"id":539,"depth":170,"text":540},{"id":754,"depth":170,"text":755},{"id":1180,"depth":170,"text":1181},{"id":2012,"depth":170,"text":2013},{"id":2365,"depth":170,"text":2366},{"id":2528,"depth":170,"text":2529},{"id":2642,"depth":170,"text":2643},{"id":2653,"depth":170,"text":2654},{"id":2672,"depth":170,"text":2673},{"id":2701,"depth":170,"text":2702},"2026-09-17","Pull every picture out of an .xlsx — all at once from the zip archive, floating images with the cell they sit on through openpyxl, and pictures placed in cells by following the rich-value parts.","md",[2762,2764,2766,2768],{"q":2679,"a":2763},"No. pandas reads cell values only; picture cells come back as missing values. Use zipfile or openpyxl as shown on this page.",{"q":2685,"a":2765},"Charts are not images; they are stored as chart XML parts and drawn by Excel. To get a chart as a picture, export it from Excel, or regenerate it with matplotlib from the underlying data.",{"q":2691,"a":2767},"For floating pictures the openpyxl loop already covers all worksheets. For pictures in cells, map each sheet name to its XML part through xl\u002Fworkbook.xml and xl\u002F_rels\u002Fworkbook.xml.rels, then call the map function per part.",{"q":2697,"a":2769},"Excel scales pictures for display but stores the original. The extracted file is the stored original, which is usually the better version to keep.","extract images from an excel file with python",null,{"breadcrumb":2773},[2774,2776,2779],{"name":2775,"item":698},"Home",{"name":2777,"item":2778},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":17,"item":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python",{"title":5,"description":2782},"Save images from Excel workbooks in Python: read xl\u002Fmedia from the zip, get floating image anchors with openpyxl, map in-cell pictures to their cells, and name files by row data.","extract-images-from-an-excel-file-with-python","formatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fextract-images-from-an-excel-file-with-python\u002Findex",[2786],"charts-and-images","how-to","1KDoaFEKYklXZA4yzqvd80URinKeBvOHAYNj7HBa0EU",[2790,2794],{"title":2791,"path":2792,"stem":2793,"children":-1},"Export an Excel Chart as an Image with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fexport-an-excel-chart-as-an-image","formatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fexport-an-excel-chart-as-an-image\u002Findex",{"title":2795,"path":2796,"stem":2797,"children":-1},"Generate QR Codes and Barcodes in Excel with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fgenerate-qr-codes-and-barcodes-in-excel-with-python","formatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fgenerate-qr-codes-and-barcodes-in-excel-with-python\u002Findex",[2799,2801],{"path":2800,"title":2777},"\u002Fformatting-and-charting-excel-reports-with-python",{"path":2802,"title":17},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel",[],[2805,2808,2811,2814,2817,2820],{"path":2806,"title":2807,"kind":2787},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fbuild-a-dashboard-sheet-with-charts-from-multiple-tabs","Build a Dashboard Sheet with Charts from Multiple Tabs",{"path":2809,"title":2810,"kind":2787},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fbuild-a-rolling-12-month-chart-on-an-excel-dashboard","Build a Rolling 12-Month Chart on an Excel Dashboard",{"path":2812,"title":2813,"kind":2787},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002Fkeep-charts-and-images-when-filling-an-excel-template","Keep Charts and Images When Filling an Excel Template",{"path":2815,"title":2816,"kind":2787},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-a-chart-to-an-excel-file-with-xlsxwriter","Add a Chart to an Excel File with xlsxwriter",{"path":2818,"title":2819,"kind":2787},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-sparklines-to-an-excel-report-with-xlsxwriter","Add Sparklines to an Excel Report with xlsxwriter",{"path":2821,"title":2822,"kind":2787},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fbuild-a-waterfall-chart-in-excel-with-python","Build a Waterfall Chart in Excel with Python",1790972116740]