[{"data":1,"prerenderedAt":46},["ShallowReactive",2],{"$faBn6wEPDYPym1fZx7t6eXKSSDGAhwisDz1A_3CEQ9S8":3},{"slug":4,"title":5,"description":6,"date":7,"tags":8,"tools":14,"draft":17,"html":18,"toc":19,"minutes":45},"removing-exif-without-recompressing","How I Remove EXIF Data From Photos Without Re-Compressing Them","Cutting metadata out of JPEG segments, PNG chunks and WebP chunks byte by byte, and why ToolOnTap's Remove EXIF tool keeps the orientation and color profile.","2026-10-07",[9,10,11,12,13],"file formats","exif","jpeg","png","webp",[15,16],"remove-exif-data","exif-viewer",false,"\u003Cp>You’re about to post a photo of the sofa you’re selling, taken in your living room. The file very likely knows the GPS coordinates of that living room, the phone model and the minute you took it. Most “remove metadata” tools fix that by redrawing the photo and saving a new JPG, which works, but quietly costs you quality every time. For \u003Ca href=\"\u002Fremove-exif-data\">Remove EXIF data\u003C\u002Fa> I wanted the picture to come out byte for byte the same, with only the metadata cut away.\u003C\u002Fp>\n\u003Ch2 id=\"two-ways-to-remove-metadata\">Two ways to remove metadata\u003C\u002Fh2>\n\u003Cp>The easy way is a canvas. Draw the image, call \u003Ccode>toBlob\u003C\u002Fcode>, and the new file has no EXIF at all, because the browser writes only pixels. Several ToolOnTap tools work like that and drop metadata as a side effect. The price is a second round of JPEG compression, and the color profile is gone too.\u003C\u002Fp>\n\u003Cp>The other way is to treat the file as what it is: a list of labelled blocks. Image formats keep the compressed pixels in some blocks and everything else (EXIF, XMP, comments, previews) in others. If you know which block is which, you can copy the pixel blocks unchanged and leave the rest out. Nothing is decoded and nothing is encoded again, so there’s nothing to lose. That’s what \u003Ccode>utils\u002Fmetadata.ts\u003C\u002Fcode> does for JPEG, PNG and WebP.\u003C\u002Fp>\n\u003Cp>It starts by reading the file’s signature, never its name: \u003Ccode>FF D8 FF\u003C\u002Fcode> for JPEG, the 8-byte \u003Ccode>\\x89PNG\\r\\n\\x1A\\n\u003C\u002Fcode> for PNG, and \u003Ccode>RIFF\u003C\u002Fcode> followed by \u003Ccode>WEBP\u003C\u002Fcode> at byte 8 for WebP. A file named \u003Ccode>.jpg\u003C\u002Fcode> that is really a PNG is cleaned as a PNG.\u003C\u002Fp>\n\u003Ch2 id=\"jpeg-a-chain-of-segments\">JPEG: a chain of segments\u003C\u002Fh2>\n\u003Cp>A JPEG is a series of segments. Each starts with \u003Ccode>0xFF\u003C\u002Fcode>, a marker byte, and a 2-byte length. The marker says what’s inside:\u003C\u002Fp>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>Marker\u003C\u002Fth>\n\u003Cth>What it usually holds\u003C\u002Fth>\n\u003Cth>What the tool does\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>APP1 (\u003Ccode>E1\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>EXIF, or XMP from Adobe apps\u003C\u002Ftd>\n\u003Ctd>Removes it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>APP2 (\u003Ccode>E2\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>ICC color profile, or MPF (extra images)\u003C\u002Ftd>\n\u003Ctd>Keeps the ICC profile, removes the rest\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>APP13 (\u003Ccode>ED\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>IPTC captions, credits, keywords\u003C\u002Ftd>\n\u003Ctd>Removes it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>APP14 (\u003Ccode>EE\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>Adobe color transform information\u003C\u002Ftd>\n\u003Ctd>Keeps it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>COM (\u003Ccode>FE\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>A text comment\u003C\u002Ftd>\n\u003Ctd>Removes it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>APP3 to APP15\u003C\u002Ftd>\n\u003Ctd>Other apps’ data\u003C\u002Ftd>\n\u003Ctd>Removes it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>SOS (\u003Ccode>DA\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>Start of the compressed image\u003C\u002Ftd>\n\u003Ctd>Copies it to the end marker unchanged\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Cp>In code, each rule is one line:\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">let\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> keep \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> true\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (marker \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0xE1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  keep \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> false\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">startsWith\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(b, body, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'Exif\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">\\0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">readExif\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(b.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">subarray\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(body \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 6\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, i \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> +\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> length), report)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  else\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">startsWith\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(b, body, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'http:\u002F\u002Fns.adobe.com\u002F'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)) report.xmp \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> true\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (marker \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0xE2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) keep \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> startsWith\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(b, body, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'ICC_PROFILE\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">\\0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)  \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#57606a;--shiki-dark:#8b949e\">\u002F\u002F drop MPF\u002FFlashPix\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (marker \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0xED\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) { keep \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> false\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">; report.iptc \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (marker \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0xEE\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) keep \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> startsWith\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(b, body, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'Adobe'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)          \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#57606a;--shiki-dark:#8b949e\">\u002F\u002F colour transform info\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (marker \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0xFE\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) { keep \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> false\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">; report.comment \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> true\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">else\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (marker \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">>=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0xE3\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> &#x26;&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> marker \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">&#x3C;=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0xEF\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) keep \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> false\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#57606a;--shiki-dark:#8b949e\">                 \u002F\u002F other apps' data\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Before an EXIF segment is dropped, it’s read, so the page can tell you what it held: the location, the camera, a serial number, the date, the software.\u003C\u002Fp>\n\u003Cp>The image data needs one bit of care. After the SOS marker, the compressed data has no length field; it runs until the end-of-image marker \u003Ccode>FF D9\u003C\u002Fcode>. Inside it, a \u003Ccode>0xFF\u003C\u002Fcode> byte is always followed by \u003Ccode>0x00\u003C\u002Fcode> or a restart marker, never by \u003Ccode>D9\u003C\u002Fcode>, so scanning for \u003Ccode>FF D9\u003C\u002Fcode> finds the real end. Anything after that end is dropped too. Phones and editors sometimes append extra data there, and the code’s own comment names depth maps and edit history as examples.\u003C\u002Fp>\n\u003Ch2 id=\"keeping-the-two-things-you-d-miss\">Keeping the two things you’d miss\u003C\u002Fh2>\n\u003Cp>Removing everything sounds safest, but two pieces of “metadata” change how the photo looks.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>The color profile.\u003C\u002Fstrong> A photo saved in a wide-gamut space such as Display P3 needs its ICC profile, or its colors are read as plain sRGB and come out dull or shifted. The profile says nothing about you, so it stays.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>The orientation.\u003C\u002Fstrong> Phones often store the pixels sideways and add an orientation tag telling viewers to turn them. Remove that tag and the photo appears on its side. So after stripping a JPEG or PNG, the tool writes back a new EXIF block that contains that one value and nothing else:\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> orientationOnlyExif\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\">orientation\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> number\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Uint8Array\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Uint8Array.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">([\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0x4D\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0x4D\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">42\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">8\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0x01\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0x12\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">3\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, orientation, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">])\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Those 26 bytes are a complete, tiny TIFF file. \u003Ccode>MM\u003C\u002Fcode> means big-endian, then the number 42 and the offset of the first directory (8). The directory has 1 entry: tag \u003Ccode>0x0112\u003C\u002Fcode> (orientation), type 3 (a 16-bit number), count 1, and the value. The last 4 zero bytes say there is no next directory. It’s only added when the original orientation wasn’t 1 (upright), so an upright photo gets no EXIF at all.\u003C\u002Fp>\n\u003Cp>Where it goes matters. If the file starts with a JFIF segment (APP0), that has to stay the first segment, so the new EXIF block is placed right after it.\u003C\u002Fp>\n\u003Ch2 id=\"png-chunks-with-checksums\">PNG: chunks with checksums\u003C\u002Fh2>\n\u003Cp>PNG files are a signature followed by chunks. Each chunk has a 4-byte length, a 4-letter type, the data, and a CRC-32 checksum over the type and data. The tool drops five chunk types:\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> PNG_DROP\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> new\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Set\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">([\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'tEXt'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'zTXt'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'iTXt'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'eXIf'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'tIME'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">])\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The three text chunks hold key-value pairs (the tool lists their keys, such as “Software” or “Creation Time”, and spots XMP by its key \u003Ccode>XML:com.adobe.xmp\u003C\u002Fcode>). \u003Ccode>eXIf\u003C\u002Fcode> is EXIF inside a PNG, and \u003Ccode>tIME\u003C\u002Fcode> is the last-modified time. Everything else is copied as it was, including \u003Ccode>iCCP\u003C\u002Fcode>, the color profile, and every \u003Ccode>IDAT\u003C\u002Fcode> chunk with the pixels.\u003C\u002Fp>\n\u003Cp>Copied chunks keep their original checksums, which stay valid because their bytes don’t change. The one chunk the tool creates, an \u003Ccode>eXIf\u003C\u002Fcode> with only the orientation, needs a fresh CRC-32. The code computes it with the standard table-based CRC (polynomial \u003Ccode>0xEDB88320\u003C\u002Fcode>), and puts the chunk right after \u003Ccode>IHDR\u003C\u002Fcode>, the header chunk. Anything after \u003Ccode>IEND\u003C\u002Fcode> is dropped.\u003C\u002Fp>\n\u003Ch2 id=\"webp-riff-chunks-and-two-flags\">WebP: RIFF chunks and two flags\u003C\u002Fh2>\n\u003Cp>WebP uses RIFF, a container where each chunk has a 4-letter type and a little-endian length, padded to an even size. The tool drops the original \u003Ccode>EXIF\u003C\u002Fcode> and \u003Ccode>XMP \u003C\u002Fcode> chunks (the space is part of the name) and keeps the rest, including \u003Ccode>ICCP\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Two more fixes keep the file valid. An extended WebP has a \u003Ccode>VP8X\u003C\u002Fcode> chunk with flags that announce which optional chunks exist. Left as they were, they would announce chunks the file no longer has, so the XMP bit (\u003Ccode>0x04\u003C\u002Fcode>) is cleared, and the EXIF bit (\u003Ccode>0x08\u003C\u002Fcode>) stays on only when the photo was rotated: then, as for JPEG and PNG, a new \u003Ccode>EXIF\u003C\u002Fcode> chunk holding just the orientation is added at the end. And the RIFF header at the top stores the total file size, which has to be rewritten because the file has changed.\u003C\u002Fp>\n\u003Ch2 id=\"the-thumbnail-you-can-t-see\">The thumbnail you can’t see\u003C\u002Fh2>\n\u003Cp>This is the item people don’t expect. Many JPEGs carry a small preview inside the EXIF block, in a second directory (IFD1, marked by tag \u003Ccode>0x0201\u003C\u002Fcode>). Cameras use it to show photos quickly.\u003C\u002Fp>\n\u003Cp>Some editing apps update the main image when you crop it but leave that thumbnail alone. So a photo cropped to hide a house number, a face or a screen can still contain a small copy of the uncropped original. The tool reports “embedded thumbnail” when it finds one, and since the thumbnail lives in the EXIF segment, it goes when that segment goes.\u003C\u002Fp>\n\u003Ch2 id=\"how-i-check-it\">How I check it\u003C\u002Fh2>\n\u003Cp>The tests build JPEG, PNG and WebP files in memory, with a fake iPhone EXIF block that includes Cairo coordinates, a serial number and a thumbnail. They check that:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>every sensitive string is gone from the output, and the ICC profile, the Adobe segment and the image data are still there;\u003C\u002Fli>\n\u003Cli>the compressed image bytes at the end of the JPEG are identical to the input;\u003C\u002Fli>\n\u003Cli>JFIF is still the first segment;\u003C\u002Fli>\n\u003Cli>stripping a cleaned file again changes nothing and finds nothing except the orientation;\u003C\u002Fli>\n\u003Cli>a file with no metadata comes back byte for byte the same, and the page says “No hidden data found. The file is unchanged.”;\u003C\u002Fli>\n\u003Cli>damaged EXIF data never throws, it only yields less. A directory can’t claim more than 512 entries.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The whole job runs in your browser, so the original photo never has to be uploaded to be cleaned.\u003C\u002Fp>\n\u003Ch2 id=\"try-it\">Try it\u003C\u002Fh2>\n\u003Cp>Drop JPG, PNG or WebP photos on \u003Ca href=\"\u002Fremove-exif-data\">Remove EXIF data\u003C\u002Fa> to see what each one contains and download clean copies. To see every detail a photo carries before you decide, open it in the \u003Ca href=\"\u002Fexif-viewer\">EXIF viewer\u003C\u002Fa>. iPhone HEIC photos are a different format built from boxes; \u003Ca href=\"\u002Farticles\u002Freading-heic-exif-by-hand\">reading HEIC EXIF by hand\u003C\u002Fa> explains how they’re read, and \u003Ca href=\"\u002Fheic-to-jpg\">HEIC to JPG\u003C\u002Fa> converts them into a JPG without the location.\u003C\u002Fp>\n",[20,24,27,30,33,36,39,42],{"id":21,"text":22,"level":23},"two-ways-to-remove-metadata","Two ways to remove metadata",2,{"id":25,"text":26,"level":23},"jpeg-a-chain-of-segments","JPEG: a chain of segments",{"id":28,"text":29,"level":23},"keeping-the-two-things-you-d-miss","Keeping the two things you’d miss",{"id":31,"text":32,"level":23},"png-chunks-with-checksums","PNG: chunks with checksums",{"id":34,"text":35,"level":23},"webp-riff-chunks-and-two-flags","WebP: RIFF chunks and two flags",{"id":37,"text":38,"level":23},"the-thumbnail-you-can-t-see","The thumbnail you can’t see",{"id":40,"text":41,"level":23},"how-i-check-it","How I check it",{"id":43,"text":44,"level":23},"try-it","Try it",6,1792325801062]