[{"data":1,"prerenderedAt":2149},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet":2118,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet":2125,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet":2129,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet":2130},{"id":4,"title":5,"body":6,"dateModified":2085,"datePublished":2085,"description":2086,"extension":2087,"faq":2088,"keyword":2097,"kind":2098,"meta":2099,"navigation":262,"path":2107,"seo":2108,"slug":2111,"stem":2112,"topics":2113,"type":2116,"__hash__":2117},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet\u002Findex.md","Add a Watermark to an Excel Sheet with Python",{"type":7,"value":8,"toc":2072},"minimark",[9,19,24,62,70,226,230,233,565,572,576,591,962,971,983,987,990,1196,1203,1286,1290,1293,1341,1653,1669,1773,1777,1780,1919,1934,1938,1941,1945,1988,1992,2003,2007,2017,2023,2029,2035,2039,2068],[10,11,12,13,18],"p",{},"A draft budget that gets forwarded as if it were final, a confidential salary report printed and left on a desk — a watermark across the page is the usual defence. Word has a Watermark button; Excel does not. What Excel users call a watermark is one of two workarounds: a picture placed in the page header, which Excel prints on every page and shows in Page Layout view, or a sheet background image, which shows on screen but never prints. Python can produce both, and when the report is shared as a PDF, it can stamp the PDF itself, which is the most reliable of all. This page is part of ",[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",".",[20,21,23],"h2",{"id":22},"prerequisites","Prerequisites",[25,26,31],"pre",{"className":27,"code":28,"language":29,"meta":30,"style":30},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install xlsxwriter pillow pypdf reportlab openpyxl\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50,53,56,59],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sMTad","pip",[35,44,46],{"class":45},"srMev"," install",[35,48,49],{"class":45}," xlsxwriter",[35,51,52],{"class":45}," pillow",[35,54,55],{"class":45}," pypdf",[35,57,58],{"class":45}," reportlab",[35,60,61],{"class":45}," openpyxl\n",[10,63,64,65,69],{},"The examples build a small budget sheet from scratch with xlsxwriter, which supports header images and backgrounds directly. openpyxl can set the header ",[66,67,68],"em",{},"text"," that references a picture, but it cannot add the picture itself, and — as Step 5 shows — it removes existing ones when it saves.",[71,72,80,81,80,85,80,89,80,97,80,105,80,112,80,118,80,121,80,125,80,128,80,132,80,137,80,143,80,145,80,156,80,158,80,166,80,168,80,173,80,176,80,180,80,182,80,187,80,189,80,194,80,196,80,201,80,204,80,208,80,210,80,215,80,217,80,222,80,224],"svg",{"viewBox":73,"role":74,"ariaLabelledBy":75,"xmlns":78,"style":79},"4 0 752 174","img",[76,77],"wm-methods-t","wm-methods-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[82,83,84],"title",{"id":76},"Three ways to watermark, and where each one shows",[86,87,88],"desc",{"id":77},"A comparison table. A header picture shows in Page Layout view, in print and in Excel's PDF export, but not in Normal view. A sheet background shows in Normal view only. A PDF stamp shows only in the PDF but cannot be removed by editing the workbook.",[90,91],"rect",{"x":92,"y":93,"width":94,"height":95,"fill":96},"4","0","752","174","#ffffff",[90,98],{"x":99,"y":100,"width":101,"height":102,"rx":93,"fill":96,"stroke":103,"style":104},"20.0","16.0","155.2","40.0","var(--line,#cdd5e6)","stroke-width:1px",[90,106],{"x":107,"y":100,"width":108,"height":102,"rx":93,"fill":109,"stroke":110,"style":111},"175.2","188.3","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.2px",[68,113,117],{"x":114,"y":115,"style":116},"269.3","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Normal view",[90,119],{"x":120,"y":100,"width":108,"height":102,"rx":93,"fill":109,"stroke":110,"style":111},"363.4",[68,122,124],{"x":123,"y":115,"style":116},"457.6","Printed \u002F PDF",[90,126],{"x":127,"y":100,"width":108,"height":102,"rx":93,"fill":109,"stroke":110,"style":111},"551.7",[68,129,131],{"x":130,"y":115,"style":116},"645.9","Survives openpyxl save",[90,133],{"x":99,"y":134,"width":101,"height":135,"rx":93,"fill":136,"stroke":103,"style":104},"56.0","34.0","#e7ebef",[68,138,142],{"x":139,"y":140,"style":141},"32.0","78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","Header picture (&G)",[90,144],{"x":107,"y":134,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[146,147,149],"g",{"transform":148},"translate(261.3,65.0) scale(0.667)",[150,151],"path",{"d":152,"fill":153,"stroke":154,"style":155},"M6 6l12 12 M18 6L6 18","none","var(--accent,#f43f8f)","stroke-width:2.70px;stroke-linecap:round;stroke-linejoin:round",[90,157],{"x":120,"y":134,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[146,159,161],{"transform":160},"translate(448.6,64.0) scale(0.750)",[150,162],{"d":163,"fill":153,"stroke":164,"style":165},"M5 12.5l4.5 4.5L19 7","var(--teal,#0f9488)","stroke-width:2.40px;stroke-linecap:round;stroke-linejoin:round",[90,167],{"x":127,"y":134,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[146,169,171],{"transform":170},"translate(637.9,65.0) scale(0.667)",[150,172],{"d":152,"fill":153,"stroke":154,"style":155},[90,174],{"x":99,"y":175,"width":101,"height":135,"rx":93,"fill":136,"stroke":103,"style":104},"90.0",[68,177,179],{"x":139,"y":178,"style":141},"112.0","Sheet background",[90,181],{"x":107,"y":175,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[146,183,185],{"transform":184},"translate(260.3,98.0) scale(0.750)",[150,186],{"d":163,"fill":153,"stroke":164,"style":165},[90,188],{"x":120,"y":175,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[146,190,192],{"transform":191},"translate(449.6,99.0) scale(0.667)",[150,193],{"d":152,"fill":153,"stroke":154,"style":155},[90,195],{"x":127,"y":175,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[146,197,199],{"transform":198},"translate(637.9,99.0) scale(0.667)",[150,200],{"d":152,"fill":153,"stroke":154,"style":155},[90,202],{"x":99,"y":203,"width":101,"height":135,"rx":93,"fill":136,"stroke":103,"style":104},"124.0",[68,205,207],{"x":139,"y":206,"style":141},"146.0","PDF stamp (pypdf)",[90,209],{"x":107,"y":203,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[68,211,214],{"x":114,"y":212,"style":213},"145.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","n\u002Fa",[90,216],{"x":120,"y":203,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[146,218,220],{"transform":219},"translate(448.6,132.0) scale(0.750)",[150,221],{"d":163,"fill":153,"stroke":164,"style":165},[90,223],{"x":127,"y":203,"width":108,"height":135,"rx":93,"fill":96,"stroke":103,"style":104},[68,225,214],{"x":130,"y":212,"style":213},[20,227,229],{"id":228},"step-1-make-a-transparent-watermark-image","Step 1 — Make a transparent watermark image",[10,231,232],{},"The watermark is an ordinary PNG: large pale text, rotated, on a transparent background so the cells show through. Pillow draws it:",[25,234,238],{"className":235,"code":236,"language":237,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","from PIL import Image, ImageDraw, ImageFont\n\ndef watermark_png(text, path, size=(1000, 360), rgba=(220, 38, 38, 60), angle=35):\n    img = Image.new(\"RGBA\", size, (255, 255, 255, 0))\n    draw = ImageDraw.Draw(img)\n    try:\n        font = ImageFont.truetype(\"DejaVuSans-Bold.ttf\", 200)\n    except OSError:\n        font = ImageFont.load_default(size=200)\n    draw.text((size[0] \u002F 2, size[1] \u002F 2), text, font=font, fill=rgba, anchor=\"mm\")\n    img = img.rotate(angle, expand=True) if angle else img\n    img.save(path)\n    return img.size\n\nprint(watermark_png(\"DRAFT\", \"draft.png\"))\n","python",[32,239,240,257,264,327,362,373,382,404,415,435,493,526,532,541,546],{"__ignoreMap":30},[35,241,242,246,250,253],{"class":37,"line":38},[35,243,245],{"class":244},"s-kum","from",[35,247,249],{"class":248},"sP0c6"," PIL",[35,251,252],{"class":244}," import",[35,254,256],{"class":255},"skGVy"," Image, ImageDraw, ImageFont\n",[35,258,260],{"class":37,"line":259},2,[35,261,263],{"emptyLinePlaceholder":262},true,"\n",[35,265,267,270,274,277,280,283,286,289,292,295,297,299,302,304,307,309,311,313,316,319,321,324],{"class":37,"line":266},3,[35,268,269],{"class":244},"def",[35,271,273],{"class":272},"s_Opv"," watermark_png",[35,275,276],{"class":255},"(text, path, size",[35,278,279],{"class":244},"=",[35,281,282],{"class":255},"(",[35,284,285],{"class":248},"1000",[35,287,288],{"class":255},", ",[35,290,291],{"class":248},"360",[35,293,294],{"class":255},"), rgba",[35,296,279],{"class":244},[35,298,282],{"class":255},[35,300,301],{"class":248},"220",[35,303,288],{"class":255},[35,305,306],{"class":248},"38",[35,308,288],{"class":255},[35,310,306],{"class":248},[35,312,288],{"class":255},[35,314,315],{"class":248},"60",[35,317,318],{"class":255},"), angle",[35,320,279],{"class":244},[35,322,323],{"class":248},"35",[35,325,326],{"class":255},"):\n",[35,328,330,333,335,338,341,344,347,349,351,353,355,357,359],{"class":37,"line":329},4,[35,331,332],{"class":255},"    img ",[35,334,279],{"class":244},[35,336,337],{"class":255}," Image.new(",[35,339,340],{"class":45},"\"RGBA\"",[35,342,343],{"class":255},", size, (",[35,345,346],{"class":248},"255",[35,348,288],{"class":255},[35,350,346],{"class":248},[35,352,288],{"class":255},[35,354,346],{"class":248},[35,356,288],{"class":255},[35,358,93],{"class":248},[35,360,361],{"class":255},"))\n",[35,363,365,368,370],{"class":37,"line":364},5,[35,366,367],{"class":255},"    draw ",[35,369,279],{"class":244},[35,371,372],{"class":255}," ImageDraw.Draw(img)\n",[35,374,376,379],{"class":37,"line":375},6,[35,377,378],{"class":244},"    try",[35,380,381],{"class":255},":\n",[35,383,385,388,390,393,396,398,401],{"class":37,"line":384},7,[35,386,387],{"class":255},"        font ",[35,389,279],{"class":244},[35,391,392],{"class":255}," ImageFont.truetype(",[35,394,395],{"class":45},"\"DejaVuSans-Bold.ttf\"",[35,397,288],{"class":255},[35,399,400],{"class":248},"200",[35,402,403],{"class":255},")\n",[35,405,407,410,413],{"class":37,"line":406},8,[35,408,409],{"class":244},"    except",[35,411,412],{"class":248}," OSError",[35,414,381],{"class":255},[35,416,418,420,422,425,429,431,433],{"class":37,"line":417},9,[35,419,387],{"class":255},[35,421,279],{"class":244},[35,423,424],{"class":255}," ImageFont.load_default(",[35,426,428],{"class":427},"sa561","size",[35,430,279],{"class":244},[35,432,400],{"class":248},[35,434,403],{"class":255},[35,436,438,441,443,446,449,452,455,458,460,462,464,467,470,472,475,478,480,483,486,488,491],{"class":37,"line":437},10,[35,439,440],{"class":255},"    draw.text((size[",[35,442,93],{"class":248},[35,444,445],{"class":255},"] ",[35,447,448],{"class":244},"\u002F",[35,450,451],{"class":248}," 2",[35,453,454],{"class":255},", size[",[35,456,457],{"class":248},"1",[35,459,445],{"class":255},[35,461,448],{"class":244},[35,463,451],{"class":248},[35,465,466],{"class":255},"), text, ",[35,468,469],{"class":427},"font",[35,471,279],{"class":244},[35,473,474],{"class":255},"font, ",[35,476,477],{"class":427},"fill",[35,479,279],{"class":244},[35,481,482],{"class":255},"rgba, ",[35,484,485],{"class":427},"anchor",[35,487,279],{"class":244},[35,489,490],{"class":45},"\"mm\"",[35,492,403],{"class":255},[35,494,496,498,500,503,506,508,511,514,517,520,523],{"class":37,"line":495},11,[35,497,332],{"class":255},[35,499,279],{"class":244},[35,501,502],{"class":255}," img.rotate(angle, ",[35,504,505],{"class":427},"expand",[35,507,279],{"class":244},[35,509,510],{"class":248},"True",[35,512,513],{"class":255},") ",[35,515,516],{"class":244},"if",[35,518,519],{"class":255}," angle ",[35,521,522],{"class":244},"else",[35,524,525],{"class":255}," img\n",[35,527,529],{"class":37,"line":528},12,[35,530,531],{"class":255},"    img.save(path)\n",[35,533,535,538],{"class":37,"line":534},13,[35,536,537],{"class":244},"    return",[35,539,540],{"class":255}," img.size\n",[35,542,544],{"class":37,"line":543},14,[35,545,263],{"emptyLinePlaceholder":262},[35,547,549,552,555,558,560,563],{"class":37,"line":548},15,[35,550,551],{"class":248},"print",[35,553,554],{"class":255},"(watermark_png(",[35,556,557],{"class":45},"\"DRAFT\"",[35,559,288],{"class":255},[35,561,562],{"class":45},"\"draft.png\"",[35,564,361],{"class":255},[10,566,567,568,571],{},"The alpha value of 60 out of 255 makes the text faint enough to read the numbers through. ",[32,569,570],{},"rotate(..., expand=True)"," grows the canvas so the rotated word is not cropped at the corners — without it, the ends of the letters are cut off. Any TrueType font works; the fallback keeps the function running on machines without DejaVu installed.",[20,573,575],{"id":574},"step-2-put-the-image-in-the-page-header","Step 2 — Put the image in the page header",[10,577,578,579,582,583,586,587,590],{},"Excel's watermark technique is a picture in the centre section of the header, referenced by the ",[32,580,581],{},"&[Picture]"," code (stored as ",[32,584,585],{},"&G","). xlsxwriter's ",[32,588,589],{},"set_header"," takes the header string and the image:",[25,592,594],{"className":235,"code":593,"language":237,"meta":30,"style":30},"import xlsxwriter\n\nwb = xlsxwriter.Workbook(\"budget_draft.xlsx\")\nws = wb.add_worksheet(\"Budget\")\nbold = wb.add_format({\"bold\": True})\nmoney = wb.add_format({\"num_format\": \"#,##0\"})\nws.write_row(0, 0, [\"Cost centre\", \"Q1\", \"Q2\", \"Q3\", \"Q4\"], bold)\nrows = [(\"Marketing\", 42000, 45000, 39000, 51000), (\"Engineering\", 180000, 184000, 190000, 195000),\n        (\"Sales\", 96000, 99000, 101000, 108000), (\"Support\", 51000, 51000, 53000, 55000)]\nfor r, row in enumerate(rows, start=1):\n    ws.write(r, 0, row[0])\n    ws.write_row(r, 1, row[1:], money)\nws.set_column(\"A:A\", 16)\nws.set_column(\"B:E\", 11)\nws.set_header(\"&C&[Picture]\", {\"image_center\": \"draft.png\"})\nws.set_page_view()\nwb.close()\nprint(\"written\")\n",[32,595,596,604,608,623,638,659,678,718,780,834,860,875,889,904,918,938,944,950],{"__ignoreMap":30},[35,597,598,601],{"class":37,"line":38},[35,599,600],{"class":244},"import",[35,602,603],{"class":255}," xlsxwriter\n",[35,605,606],{"class":37,"line":259},[35,607,263],{"emptyLinePlaceholder":262},[35,609,610,613,615,618,621],{"class":37,"line":266},[35,611,612],{"class":255},"wb ",[35,614,279],{"class":244},[35,616,617],{"class":255}," xlsxwriter.Workbook(",[35,619,620],{"class":45},"\"budget_draft.xlsx\"",[35,622,403],{"class":255},[35,624,625,628,630,633,636],{"class":37,"line":329},[35,626,627],{"class":255},"ws ",[35,629,279],{"class":244},[35,631,632],{"class":255}," wb.add_worksheet(",[35,634,635],{"class":45},"\"Budget\"",[35,637,403],{"class":255},[35,639,640,643,645,648,651,654,656],{"class":37,"line":364},[35,641,642],{"class":255},"bold ",[35,644,279],{"class":244},[35,646,647],{"class":255}," wb.add_format({",[35,649,650],{"class":45},"\"bold\"",[35,652,653],{"class":255},": ",[35,655,510],{"class":248},[35,657,658],{"class":255},"})\n",[35,660,661,664,666,668,671,673,676],{"class":37,"line":375},[35,662,663],{"class":255},"money ",[35,665,279],{"class":244},[35,667,647],{"class":255},[35,669,670],{"class":45},"\"num_format\"",[35,672,653],{"class":255},[35,674,675],{"class":45},"\"#,##0\"",[35,677,658],{"class":255},[35,679,680,683,685,687,689,692,695,697,700,702,705,707,710,712,715],{"class":37,"line":384},[35,681,682],{"class":255},"ws.write_row(",[35,684,93],{"class":248},[35,686,288],{"class":255},[35,688,93],{"class":248},[35,690,691],{"class":255},", [",[35,693,694],{"class":45},"\"Cost centre\"",[35,696,288],{"class":255},[35,698,699],{"class":45},"\"Q1\"",[35,701,288],{"class":255},[35,703,704],{"class":45},"\"Q2\"",[35,706,288],{"class":255},[35,708,709],{"class":45},"\"Q3\"",[35,711,288],{"class":255},[35,713,714],{"class":45},"\"Q4\"",[35,716,717],{"class":255},"], bold)\n",[35,719,720,723,725,728,731,733,736,738,741,743,746,748,751,754,757,759,762,764,767,769,772,774,777],{"class":37,"line":406},[35,721,722],{"class":255},"rows ",[35,724,279],{"class":244},[35,726,727],{"class":255}," [(",[35,729,730],{"class":45},"\"Marketing\"",[35,732,288],{"class":255},[35,734,735],{"class":248},"42000",[35,737,288],{"class":255},[35,739,740],{"class":248},"45000",[35,742,288],{"class":255},[35,744,745],{"class":248},"39000",[35,747,288],{"class":255},[35,749,750],{"class":248},"51000",[35,752,753],{"class":255},"), (",[35,755,756],{"class":45},"\"Engineering\"",[35,758,288],{"class":255},[35,760,761],{"class":248},"180000",[35,763,288],{"class":255},[35,765,766],{"class":248},"184000",[35,768,288],{"class":255},[35,770,771],{"class":248},"190000",[35,773,288],{"class":255},[35,775,776],{"class":248},"195000",[35,778,779],{"class":255},"),\n",[35,781,782,785,788,790,793,795,798,800,803,805,808,810,813,815,817,819,821,823,826,828,831],{"class":37,"line":417},[35,783,784],{"class":255},"        (",[35,786,787],{"class":45},"\"Sales\"",[35,789,288],{"class":255},[35,791,792],{"class":248},"96000",[35,794,288],{"class":255},[35,796,797],{"class":248},"99000",[35,799,288],{"class":255},[35,801,802],{"class":248},"101000",[35,804,288],{"class":255},[35,806,807],{"class":248},"108000",[35,809,753],{"class":255},[35,811,812],{"class":45},"\"Support\"",[35,814,288],{"class":255},[35,816,750],{"class":248},[35,818,288],{"class":255},[35,820,750],{"class":248},[35,822,288],{"class":255},[35,824,825],{"class":248},"53000",[35,827,288],{"class":255},[35,829,830],{"class":248},"55000",[35,832,833],{"class":255},")]\n",[35,835,836,839,842,845,848,851,854,856,858],{"class":37,"line":437},[35,837,838],{"class":244},"for",[35,840,841],{"class":255}," r, row ",[35,843,844],{"class":244},"in",[35,846,847],{"class":248}," enumerate",[35,849,850],{"class":255},"(rows, ",[35,852,853],{"class":427},"start",[35,855,279],{"class":244},[35,857,457],{"class":248},[35,859,326],{"class":255},[35,861,862,865,867,870,872],{"class":37,"line":495},[35,863,864],{"class":255},"    ws.write(r, ",[35,866,93],{"class":248},[35,868,869],{"class":255},", row[",[35,871,93],{"class":248},[35,873,874],{"class":255},"])\n",[35,876,877,880,882,884,886],{"class":37,"line":528},[35,878,879],{"class":255},"    ws.write_row(r, ",[35,881,457],{"class":248},[35,883,869],{"class":255},[35,885,457],{"class":248},[35,887,888],{"class":255},":], money)\n",[35,890,891,894,897,899,902],{"class":37,"line":534},[35,892,893],{"class":255},"ws.set_column(",[35,895,896],{"class":45},"\"A:A\"",[35,898,288],{"class":255},[35,900,901],{"class":248},"16",[35,903,403],{"class":255},[35,905,906,908,911,913,916],{"class":37,"line":543},[35,907,893],{"class":255},[35,909,910],{"class":45},"\"B:E\"",[35,912,288],{"class":255},[35,914,915],{"class":248},"11",[35,917,403],{"class":255},[35,919,920,923,926,929,932,934,936],{"class":37,"line":548},[35,921,922],{"class":255},"ws.set_header(",[35,924,925],{"class":45},"\"&C&[Picture]\"",[35,927,928],{"class":255},", {",[35,930,931],{"class":45},"\"image_center\"",[35,933,653],{"class":255},[35,935,562],{"class":45},[35,937,658],{"class":255},[35,939,941],{"class":37,"line":940},16,[35,942,943],{"class":255},"ws.set_page_view()\n",[35,945,947],{"class":37,"line":946},17,[35,948,949],{"class":255},"wb.close()\n",[35,951,953,955,957,960],{"class":37,"line":952},18,[35,954,551],{"class":248},[35,956,282],{"class":255},[35,958,959],{"class":45},"\"written\"",[35,961,403],{"class":255},[10,963,964,967,968,970],{},[32,965,966],{},"set_page_view()"," makes the sheet open in Page Layout view, where header pictures are visible; in Excel's Normal view they are hidden, which is the most common reason people think the watermark did not work. Every printed page and every PDF made from Excel carries the picture, centred at the top — if the image is taller than the header area, Excel lets it extend down over the page, which is what makes it look like a watermark rather than a logo. Make the transparent image taller, or add blank lines before ",[32,969,581],{}," in the header string, to move it further down the page.",[10,972,973,974,977,978,982],{},"LibreOffice does not display pictures in ",[32,975,976],{},".xlsx"," headers, so this step has to be checked in Excel. ",[14,979,981],{"href":980},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fadd-headers-footers-and-page-numbers-to-an-excel-pdf\u002F","Add Headers, Footers and Page Numbers to an Excel PDF"," covers the other header codes.",[20,984,986],{"id":985},"step-3-a-background-for-the-screen","Step 3 — A background for the screen",[10,988,989],{},"A sheet background tiles an image behind the cells in Normal view. Excel never prints it, so it suits a workbook that is read on screen — \"CONFIDENTIAL\" behind a salary sheet, say:",[25,991,993],{"className":235,"code":992,"language":237,"meta":30,"style":30},"print(watermark_png(\"CONFIDENTIAL\", \"confidential.png\", size=(1400, 300), rgba=(67, 56, 202, 40), angle=0))\nwb = xlsxwriter.Workbook(\"salaries.xlsx\")\nws = wb.add_worksheet(\"Salaries\")\nws.write_row(0, 0, [\"Employee\", \"Salary\"])\nfor r, (name, pay) in enumerate([(\"A. Okafor\", 72000), (\"J. Lindqvist\", 68000), (\"C. Martin\", 55000)], start=1):\n    ws.write_row(r, 0, [name, pay])\nws.set_background(\"confidential.png\")\nwb.close()\nprint(\"written\")\n",[32,994,995,1064,1077,1090,1112,1164,1173,1182,1186],{"__ignoreMap":30},[35,996,997,999,1001,1004,1006,1009,1011,1013,1015,1017,1020,1022,1025,1028,1031,1033,1035,1038,1040,1043,1045,1048,1050,1053,1055,1058,1060,1062],{"class":37,"line":38},[35,998,551],{"class":248},[35,1000,554],{"class":255},[35,1002,1003],{"class":45},"\"CONFIDENTIAL\"",[35,1005,288],{"class":255},[35,1007,1008],{"class":45},"\"confidential.png\"",[35,1010,288],{"class":255},[35,1012,428],{"class":427},[35,1014,279],{"class":244},[35,1016,282],{"class":255},[35,1018,1019],{"class":248},"1400",[35,1021,288],{"class":255},[35,1023,1024],{"class":248},"300",[35,1026,1027],{"class":255},"), ",[35,1029,1030],{"class":427},"rgba",[35,1032,279],{"class":244},[35,1034,282],{"class":255},[35,1036,1037],{"class":248},"67",[35,1039,288],{"class":255},[35,1041,1042],{"class":248},"56",[35,1044,288],{"class":255},[35,1046,1047],{"class":248},"202",[35,1049,288],{"class":255},[35,1051,1052],{"class":248},"40",[35,1054,1027],{"class":255},[35,1056,1057],{"class":427},"angle",[35,1059,279],{"class":244},[35,1061,93],{"class":248},[35,1063,361],{"class":255},[35,1065,1066,1068,1070,1072,1075],{"class":37,"line":259},[35,1067,612],{"class":255},[35,1069,279],{"class":244},[35,1071,617],{"class":255},[35,1073,1074],{"class":45},"\"salaries.xlsx\"",[35,1076,403],{"class":255},[35,1078,1079,1081,1083,1085,1088],{"class":37,"line":266},[35,1080,627],{"class":255},[35,1082,279],{"class":244},[35,1084,632],{"class":255},[35,1086,1087],{"class":45},"\"Salaries\"",[35,1089,403],{"class":255},[35,1091,1092,1094,1096,1098,1100,1102,1105,1107,1110],{"class":37,"line":329},[35,1093,682],{"class":255},[35,1095,93],{"class":248},[35,1097,288],{"class":255},[35,1099,93],{"class":248},[35,1101,691],{"class":255},[35,1103,1104],{"class":45},"\"Employee\"",[35,1106,288],{"class":255},[35,1108,1109],{"class":45},"\"Salary\"",[35,1111,874],{"class":255},[35,1113,1114,1116,1119,1121,1123,1126,1129,1131,1134,1136,1139,1141,1144,1146,1149,1151,1153,1156,1158,1160,1162],{"class":37,"line":364},[35,1115,838],{"class":244},[35,1117,1118],{"class":255}," r, (name, pay) ",[35,1120,844],{"class":244},[35,1122,847],{"class":248},[35,1124,1125],{"class":255},"([(",[35,1127,1128],{"class":45},"\"A. Okafor\"",[35,1130,288],{"class":255},[35,1132,1133],{"class":248},"72000",[35,1135,753],{"class":255},[35,1137,1138],{"class":45},"\"J. Lindqvist\"",[35,1140,288],{"class":255},[35,1142,1143],{"class":248},"68000",[35,1145,753],{"class":255},[35,1147,1148],{"class":45},"\"C. Martin\"",[35,1150,288],{"class":255},[35,1152,830],{"class":248},[35,1154,1155],{"class":255},")], ",[35,1157,853],{"class":427},[35,1159,279],{"class":244},[35,1161,457],{"class":248},[35,1163,326],{"class":255},[35,1165,1166,1168,1170],{"class":37,"line":375},[35,1167,879],{"class":255},[35,1169,93],{"class":248},[35,1171,1172],{"class":255},", [name, pay])\n",[35,1174,1175,1178,1180],{"class":37,"line":384},[35,1176,1177],{"class":255},"ws.set_background(",[35,1179,1008],{"class":45},[35,1181,403],{"class":255},[35,1183,1184],{"class":37,"line":406},[35,1185,949],{"class":255},[35,1187,1188,1190,1192,1194],{"class":37,"line":417},[35,1189,551],{"class":248},[35,1191,282],{"class":255},[35,1193,959],{"class":45},[35,1195,403],{"class":255},[10,1197,1198,1199,1202],{},"Background images are repeated across and down the whole sheet, so a wide, short, unrotated image like this one tiles into horizontal bands of text — easier to read around than a diagonal pattern. Because the background is not printed by Excel, pair it with a header picture if the sheet may be printed too. One inconsistency to be aware of: LibreOffice's PDF export ",[66,1200,1201],{},"does"," draw sheet backgrounds, so the same file can print differently depending on the program.",[71,1204,80,1210,80,1213,80,1216,80,1221,80,1230,80,1238,80,1244,80,1248,80,1251,80,1258,80,1263,80,1267,80,1270,80,1277,80,1282],{"viewBox":1205,"role":74,"ariaLabelledBy":1206,"xmlns":78,"style":1209},"64 0 632 331",[1207,1208],"wm-layers-t","wm-layers-d","width:100%;max-width:632px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[82,1211,1212],{"id":1207},"Where each watermark sits",[86,1214,1215],{"id":1208},"Three layers of a printed page. The PDF stamp is drawn over everything; the cells are in the middle; the header picture and the sheet background sit behind the cells.",[90,1217],{"x":1218,"y":93,"width":1219,"height":1220,"fill":96},"64","632","331",[90,1222],{"x":1223,"y":100,"width":1224,"height":1225,"rx":1226,"fill":1227,"stroke":1228,"style":1229},"80.0","600.0","93.0","12","#fce9e9","var(--danger,#dc2626)","stroke-width:2px",[146,1231,1233],{"transform":1232},"translate(368.0,29.0) scale(1.000)",[150,1234],{"d":1235,"fill":153,"stroke":1236,"style":1237},"M6 3h9l4 4v14H6z M15 3v4h4 M9 12h6 M9 15.5h6 M9 19h4","var(--accent-ink,#be185d)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[68,1239,1243],{"x":1240,"y":1241,"style":1242},"380.0","75.5","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","PDF stamp",[68,1245,1247],{"x":1240,"y":1246,"style":213},"95.0","drawn over the page by pypdf — cannot be edited away in Excel",[90,1249],{"x":1223,"y":1250,"width":1224,"height":1225,"rx":1226,"fill":136,"stroke":103,"style":1229},"119.0",[146,1252,1254],{"transform":1253},"translate(368.0,132.0) scale(1.000)",[150,1255],{"d":1256,"fill":153,"stroke":1257,"style":1237},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","var(--text,#172033)",[68,1259,1262],{"x":1240,"y":1260,"style":1261},"178.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Cells and text",[68,1264,1266],{"x":1240,"y":1265,"style":213},"198.0","the report itself",[90,1268],{"x":1223,"y":1269,"width":1224,"height":1225,"rx":1226,"fill":109,"stroke":110,"style":1229},"222.0",[146,1271,1273],{"transform":1272},"translate(368.0,235.0) scale(1.000)",[150,1274],{"d":1275,"fill":153,"stroke":1276,"style":1237},"M4 5h16v14H4z M4 16l5-5 4 4 3-3 4 4 M15 9h.01","var(--brand-strong,#4338ca)",[68,1278,1281],{"x":1240,"y":1279,"style":1280},"281.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Header picture or background",[68,1283,1285],{"x":1240,"y":1284,"style":213},"301.0","behind the cells — part of the workbook",[20,1287,1289],{"id":1288},"step-4-stamp-the-pdf-instead","Step 4 — Stamp the PDF instead",[10,1291,1292],{},"When the report is distributed as a PDF, stamp the PDF rather than the workbook: the mark is on every page regardless of how the workbook's print settings or viewer behave, and it cannot be removed by editing the spreadsheet. Convert the workbook to PDF, draw the watermark on a transparent page with reportlab, and merge it onto each page of a writer cloned from the export with pypdf:",[25,1294,1296],{"className":27,"code":1295,"language":29,"meta":30,"style":30},"soffice -env:UserInstallation=file:\u002F\u002F$PWD\u002Flo_profile --headless --convert-to pdf budget_draft.xlsx > \u002Fdev\u002Fnull 2>&1\nls budget_draft.pdf\n",[32,1297,1298,1333],{"__ignoreMap":30},[35,1299,1300,1303,1306,1309,1312,1315,1318,1321,1324,1327,1330],{"class":37,"line":38},[35,1301,1302],{"class":41},"soffice",[35,1304,1305],{"class":248}," -env:UserInstallation=file:\u002F\u002F",[35,1307,1308],{"class":255},"$PWD",[35,1310,1311],{"class":248},"\u002Flo_profile",[35,1313,1314],{"class":248}," --headless",[35,1316,1317],{"class":248}," --convert-to",[35,1319,1320],{"class":45}," pdf",[35,1322,1323],{"class":45}," budget_draft.xlsx",[35,1325,1326],{"class":244}," >",[35,1328,1329],{"class":45}," \u002Fdev\u002Fnull",[35,1331,1332],{"class":244}," 2>&1\n",[35,1334,1335,1338],{"class":37,"line":259},[35,1336,1337],{"class":41},"ls",[35,1339,1340],{"class":45}," budget_draft.pdf\n",[25,1342,1344],{"className":235,"code":1343,"language":237,"meta":30,"style":30},"from pypdf import PdfReader, PdfWriter\nfrom reportlab.lib.colors import Color\nfrom reportlab.pdfgen import canvas\n\ndef stamp_pdf(src, dst, text=\"DRAFT\"):\n    writer = PdfWriter(clone_from=src)\n    box = writer.pages[0].mediabox\n    w, h = float(box.width), float(box.height)\n    c = canvas.Canvas(\"_stamp.pdf\", pagesize=(w, h))\n    c.setFillColor(Color(0.86, 0.15, 0.15, alpha=0.18))\n    c.setFont(\"Helvetica-Bold\", 110)\n    c.translate(w \u002F 2, h \u002F 2)\n    c.rotate(40)\n    c.drawCentredString(0, -35, text)\n    c.save()\n    stamp = PdfReader(\"_stamp.pdf\").pages[0]\n    for page in writer.pages:\n        page.merge_page(stamp)\n    writer.write(dst)\n    return len(writer.pages)\n\nprint(stamp_pdf(\"budget_draft.pdf\", \"budget_draft_stamped.pdf\"), \"page(s) stamped\")\n",[32,1345,1346,1358,1370,1382,1386,1402,1420,1435,1454,1477,1506,1521,1539,1548,1565,1570,1590,1603,1608,1614,1625,1630],{"__ignoreMap":30},[35,1347,1348,1350,1353,1355],{"class":37,"line":38},[35,1349,245],{"class":244},[35,1351,1352],{"class":255}," pypdf ",[35,1354,600],{"class":244},[35,1356,1357],{"class":255}," PdfReader, PdfWriter\n",[35,1359,1360,1362,1365,1367],{"class":37,"line":259},[35,1361,245],{"class":244},[35,1363,1364],{"class":255}," reportlab.lib.colors ",[35,1366,600],{"class":244},[35,1368,1369],{"class":255}," Color\n",[35,1371,1372,1374,1377,1379],{"class":37,"line":266},[35,1373,245],{"class":244},[35,1375,1376],{"class":255}," reportlab.pdfgen ",[35,1378,600],{"class":244},[35,1380,1381],{"class":255}," canvas\n",[35,1383,1384],{"class":37,"line":329},[35,1385,263],{"emptyLinePlaceholder":262},[35,1387,1388,1390,1393,1396,1398,1400],{"class":37,"line":364},[35,1389,269],{"class":244},[35,1391,1392],{"class":272}," stamp_pdf",[35,1394,1395],{"class":255},"(src, dst, text",[35,1397,279],{"class":244},[35,1399,557],{"class":45},[35,1401,326],{"class":255},[35,1403,1404,1407,1409,1412,1415,1417],{"class":37,"line":375},[35,1405,1406],{"class":255},"    writer ",[35,1408,279],{"class":244},[35,1410,1411],{"class":255}," PdfWriter(",[35,1413,1414],{"class":427},"clone_from",[35,1416,279],{"class":244},[35,1418,1419],{"class":255},"src)\n",[35,1421,1422,1425,1427,1430,1432],{"class":37,"line":384},[35,1423,1424],{"class":255},"    box ",[35,1426,279],{"class":244},[35,1428,1429],{"class":255}," writer.pages[",[35,1431,93],{"class":248},[35,1433,1434],{"class":255},"].mediabox\n",[35,1436,1437,1440,1442,1445,1448,1451],{"class":37,"line":406},[35,1438,1439],{"class":255},"    w, h ",[35,1441,279],{"class":244},[35,1443,1444],{"class":248}," float",[35,1446,1447],{"class":255},"(box.width), ",[35,1449,1450],{"class":248},"float",[35,1452,1453],{"class":255},"(box.height)\n",[35,1455,1456,1459,1461,1464,1467,1469,1472,1474],{"class":37,"line":417},[35,1457,1458],{"class":255},"    c ",[35,1460,279],{"class":244},[35,1462,1463],{"class":255}," canvas.Canvas(",[35,1465,1466],{"class":45},"\"_stamp.pdf\"",[35,1468,288],{"class":255},[35,1470,1471],{"class":427},"pagesize",[35,1473,279],{"class":244},[35,1475,1476],{"class":255},"(w, h))\n",[35,1478,1479,1482,1485,1487,1490,1492,1494,1496,1499,1501,1504],{"class":37,"line":437},[35,1480,1481],{"class":255},"    c.setFillColor(Color(",[35,1483,1484],{"class":248},"0.86",[35,1486,288],{"class":255},[35,1488,1489],{"class":248},"0.15",[35,1491,288],{"class":255},[35,1493,1489],{"class":248},[35,1495,288],{"class":255},[35,1497,1498],{"class":427},"alpha",[35,1500,279],{"class":244},[35,1502,1503],{"class":248},"0.18",[35,1505,361],{"class":255},[35,1507,1508,1511,1514,1516,1519],{"class":37,"line":495},[35,1509,1510],{"class":255},"    c.setFont(",[35,1512,1513],{"class":45},"\"Helvetica-Bold\"",[35,1515,288],{"class":255},[35,1517,1518],{"class":248},"110",[35,1520,403],{"class":255},[35,1522,1523,1526,1528,1530,1533,1535,1537],{"class":37,"line":528},[35,1524,1525],{"class":255},"    c.translate(w ",[35,1527,448],{"class":244},[35,1529,451],{"class":248},[35,1531,1532],{"class":255},", h ",[35,1534,448],{"class":244},[35,1536,451],{"class":248},[35,1538,403],{"class":255},[35,1540,1541,1544,1546],{"class":37,"line":534},[35,1542,1543],{"class":255},"    c.rotate(",[35,1545,1052],{"class":248},[35,1547,403],{"class":255},[35,1549,1550,1553,1555,1557,1560,1562],{"class":37,"line":543},[35,1551,1552],{"class":255},"    c.drawCentredString(",[35,1554,93],{"class":248},[35,1556,288],{"class":255},[35,1558,1559],{"class":244},"-",[35,1561,323],{"class":248},[35,1563,1564],{"class":255},", text)\n",[35,1566,1567],{"class":37,"line":548},[35,1568,1569],{"class":255},"    c.save()\n",[35,1571,1572,1575,1577,1580,1582,1585,1587],{"class":37,"line":940},[35,1573,1574],{"class":255},"    stamp ",[35,1576,279],{"class":244},[35,1578,1579],{"class":255}," PdfReader(",[35,1581,1466],{"class":45},[35,1583,1584],{"class":255},").pages[",[35,1586,93],{"class":248},[35,1588,1589],{"class":255},"]\n",[35,1591,1592,1595,1598,1600],{"class":37,"line":946},[35,1593,1594],{"class":244},"    for",[35,1596,1597],{"class":255}," page ",[35,1599,844],{"class":244},[35,1601,1602],{"class":255}," writer.pages:\n",[35,1604,1605],{"class":37,"line":952},[35,1606,1607],{"class":255},"        page.merge_page(stamp)\n",[35,1609,1611],{"class":37,"line":1610},19,[35,1612,1613],{"class":255},"    writer.write(dst)\n",[35,1615,1617,1619,1622],{"class":37,"line":1616},20,[35,1618,537],{"class":244},[35,1620,1621],{"class":248}," len",[35,1623,1624],{"class":255},"(writer.pages)\n",[35,1626,1628],{"class":37,"line":1627},21,[35,1629,263],{"emptyLinePlaceholder":262},[35,1631,1633,1635,1638,1641,1643,1646,1648,1651],{"class":37,"line":1632},22,[35,1634,551],{"class":248},[35,1636,1637],{"class":255},"(stamp_pdf(",[35,1639,1640],{"class":45},"\"budget_draft.pdf\"",[35,1642,288],{"class":255},[35,1644,1645],{"class":45},"\"budget_draft_stamped.pdf\"",[35,1647,1027],{"class":255},[35,1649,1650],{"class":45},"\"page(s) stamped\"",[35,1652,403],{"class":255},[10,1654,1655,1656,1659,1660,1663,1664,1668],{},"The stamp is drawn at 18% opacity in the middle of the page, rotated 40 degrees, and ",[32,1657,1658],{},"merge_page"," lays it over each page's content — the numbers remain readable through it. Size the stamp from each page's own ",[32,1661,1662],{},"mediabox"," if a document mixes portrait and landscape pages. ",[14,1665,1667],{"href":1666},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fconvert-excel-to-pdf-on-linux-with-libreoffice\u002F","Convert Excel to PDF on Linux with LibreOffice"," covers the conversion step in detail.",[71,1670,80,1675,80,1678,80,1681,80,1684,80,1687,80,1693,80,1697,80,1700,80,1705,80,1710,80,1713,80,1718,80,1722,80,1725,80,1729,80,1732,80,1735,80,1740,80,1744,80,1747,80,1751,80,1754,80,1758,80,1765,80,1770],{"viewBox":1671,"role":74,"ariaLabelledBy":1672,"xmlns":78,"style":79},"4 0 752 125",[1673,1674],"wm-pdf-t","wm-pdf-d",[82,1676,1677],{"id":1673},"Stamping the PDF export",[86,1679,1680],{"id":1674},"The workbook is converted to PDF, reportlab draws a transparent DRAFT page of the same size, pypdf merges it over every page, and the stamped PDF is sent out.",[90,1682],{"x":92,"y":93,"width":94,"height":1683,"fill":96},"125",[90,1685],{"x":99,"y":100,"width":1686,"height":1225,"rx":1226,"fill":136,"stroke":103,"style":1229},"153.0",[146,1688,1690],{"transform":1689},"translate(84.5,29.0) scale(1.000)",[150,1691],{"d":1692,"fill":153,"stroke":1257,"style":1237},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6",[68,1694,1696],{"x":1695,"y":1241,"style":1261},"96.5","budget_draft.xlsx",[68,1698,1699],{"x":1695,"y":1246,"style":213},"the report",[37,1701],{"x1":1702,"y1":1703,"x2":1704,"y2":1703,"stroke":110,"style":1229},"178.0","62.5","200.0",[1706,1707],"polygon",{"points":1708,"fill":1709},"204.0,62.5 195.0,67.5 195.0,57.5","#5b5cf0",[90,1711],{"x":1712,"y":100,"width":1686,"height":1225,"rx":1226,"fill":109,"stroke":110,"style":1229},"209.0",[146,1714,1716],{"transform":1715},"translate(273.5,29.0) scale(1.000)",[150,1717],{"d":1235,"fill":153,"stroke":1276,"style":1237},[68,1719,1721],{"x":1720,"y":1241,"style":1280},"285.5","Convert to PDF",[68,1723,1724],{"x":1720,"y":1246,"style":213},"headless LibreOffice",[37,1726],{"x1":1727,"y1":1703,"x2":1728,"y2":1703,"stroke":110,"style":1229},"367.0","389.0",[1706,1730],{"points":1731,"fill":1709},"393.0,62.5 384.0,67.5 384.0,57.5",[90,1733],{"x":1734,"y":100,"width":1686,"height":1225,"rx":1226,"fill":109,"stroke":110,"style":1229},"398.0",[146,1736,1738],{"transform":1737},"translate(462.5,29.0) scale(1.000)",[150,1739],{"d":1275,"fill":153,"stroke":1276,"style":1237},[68,1741,1743],{"x":1742,"y":1241,"style":1280},"474.5","Draw stamp",[68,1745,1746],{"x":1742,"y":1246,"style":213},"reportlab, 18% opacity",[37,1748],{"x1":1749,"y1":1703,"x2":1750,"y2":1703,"stroke":110,"style":1229},"556.0","578.0",[1706,1752],{"points":1753,"fill":1709},"582.0,62.5 573.0,67.5 573.0,57.5",[90,1755],{"x":1756,"y":100,"width":1686,"height":1225,"rx":1226,"fill":1757,"stroke":164,"style":1229},"587.0","#d9f4f1",[146,1759,1761],{"transform":1760},"translate(651.5,29.0) scale(1.000)",[150,1762],{"d":1763,"fill":153,"stroke":1764,"style":1237},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--teal-ink,#0b6157)",[68,1766,1769],{"x":1767,"y":1241,"style":1768},"663.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Merge onto pages",[68,1771,1772],{"x":1767,"y":1246,"style":213},"pypdf merge_page",[20,1774,1776],{"id":1775},"step-5-do-not-let-openpyxl-remove-it","Step 5 — Do not let openpyxl remove it",[10,1778,1779],{},"A common pipeline builds a workbook with xlsxwriter and then opens it with openpyxl to add a finishing touch. openpyxl keeps the header text but drops the header image itself, so the watermark disappears without an error:",[25,1781,1783],{"className":235,"code":1782,"language":237,"meta":30,"style":30},"import zipfile\nfrom openpyxl import load_workbook\n\ndef media(path):\n    return [n for n in zipfile.ZipFile(path).namelist() if n.startswith(\"xl\u002Fmedia\u002F\")]\n\nwb = load_workbook(\"budget_draft.xlsx\")\nprint(\"header text:\", repr(wb[\"Budget\"].oddHeader.center.text))\nwb.save(\"budget_draft_resaved.xlsx\")\nprint(\"images before:\", media(\"budget_draft.xlsx\"), \"after:\", media(\"budget_draft_resaved.xlsx\"))\n",[32,1784,1785,1792,1804,1808,1818,1845,1849,1862,1884,1894],{"__ignoreMap":30},[35,1786,1787,1789],{"class":37,"line":38},[35,1788,600],{"class":244},[35,1790,1791],{"class":255}," zipfile\n",[35,1793,1794,1796,1799,1801],{"class":37,"line":259},[35,1795,245],{"class":244},[35,1797,1798],{"class":255}," openpyxl ",[35,1800,600],{"class":244},[35,1802,1803],{"class":255}," load_workbook\n",[35,1805,1806],{"class":37,"line":266},[35,1807,263],{"emptyLinePlaceholder":262},[35,1809,1810,1812,1815],{"class":37,"line":329},[35,1811,269],{"class":244},[35,1813,1814],{"class":272}," media",[35,1816,1817],{"class":255},"(path):\n",[35,1819,1820,1822,1825,1827,1830,1832,1835,1837,1840,1843],{"class":37,"line":364},[35,1821,537],{"class":244},[35,1823,1824],{"class":255}," [n ",[35,1826,838],{"class":244},[35,1828,1829],{"class":255}," n ",[35,1831,844],{"class":244},[35,1833,1834],{"class":255}," zipfile.ZipFile(path).namelist() ",[35,1836,516],{"class":244},[35,1838,1839],{"class":255}," n.startswith(",[35,1841,1842],{"class":45},"\"xl\u002Fmedia\u002F\"",[35,1844,833],{"class":255},[35,1846,1847],{"class":37,"line":375},[35,1848,263],{"emptyLinePlaceholder":262},[35,1850,1851,1853,1855,1858,1860],{"class":37,"line":384},[35,1852,612],{"class":255},[35,1854,279],{"class":244},[35,1856,1857],{"class":255}," load_workbook(",[35,1859,620],{"class":45},[35,1861,403],{"class":255},[35,1863,1864,1866,1868,1871,1873,1876,1879,1881],{"class":37,"line":406},[35,1865,551],{"class":248},[35,1867,282],{"class":255},[35,1869,1870],{"class":45},"\"header text:\"",[35,1872,288],{"class":255},[35,1874,1875],{"class":248},"repr",[35,1877,1878],{"class":255},"(wb[",[35,1880,635],{"class":45},[35,1882,1883],{"class":255},"].oddHeader.center.text))\n",[35,1885,1886,1889,1892],{"class":37,"line":417},[35,1887,1888],{"class":255},"wb.save(",[35,1890,1891],{"class":45},"\"budget_draft_resaved.xlsx\"",[35,1893,403],{"class":255},[35,1895,1896,1898,1900,1903,1906,1908,1910,1913,1915,1917],{"class":37,"line":437},[35,1897,551],{"class":248},[35,1899,282],{"class":255},[35,1901,1902],{"class":45},"\"images before:\"",[35,1904,1905],{"class":255},", media(",[35,1907,620],{"class":45},[35,1909,1027],{"class":255},[35,1911,1912],{"class":45},"\"after:\"",[35,1914,1905],{"class":255},[35,1916,1891],{"class":45},[35,1918,361],{"class":255},[10,1920,1921,1922,1924,1925,1928,1929,1933],{},"The header still says ",[32,1923,585],{}," — \"a picture goes here\" — but the picture is gone from the file. Add the watermark as the ",[66,1926,1927],{},"last"," step, with the library that writes the final file, or stamp the PDF. ",[14,1930,1932],{"href":1931},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook\u002F","What openpyxl Loses When Saving an Existing Workbook"," lists the other things a re-save discards.",[20,1935,1937],{"id":1936},"performance-notes","Performance notes",[10,1939,1940],{},"None of these steps is expensive. The header picture is stored once in the file however many pages it prints on, so it adds only the size of the PNG — keep it at a modest resolution, since it is displayed large but faint. Stamping PDFs with pypdf handles hundreds of pages per second; converting the workbook to PDF is the slow part, dominated by LibreOffice's start-up, so batch several workbooks into one conversion call when watermarking a whole set of reports.",[20,1942,1944],{"id":1943},"common-pitfalls","Common pitfalls",[1946,1947,1948,1956,1962,1971,1977],"ul",{},[1949,1950,1951,1955],"li",{},[1952,1953,1954],"strong",{},"Looking in Normal view."," Header pictures only appear in Page Layout view, print preview and printed output.",[1949,1957,1958,1961],{},[1952,1959,1960],{},"An opaque image."," A white background on the PNG hides the cells; save with transparency.",[1949,1963,1964,1967,1968,18],{},[1952,1965,1966],{},"Cropped rotated text."," Rotate with ",[32,1969,1970],{},"expand=True",[1949,1972,1973,1976],{},[1952,1974,1975],{},"Re-saving with openpyxl."," The header image is dropped; watermark last.",[1949,1978,1979,1982,1983,1987],{},[1952,1980,1981],{},"Relying on a watermark for security."," It marks the document; it does not protect it. Combine with ",[14,1984,1986],{"href":1985},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fpassword-protect-an-excel-file-with-python\u002F","Password Protect an Excel File with Python"," when the content matters.",[20,1989,1991],{"id":1990},"conclusion","Conclusion",[10,1993,1994,1995,1998,1999,2002],{},"Draw a pale, rotated, transparent PNG with Pillow. For printed workbooks, put it in the centre header with xlsxwriter's ",[32,1996,1997],{},"set_header(\"&C&[Picture]\", {\"image_center\": ...})"," and open the sheet in Page Layout view; for on-screen marking, use ",[32,2000,2001],{},"set_background",". When the PDF is what people receive, stamp the PDF with reportlab and pypdf instead. Whichever you choose, add the watermark in the final step, because an openpyxl re-save removes header pictures.",[20,2004,2006],{"id":2005},"frequently-asked-questions","Frequently asked questions",[10,2008,2009,2012,2013,2016],{},[1952,2010,2011],{},"How do I add a watermark to an Excel file with Python?","\nCreate a transparent PNG and add it as a header picture with xlsxwriter's ",[32,2014,2015],{},"set_header(\"&C&[Picture]\", {\"image_center\": \"draft.png\"})",". Excel shows it in Page Layout view and prints it on every page.",[10,2018,2019,2022],{},[1952,2020,2021],{},"Why can't I see my watermark in Excel?","\nHeader pictures are hidden in Normal view. Switch to Page Layout view or print preview. If it is missing there too, check whether the file was re-saved with openpyxl, which drops header images.",[10,2024,2025,2028],{},[1952,2026,2027],{},"Can openpyxl add a watermark?","\nopenpyxl can set the header text that references a picture, but it cannot embed the picture, and it removes existing header pictures when it saves. Use xlsxwriter for the watermark, or stamp the PDF.",[10,2030,2031,2034],{},[1952,2032,2033],{},"How do I watermark the PDF version of a report?","\nDraw the watermark on a transparent page with reportlab, then merge that page onto every page of the PDF with pypdf's merge_page and write the result to a new file.",[20,2036,2038],{"id":2037},"related","Related",[1946,2040,2041,2047,2054,2061],{},[1949,2042,2043,2044,2046],{},"Up one level: ",[14,2045,17],{"href":16}," — pictures in and out of workbooks.",[1949,2048,2049,2053],{},[14,2050,2052],{"href":2051},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-logo-image-to-excel-report-with-openpyxl\u002F","Add a Logo Image to an Excel Report with openpyxl"," — placing images in cells rather than headers.",[1949,2055,2056,2060],{},[14,2057,2059],{"href":2058},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fconvert-excel-file-to-pdf-with-python\u002F","Convert Excel File to PDF with Python"," — the conversion before stamping.",[1949,2062,2063,2067],{},[14,2064,2066],{"href":2065},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-print-area-and-page-setup-with-openpyxl\u002F","Set the Print Area and Page Setup with openpyxl"," — the print settings a watermark depends on.",[2069,2070,2071],"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 .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}",{"title":30,"searchDepth":259,"depth":259,"links":2073},[2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084],{"id":22,"depth":259,"text":23},{"id":228,"depth":259,"text":229},{"id":574,"depth":259,"text":575},{"id":985,"depth":259,"text":986},{"id":1288,"depth":259,"text":1289},{"id":1775,"depth":259,"text":1776},{"id":1936,"depth":259,"text":1937},{"id":1943,"depth":259,"text":1944},{"id":1990,"depth":259,"text":1991},{"id":2005,"depth":259,"text":2006},{"id":2037,"depth":259,"text":2038},"2026-09-29","Mark a report as DRAFT or CONFIDENTIAL from Python: make a transparent watermark image with Pillow, place it in the page header with xlsxwriter so it prints on every page, use a sheet background for on-screen marking, stamp the exported PDF with pypdf when the PDF is what gets shared, and avoid the openpyxl re-save that silently removes header images.","md",[2089,2091,2093,2095],{"q":2011,"a":2090},"Create a transparent PNG and add it as a header picture with xlsxwriter's set_header(\"&C&[Picture]\", {\"image_center\": \"draft.png\"}). Excel shows it in Page Layout view and prints it on every page.",{"q":2021,"a":2092},"Header pictures are hidden in Normal view. Switch to Page Layout view or print preview. If it is missing there too, check whether the file was re-saved with openpyxl, which drops header images.",{"q":2027,"a":2094},"openpyxl can set the header text that references a picture, but it cannot embed the picture, and it removes existing header pictures when it saves. Use xlsxwriter for the watermark, or stamp the PDF.",{"q":2033,"a":2096},"Draw the watermark on a transparent page with reportlab, then merge that page onto every page of the PDF with pypdf's merge_page and write the result to a new file.","add a watermark to an excel sheet",null,{"breadcrumb":2100},[2101,2103,2106],{"name":2102,"item":448},"Home",{"name":2104,"item":2105},"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\u002Fadd-a-watermark-to-an-excel-sheet",{"title":2109,"description":2110},"Add a DRAFT or CONFIDENTIAL Watermark to Excel with Python","Excel has no watermark feature, so use a header picture (&G) with xlsxwriter set_header, a set_background image for the screen, or stamp the PDF export with pypdf. Create a transparent rotated PNG with Pillow and keep openpyxl from dropping it.","add-a-watermark-to-an-excel-sheet","formatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet\u002Findex",[2114,2115],"charts-and-images","report-layouts","how-to","5bTWBMh3f59LxP6xNtvdnP82CyLXacoCLryForqwb3w",[2119,2122],{"title":17,"path":2120,"stem":2121,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel","formatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Findex",{"title":2052,"path":2123,"stem":2124,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-logo-image-to-excel-report-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-logo-image-to-excel-report-with-openpyxl\u002Findex",[2126,2128],{"path":2127,"title":2104},"\u002Fformatting-and-charting-excel-reports-with-python",{"path":2120,"title":17},[],[2131,2134,2137,2140,2143,2146],{"path":2132,"title":2133,"kind":2116},"\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":2135,"title":2136,"kind":2116},"\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":2138,"title":2139,"kind":2116},"\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":2141,"title":2142,"kind":2116},"\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":2144,"title":2145,"kind":2116},"\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":2147,"title":2148,"kind":2116},"\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",1790972116582]