SUBMIT A FILE TYPE CONTACT US SUPPORT ABOUT US

What Is a JPG File? The Compressed Picture That Also Stores Where and When You Took It

JPG files are compressed pictures that can also store places, times and extra bytes, and decoders accept edited ones with no warning. Jump to your question below, or work through it in order.

40 min read Updated October 2026 Checked against sources and tests

What Is a JPG File? A picture saved in marked segments, and the ending is only a label

Short answer

JPG files are pictures saved with lossy JPEG compression and stored as chains of marked segments. Besides the pixels, they can store the camera make, the time, GPS positions and even other files. The first three bytes, FF D8 FF, are the usual sign of one, and the ending .jpg is only a label.

We read 1,052 public JPG files, made 15 of our own and damaged one JPG file in 50 ways. Five decoders and our script handled the 50 copies in different ways, and only 2 copies gave the same answer in all six. Nine edits to the metadata passed all five decoders with no warning.

To see what a JPG file stores about you, read the privacy part. To check one, read the six steps. If your JPG file will not open, begin with the eight causes.

The ending .jpg is only a label. What makes a file a JPG file is its first bytes, FF D8 FF, and the chain of segments after them. Those segments can store more than the picture, so two JPG files can differ widely inside.

Picture a phone photo that arrives by email as IMG_2041.jpg. It opens in every app you own, so it feels like one flat picture. Inside, it is a list of segments. Some segments store pixels, and others store the camera, the day, the place and small previews.

Wikipedia on JPEG says the Joint Photographic Experts Group made the format, and that ISO/IEC 10918 and ITU-T T.81 define it. The first public release came on 18 September 1992. The same page lists .jpg, .jpeg, .jpe, .jif, .jfif and .jfi as endings. It names image/jpeg as the MIME type.

FileInfo says .jpeg and .jpg name the same JPG file format, and that .jpg is more common because early Windows allowed only three letters after the dot. It files the format under raster images and says it uses lossy compression to cut the size with little visible loss.

Two more names matter. JFIF is the wrapper that most JPG files use, and Exif is the camera metadata format. Wikipedia on JFIF says Eric Hamilton of C-Cube led JFIF. Wikipedia on Exif says Exif lives in the APP1 segment and can store location, time and device identifiers.

Where our JPG files come from

We worked with three sets of JPG files. We read 1,052 public JPG files from 13 sources, which are 12 code projects and the Go standard library. We made 15 JPG files ourselves, starting from one base file, base.jpg. We also damaged copies of base.jpg in 50 ways and read every copy with six readers.

The public JPG files are test and sample files. About 316 are camera samples from the metadata extractor project, and 98 more are test cases made to break readers. The rest come from image libraries, with 279 from the sharp tests alone. Odd files are common, so the counts show what projects collect and not what phones send.

The ending is no guide to what JPG files contain. Two JPG files can differ in compression, color layout, metadata and extra bytes at the end. Our tests below show what the segments say and what happens when they change.

JPG file facts at a glance

Quick facts about JPG files
Property Value
Meaning Joint Photographic Experts Group, the group that made the format. The files use lossy compression for continuous tone pictures.
Endings .jpg and .jpeg for the same format. Wikipedia also lists .jpe, .jif, .jfif and .jfi.
Start FF D8, the start marker. IANA and Wikipedia give FF D8 FF as the magic number.
MIME type image/jpeg, registered with IANA.
Size limit Wikipedia says 65,535 by 65,535 pixels for JPEG and JFIF.
Usual metadata JFIF in 384 of our 956 parsed public JPG files and Exif in 547. Another 211 store neither.
Our base file base.jpg has 15,745 bytes and 480 by 320 pixels, and about 90 percent of its bytes are picture data.
Opens with Every browser, phone and photo app. Windows Photos, Apple Preview and Paint also open JPG files.
Our tests 1,052 public JPG files, 15 made files, 50 damaged copies and six readers, on Linux. We opened no JPG file in a viewer.

Wrong page? Look at the PNG file for lossless pictures, the GIF file for short animations and the BMP file for raw bitmaps.

What Is Inside a JPG File? Four bands, and 90 percent of the bytes are the picture

A JPG file is a chain of segments, and every segment starts with FF and a marker byte. In base.jpg, 940 bytes are metadata and 603 bytes are tables and headers. The other 14,198 bytes are picture data, and the JPG file has 15,745 bytes in all.

We made base.jpg with Pillow from a drawn picture of 480 by 320 pixels at quality 85. We added camera make, time, GPS position, color profile and comment data, so that every part has something to read. The figure shows its parts in file order.

The layout of base.jpg, a 15,745 byte JPG file. It starts with the two byte start marker, then a JFIF segment, an Exif segment with the camera make, the date and a GPS position, an ICC color profile segment and a comment. Two quantization tables, the frame header, four Huffman tables and the scan header follow. The scan data takes 14,198 bytes, about 90 percent of the file, and the two byte end marker closes it.
One JPG file from our tests, from the first byte. The bands follow the order of the segments in the file we call base.jpg.

Read the figure from the top. The file starts with FF D8 and ends with FF D9. The segments between them all begin with FF, a marker byte and a length. The Library of Congress record names the same markers, with FF C0 for a baseline frame and FF C2 for a progressive one.

The first bytes and the marker list

The first 32 bytes of base.jpg
00000000: ffd8 ffe0 0010 4a46 4946 0001 0100 0001  ......JFIF......
00000010: 0001 0000 ffe1 011b 4578 6966 0000 4d4d  ........Exif..MM

The first two bytes are the start marker. The next four are FF E0 00 10, a JFIF segment with a length of 16 bytes. Then comes the word JFIF and a null byte. The segment after it starts with FF E1, and its letters spell Exif.

Every marker in base.jpg, with its offset and length
 byte  marker length  what
    0  FF D8  -       start of image
    2  FF E0  16      JFIF segment
   20  FF E1  283     Exif segment
  305  FF E2  604     ICC profile
  911  FF FE  29      comment
  942  FF DB  67      quantization table
 1011  FF DB  67      quantization table
 1080  FF C0  17      baseline frame header
 1099  FF C4  31      Huffman table
 1132  FF C4  181     Huffman table
 1315  FF C4  31      Huffman table
 1348  FF C4  181     Huffman table
 1531  FF DA  12      scan header
 1545  -      14198   picture data
15743  FF D9  -       end of image

A segment length counts its own two length bytes and not the marker. The reader adds 2 to the length and lands on the next marker. This is why a bad length value, like in our A5 and A6 copies, sends readers to the wrong place.

The metadata segments

Metadata segments of base.jpg
Segment What the sources say In base.jpg
APP0 JFIF The JFIF segment follows the start marker. Wikipedia lists the version, a density unit, two density values and an optional thumbnail. Version 1.01, density 1 by 1 with no unit
APP1 Exif Exif lives in the APP1 segment as a TIFF structure. The segment is limited to 64 KB, per Wikipedia. Make, orientation, date and GPS in 285 bytes
APP2 ICC A color profile can follow in the APP2 segment. It is our choice of segment here and not a rule from the sources above. An sRGB profile of 606 bytes
COM comment A free text segment that readers ignore. The words made by us for the JPG page

JFIF and Exif both want to come first. Wikipedia says the two are mutually incompatible for that reason, yet many cameras and programs write both. Our public JPG files agree with it. Of 956 parsed files, 197 store both segments and 350 store Exif without JFIF.

The tables, the frame and the picture

Two quantization tables set how much detail every block keeps. The frame header gives the size, bit depth and sampling. Four Huffman tables decode the bits that follow. Then the scan header starts the picture data, which is 14,198 bytes in base.jpg.

In the picture data, every FF byte is followed by 00, so it cannot be mistaken for a marker. Restart markers, FF D0 to FF D7, can also appear. A reader walks these bytes until it meets the next marker. For base.jpg that is FF D9 at byte 15,743.

Most bytes are picture. In base.jpg, 90 percent of the bytes are scan data and 6 percent are metadata. That share changes from file to file. The largest tail in our public JPG files has 18,469,861 bytes, and no decoder reads it.

What Do JPG Files Store? Three in four Exif files name a camera, and 83 files have a tail

The ending .jpg says nothing about what JPG files contain. Of 956 public JPG files that parse, 872 are baseline and 77 are progressive. Exif is in 547 files, GPS positions in 66 and bytes after the end marker in 83.

Two JPG files can look alike in a file manager and differ inside. We counted the compression mode, the chroma sampling, the metadata segments and the extra bytes in the public JPG files. The figure shows the counts.

What the parsed public JPG files store. Of 956 files that reach a frame header, 872 are baseline and 77 progressive. 516 sample the color at half width and half height. 547 store Exif, 384 JFIF, 176 XMP, 107 an Adobe segment and 105 an ICC profile, and 211 store none of these. 66 of the Exif blocks name a GPS position and 67 an orientation that is not upright. 83 files have bytes after the end marker.
Counts are for the 956 of 1,052 public files that reach a frame header. Every bar shows a share of the 956.

The compression modes

Compression modes in the public JPG files
Mode What it does Public files
Baseline The common mode. Wikipedia says coefficients are coded block by block. The frame marker is FF C0. 872 of 956
Progressive Several scans of rising detail, so a slow page can show a rough picture first. The frame marker is FF C2. 77 of 956
Extended The same family with more tables or 12 bit samples. The frame marker is FF C1. 5 of 956
Arithmetic and lossless Wikipedia calls both rare. We found one arithmetic file and one lossless file. 2 of 956

Chroma sampling shows how much color detail a JPG file keeps. We saw 516 files with 4:2:0, 212 with 4:2:2 and 151 with 4:4:4. Another 49 files have one or four color channels, like grayscale and CMYK pictures. Our base.jpg uses 4:2:0.

What the metadata stores

Of 956 parsed JPG files, 547 store Exif, 384 store JFIF and 176 store an XMP packet. Another 107 store an Adobe segment, 105 store an ICC profile and 33 store a comment. A total of 211 store none of these. Many of those come from image library tests, which write bare files.

Among the 547 Exif files, 409 name a camera make and 404 store the time the picture was taken. Another 66 store GPS positions, which is 12 percent. A further 67 store an orientation other than upright, and 31 of those say rotated 90 right.

Bytes after the end marker

Of the 956 JPG files, 83 have bytes after FF D9. Of those 83, 28 start with a second JPEG file. Three are only zeros, and 7 start with text. The largest tail is 18,469,861 bytes. A reader that stops at the end marker never sees any of it.

The ending is not the content Files with the same ending differ in mode, sampling, metadata and tail.
Place and time are common Three in four Exif files store the camera make and the date. One in eight stores a place.
Orientation lives in metadata The pixels can be sideways while a tag says how to show them.
Tails are not rare One file in twelve has bytes after the end marker.

Not sure the file is a JPG file at all? Check it with our script.

What Did We Find in 1,052 Public JPG Files? Six readers, and 16 files that only djpeg accepted

Six readers saw our 1,052 public JPG files in nearly the same way. All six accepted 904 files, which is 86 percent, and none accepted 69. The other 79 files split the readers, and 16 passed in djpeg alone.

We searched 13 public sources for JPG files and found 1,052 different ones. Many are made to be odd, so this study shows what readers do with sample and test JPG files and not what servers send. The figure shows how many files every reader accepted.

1,052 public JPG files
904 accepted by all six readers
69 refused by all six readers
16 accepted by djpeg alone
Six readers on 1,052 public JPG files. Our script accepted 956, djpeg 958, Pillow 930, Go 915, Rust 922 and jpeg-js 916. All six accepted 904 files and none accepted 69.
Bars show how many of the 1,052 public files a reader accepted. A warning still counts as accepted.

The six readers

Our script is the 139 line Python program in the check part. It walks the markers, reads the Exif values and notes every rule that a JPG file breaks, and it decodes no pixels.

The other five readers decode the picture. They are djpeg from libjpeg-turbo 2.1.5, Pillow 12.3.0, the Go 1.24.7 standard library, the Rust crate zune-jpeg 0.4.21 and jpeg-js 0.4.4 on Node 22.

Pillow and djpeg use the same C library, so they differ only in the policy of the wrapper. We counted JPG files as accepted when readers returned pictures, even with warnings. For the decoders we saved hashes of the pixels, to see if copies gave the same picture as the intact JPG file.

Where the readers agree

All six readers accepted 904 JPG files. In every file that two or more decoders accepted, they reported the same width and height. We found no case where one decoder saw a larger picture than another. The exact pixel values differ in more files, but we compared them only against the same reader, never across readers.

All six readers refused 69 JPG files. Most are broken on purpose. Forty seven come from the test suite of the metadata extractor project, and 21 come from the PHP exif tests. Nearly all have no frame header or no start marker. One comes from the sharp tests.

Where the readers split

Strictness differs widely. The djpeg tool accepted 958 files and Rust 922. Go accepted 915 and jpeg-js 916.

Pillow accepted 930, which is 28 fewer than djpeg, although both call the same library. Pillow refused 29 files that djpeg accepted, and accepted 1 that djpeg refused. Pillow refuses a cut file by default, while djpeg decodes what it can and prints a warning.

The 16 JPG files that only djpeg accepted all have extra bytes before a marker, from 4 to 42 bytes. The djpeg tool skips them and warns. Rust refuses 65 files for the same reason and names its strict mode. Go refuses 25 because a byte sequence is missing.

Go refused 43 JPG files that djpeg accepted, and accepted none that djpeg refused. Rust accepted 18 that Go refused, and Go accepted 11 that Rust refused. Go also refused 26 files with the words unsupported JPEG feature, like an unusual chroma ratio or an unknown marker, which is not the same as broken.

Readers differ in strictness djpeg skips extra bytes with a warning. Rust, Go and jpeg-js refuse them.
Test files are odd on purpose Cut files, wrong lengths and fuzz cases fill the set, so many refusals are correct.
Sizes agree Every decoder that accepted a JPG file reported the same width and height.
Camera files pass Of 316 camera samples from one project, 311 passed all six readers. Of its 98 test cases, 3 did.

Read the study with care. It shows what six readers do with 1,052 public JPG files. We opened no JPG file in browsers, phones or photo apps, and we did not check how any file was made. Readers that agree on these files can still differ on yours.

What Do Readers Do With a Damaged JPG File? 50 broken copies, six readers and nine silent edits

We damaged one JPG file in 50 ways and read every copy with six readers. Only 2 of the 50 copies gave the same answer in all six, and 6 were refused by all six. Nine edits to the metadata passed all five decoders with no warning, and so did a zip after the end marker.

The base file, base.jpg, has 15,745 bytes. We changed one thing at a time and sorted the 50 damaged JPG files into 6 groups. The groups cover the start and the segments, the tables and the frame, and what the JPG file says about itself. They also cover the picture data and the size, with the wrapping and extras last.

A grid of 50 damaged copies of one JPG file and six readers. Nine edits to what the file says about itself changed no pixel in five decoders, and none warned. A zip archive after the end marker passed all five decoders. Two copies gave the same answer in all six readers and six were refused by all six.
Rows are damaged copies. Green means the same answer as the intact file, amber means another answer with no warning and red means a warning or a refusal.

Green means the reader gave the same answer as for the intact JPG file. For the five decoders that means the same pixels. Amber means it gave another answer with no warning. Red means a warning or a refusal. Our script compares the summary it prints, so it also sees changes to the metadata.

Edits to the metadata pass every decoder

Nine copies change only what the JPG file says about itself. Two remove the JFIF segment (A3) and the Exif segment (A4).

The other seven set orientation to rotated (C1) and move GPS latitude from 12 to 48 (C2). They also remove the GPS block (C3), add an XMP packet (C5) and remove the ICC profile (C6). The last two set the date to 2001 (C7) and change camera make (C9).

All five decoders returned the same pixels for all nine copies, and none warned. Only our script showed a change, because it prints the Exif values. A picture viewer that obeys the orientation tag would show C1 sideways, even though every decoder returned the same pixels.

The same is true for extra bytes. Four copies add data after the end marker. They are a zip archive (F2), a second small JPEG (F3), 1 KB of zeros (F1) and 1 MB of zeros (F8). All four passed the five decoders with the same pixels.

Python and unzip read the zip inside F2 and listed its note.txt file. Our script warned about the extra bytes.

What the groups show

Results by group of damaged JPG files
Group What we found
A. Start and segments A changed first byte (A1) and a repeated start marker (A7) were refused by all six. Three junk bytes in front (A2) stopped all five decoders, and only our script read past them. Wrong JFIF lengths (A5, A6) split the readers three ways. Removing JFIF or Exif (A3, A4) changed no pixel.
B. Tables and frame With no quantization tables (B1), four decoders refused and Go gave a different picture with no warning. With no Huffman tables (B2), djpeg and Pillow decoded the same pixels and the other three refused. Setting every quantization value to 1 (B4) changed the picture in all five decoders with no warning. A width of 481 (B7) and a doubled height (B6) gave different pictures in Pillow and Rust.
C. What the file says about itself All nine edits changed the metadata only, and no decoder noticed any. Our script showed seven of them. A new comment (C4) and a density of 300 dots per inch (C8) changed no answer in any of the six readers, our script included, because it prints neither.
D. Picture data One flipped byte (D1) made djpeg warn and Go and jpeg-js refuse. Pillow and Rust gave a different picture. Ten flipped bytes (D2) were refused by four decoders, and Rust returned a picture. Moving or deleting bytes (D3 to D7) split the readers in similar ways. A marker inside the scan (D8) made djpeg warn and Go and jpeg-js refuse. Pillow gave another picture.
E. Size A file cut at 90, 50 or 10 percent (E1 to E3) made djpeg warn and Pillow, Go and jpeg-js refuse. Rust gave a different picture with no warning. With no end marker (E4), Rust returned the same pixels. An empty file (E6) and a JPG file with only start and end markers (E7) were refused by all six.
F. Wrapping and extras Base64 text (F4) and gzip (F5) were refused by all six. A PNG with a JPG name (F6) was refused by four decoders, and Pillow opened it, because it goes by content and not by the ending. HTTP headers on top (F7) stopped all five decoders. Extra bytes after the end passed all five.

Which readers warn

On the 50 copies, only djpeg and our script warned. Pillow, Go, Rust and jpeg-js warned on none. Go refused 31 copies and jpeg-js refused 33, which makes them the strictest. Rust returned another picture for 13 copies and Pillow for 11, and neither said so.

The djpeg tool warned on 18 copies and refused 14. Our script flagged 16, refused 9 and passed 14 with another summary. A reader that forgives more is not safer, because it can hide the damage from you.

Read the grid with care. Green cells mean only that a reader gave the same answer as for the intact JPG file. We opened no copy in browsers or photo apps, so the grid shows decoding and nothing else. Every test changed one thing in a single JPG file that we made.

What Does Our Expert Say About JPG Files? A note from Neeraj Singh on reading before sharing

Read the Exif data of a JPG file yourself before you share it. Nine edits to the metadata and four kinds of extra bytes passed five decoders with no warning, and only a script that reads the metadata saw them. A scan of the first bytes takes seconds.

Neeraj Singh

Expert insight

JPG files look like only pictures, but they also store where and when you took them. In our tests, nine edits to the metadata, like a new place, another date or a new rotation, changed no pixel, and none of five decoders warned. Read the Exif data yourself and look for bytes after the end marker. Remove the metadata before you share a photo.

Neeraj Singh Manager, Tech Support & Operations 19+ years fixing Windows and system errors

Why a decoder proves little

A decoder that opens a JPG file shows that the picture data makes sense to that decoder. It does not show what else the JPG file stores. In our tests the five decoders returned the same pixels for nine copies with other metadata, so a JPG file that opens everywhere can still name a place.

Two decoders that agree on a JPG file can both miss the tail. Neither says whether a zip follows the end marker or whether the Exif block names a street. The script from the check part reads the markers, the Exif values and the end of the JPG file. Compare its answer with a second reader.

Hash the file first. The SHA256 hash of a JPG file shows which copy you have, and it shows if a transfer changed it later. Keep the original read only, and work on copies of JPG files.

How Do You Open a JPG File? Every viewer opens it, so look inside with a second tool

Open a JPG file by double clicking it. Every browser, phone and photo app opens JPG files, and Windows, macOS, Android and iOS include viewers. Viewers show the picture and hide what else the JPG file stores, so read the metadata and the end of the file with a second tool.

Opening JPG files is the easy part. The FileInfo entry lists Microsoft Photos and Paint for Windows, and Apple Preview and Photos for Mac. For phones it lists Google Photos and Apple Photos. For the web it lists Google Drive, OneDrive and iCloud Photos. Chrome opens JPG files too.

We opened no JPG file in these apps. Our tests used decoders and a script, so do not read our grid as a test of Photos, Preview or Chrome. The sections below cover what to use when a double click fails or when you want to look inside.

Look inside with a command line

The four commands below hash the JPG file, show its first 16 bytes, decode it with djpeg and use our script. The first two work on any computer with a shell. The djpeg tool comes with libjpeg-turbo, and the script in the check part is ours.

Four commands to read a JPG file without opening a viewer
sha256sum base.jpg
head -c 16 base.jpg | xxd
djpeg -ppm base.jpg > /dev/null
python3 jpg_peek.py base.jpg

The djpeg tool prints warnings on any trouble and writes the picture to a PPM file, which is why we sent it to the null device. A silent result is good for the picture, but it says nothing about the metadata and the tail. Our script covers those two.

Two Windows viewers

These cards link to the two Windows programs that name JPG files on their own pages. Both pages say the free version has a limit, and we did not install either one.

SysTools JPG Converter

Batch converts JPG files on Windows

Trial converts 5 files

Freeviewer Image Viewer

Opens and previews image files on Windows

Demo opens and reads only

The SysTools page describes a Windows converter. It adds single files or folders, previews and resizes the pictures and writes one file or one file per picture. It lists PDF, DOC, DOCX, HTML, TXT, PNG, BMP, TIFF, TGA, APNG, WEBP, GIF, JPEG and JPEG 2000 as outputs.

Its free version converts the first 5 JPG files, and PDF, DOC and DOCX outputs get a watermark.

The Freeviewer page describes a Windows viewer that opens and previews image files of many types, among them JPG, JPEG, PNG, GIF, BMP and TIFF. It lists bulk adding, reordering and printing. Its free demo opens and reads files, and its export is limited to the first 5 images. The page says there are no limits on file size.

How the readers did on our 50 damaged copies

How every reader did on our 50 damaged JPG files
Reader Result
Our script Same answer on 11 copies, another summary with no warning on 14, flags on 16 and refusals on 9. It reads the metadata, so it sees edits that decoders miss.
djpeg Same on 17 copies, another picture on 1, a warning on 18 and a refusal on 14. It is the only decoder that warns.
Pillow Same on 20 copies, another picture with no warning on 11 and a refusal on 19.
Go Same on 17 copies, another picture on 2 and a refusal on 31.
Rust Same on 17 copies, another picture with no warning on 13 and a refusal on 20.
jpeg-js Same on 16 copies, another picture on 1 and a refusal on 33.

How Do You Check a JPG File? Six steps, and a 139 line script

Check a JPG file in six steps. Hash it and read its first bytes. Then decode it, use a script that prints the markers and the Exif values, read the end of the JPG file and compare with a second decoder. No decoder shows what the metadata says.

The six steps

  1. Copy the JPG file, write down its SHA256 hash and work on the copy.
  2. Read the first bytes with head -c 16 file.jpg | xxd. JPG files start with FF D8 FF. Anything else, like text or 89 50 4E 47, means the ending is wrong.
  3. Decode the JPG file with djpeg -ppm file.jpg > /dev/null. It prints a warning when the data is cut or damaged.
  4. Use the script below. It prints the kind, size, sampling and metadata, and then the GPS position, camera make and date.
  5. Read the notes at the end of its output. Bytes after the end marker, a missing end marker and a damaged Exif block get a line of their own.
  6. Open the JPG file in a second reader and compare the answers. If you plan to share the JPG file, remove the metadata first with the steps in the privacy part.

A 139 line script that reads the JPG file

The Python script below does steps 4 and 5 in about a second. It walks the segments, reads the Exif values and compares the JPG file with the rules we listed. It prints REFUSED when it cannot go on, and a note for every smaller worry. It decodes no pixels, and it changes no JPG file.

jpg_peek.py
import sys, struct

SOF = {0xC0: 'baseline', 0xC1: 'extended', 0xC2: 'progressive', 0xC3: 'lossless',
       0xC9: 'arithmetic', 0xCA: 'arithmetic progressive', 0xCB: 'arithmetic lossless'}
ROT = {1: 'upright', 2: 'mirrored', 3: 'rotated 180', 4: 'flipped', 5: 'transposed',
        6: 'rotated 90 right', 7: 'transversed', 8: 'rotated 90 left'}

def ifd(t, off, e):
    out = {}
    for i in range(struct.unpack(e + 'H', t[off:off + 2])[0]):
        tag, typ, cnt, val = struct.unpack(e + 'HHI4s', t[off + 2 + 12 * i:off + 14 + 12 * i])
        at = struct.unpack(e + 'I', val)[0]
        if typ == 3:
            out[tag] = struct.unpack(e + 'H', val[:2])[0]
        elif typ == 4:
            out[tag] = at
        elif typ == 2:
            out[tag] = (val[:cnt] if cnt <= 4 else t[at:at + cnt]).split(b'\0')[0].decode('latin1')
        elif typ == 5 and cnt == 3:
            r = struct.unpack(e + '6I', t[at:at + 24])
            out[tag] = r[0] / r[1] + r[2] / r[3] / 60 + r[4] / r[5] / 3600
    return out

def exif_facts(seg):
    t = seg[6:]
    e = '<' if t[:2] == b'II' else '>'
    a = ifd(t, struct.unpack(e + 'I', t[4:8])[0], e)
    b = ifd(t, a[0x8769], e) if 0x8769 in a else {}
    g = ifd(t, a[0x8825], e) if 0x8825 in a else {}
    info = []
    if a.get(0x0112, 1) != 1:
        info.append('orientation tag says ' + ROT.get(a[0x0112], str(a[0x0112])))
    if 2 in g and 4 in g:
        info.append('GPS %.4f %s, %.4f %s' % (g[2], g.get(1, ''), g[4], g.get(3, '')))
    if 0x010F in a:
        info.append('camera make: ' + a[0x010F])
    if 0x9003 in b:
        info.append('taken ' + b[0x9003])
    return info

def scan_end(d, pos):
    """Step over the entropy coded data and return the offset of the next marker."""
    while pos + 1 < len(d):
        j = d.find(b'\xff', pos)
        if j < 0 or j + 1 >= len(d):
            return len(d)
        if d[j + 1] == 0 or 0xD0 <= d[j + 1] <= 0xD7:
            pos = j + 2
            continue
        return j
    return pos

def peek(path):
    d = open(path, 'rb').read()
    notes, meta, info = [], [], []
    i = d.find(b'\xff\xd8')
    if i < 0:
        return None, ['REFUSED: no start marker FF D8'], []
    if i > 0:
        notes.append('%d bytes before the start marker' % i)
    pos, sof, dqt, dht, eoi = i + 2, None, 0, 0, None
    while pos + 4 <= len(d):
        if d[pos] != 0xFF:
            notes.append('data where a marker should be at byte %d' % pos)
            break
        m = d[pos + 1]
        if m == 0xFF or m == 0x01 or 0xD0 <= m <= 0xD7:
            pos += 1 if m == 0xFF else 2
            continue
        if m == 0xD9:
            eoi = pos
            break
        ln = struct.unpack('>H', d[pos + 2:pos + 4])[0]
        seg = d[pos + 4:pos + 2 + ln]
        if pos + 2 + ln > len(d):
            notes.append('a segment goes past the end of the file')
            break
        if m in SOF:
            sof = (SOF[m], seg[0], struct.unpack('>HH', seg[1:5]), seg[5], seg[6:15])
        elif m == 0xDB:
            dqt += 1
        elif m == 0xC4:
            dht += 1
        elif m == 0xFE:
            meta.append('comment')
        elif m == 0xE0 and seg[:4] == b'JFIF':
            meta.append('JFIF %d.%02d' % (seg[5], seg[6]))
        elif m == 0xE1 and seg[:4] == b'Exif':
            meta.append('Exif')
            try:
                info += exif_facts(d[pos + 4:pos + 2 + ln])
            except Exception:
                notes.append('the Exif block is damaged')
        elif m == 0xE1 and b'ns.adobe.com/x' in seg[:40]:
            meta.append('XMP')
        elif m == 0xE2 and seg[:11] == b'ICC_PROFILE':
            meta.append('ICC profile')
        elif m == 0xEE and seg[:5] == b'Adobe':
            meta.append('Adobe')
        pos += 2 + ln
        if m == 0xDA:
            pos = scan_end(d, pos)
            if d[pos:pos + 2] == b'\xff\xd9':
                eoi = pos
                break
    if sof is None:
        return None, ['REFUSED: no frame header, so no size and no pixels'], []
    if eoi is None:
        notes.append('no end marker FF D9, the file looks cut')
    elif len(d) - eoi - 2 > 0:
        notes.append('%d bytes after the end marker' % (len(d) - eoi - 2))
    if dqt == 0:
        notes.append('no quantization table')
    if dht == 0 and sof[0] in ('baseline', 'extended', 'progressive'):
        notes.append('no Huffman table')
    (h, w), n = sof[2], sof[3]
    if w == 0 or h == 0:
        notes.append('width or height is zero')
    sub = '-'
    if n == 3:
        s = (sof[4][1] >> 4, sof[4][1] & 15)
        sub = {(2, 2): '4:2:0', (2, 1): '4:2:2', (1, 1): '4:4:4', (1, 2): '4:4:0'}.get(s, 'other')
    return '|'.join([sof[0], '%dx%d' % (w, h), str(n), sub, str(sof[1]), ', '.join(meta) or 'none']), notes, info

for p in sys.argv[1:]:
    s, n, inf = peek(p)
    print(p)
    if s is None:
        print('  ' + n[0])
        continue
    kind, size, comps, sub, bits, meta = s.split('|')
    print('  %s JPEG, %s, %s components, subsampling %s, %s bit' % (kind, size, comps, sub, bits))
    print('  metadata: ' + meta)
    for x in inf:
        print('  info: ' + x)
    for x in n:
        print('  note: ' + x)
    if not n:
        print('  no complaint')

On the intact JPG file it prints the kind, size, sampling and metadata, then the place, the camera and the date, with no complaint. On damaged files it names the problem. F2 has 143 bytes after the end marker, E4 has no end marker and A2 has 3 bytes before the start.

The script on the intact file and on six damaged copies
python3 jpg_peek.py base.jpg
base.jpg
  baseline JPEG, 480x320, 3 components, subsampling 4:2:0, 8 bit
  metadata: JFIF 1.01, Exif, ICC profile, comment
  info: GPS 12.0000 N, 77.0000 E
  info: camera make: ExampleCam
  info: taken 2026:10:25 09:00:00
  no complaint
python3 jpg_peek.py C1.jpg C2.jpg F2.jpg E4.jpg B7.jpg A2.jpg
C1.jpg
  baseline JPEG, 480x320, 3 components, subsampling 4:2:0, 8 bit
  metadata: JFIF 1.01, Exif, ICC profile, comment
  info: orientation tag says rotated 90 right
  info: GPS 12.0000 N, 77.0000 E
  info: camera make: ExampleCam
  info: taken 2026:10:25 09:00:00
  no complaint
C2.jpg
  baseline JPEG, 480x320, 3 components, subsampling 4:2:0, 8 bit
  metadata: JFIF 1.01, Exif, ICC profile, comment
  info: GPS 48.0000 N, 77.0000 E
  info: camera make: ExampleCam
  info: taken 2026:10:25 09:00:00
  no complaint
F2.jpg
  baseline JPEG, 480x320, 3 components, subsampling 4:2:0, 8 bit
  metadata: JFIF 1.01, Exif, ICC profile, comment
  info: GPS 12.0000 N, 77.0000 E
  info: camera make: ExampleCam
  info: taken 2026:10:25 09:00:00
  note: 143 bytes after the end marker
E4.jpg
  baseline JPEG, 480x320, 3 components, subsampling 4:2:0, 8 bit
  metadata: JFIF 1.01, Exif, ICC profile, comment
  info: GPS 12.0000 N, 77.0000 E
  info: camera make: ExampleCam
  info: taken 2026:10:25 09:00:00
  note: no end marker FF D9, the file looks cut
B7.jpg
  baseline JPEG, 481x320, 3 components, subsampling 4:2:0, 8 bit
  metadata: JFIF 1.01, Exif, ICC profile, comment
  info: GPS 12.0000 N, 77.0000 E
  info: camera make: ExampleCam
  info: taken 2026:10:25 09:00:00
  no complaint
A2.jpg
  baseline JPEG, 480x320, 3 components, subsampling 4:2:0, 8 bit
  metadata: JFIF 1.01, Exif, ICC profile, comment
  info: GPS 12.0000 N, 77.0000 E
  info: camera make: ExampleCam
  info: taken 2026:10:25 09:00:00
  note: 3 bytes before the start marker

What the script cannot see

The script reads structure and values, and it cannot say if they are the ones you meant. It passed C1, C2 and B7 with no complaint, although they change orientation, position and width. It prints the new values, and you must compare them with what you expect.

It also decodes nothing. It cannot say whether the picture data is intact, because flipped bytes in the scan (D1) change no marker. For that, use a decoder. A script refusal is a reason to look closer and not a verdict. djpeg decoded 27 public JPG files that the script refused.

Want the causes of an error? Go to the causes.

Is a JPG File Safe to Open? Viewing is safe, and sharing can give away a place

JPG files are safe to view, and they can still reveal more than you meant. Exif can store the camera, the time and GPS positions, and 66 of our 956 parsed public JPG files store one. IANA says the format has no privacy or integrity mechanism of its own.

Looking at a picture is not the risk. IANA says that JPEG data is not inherently executable and that parsers of untrusted data need the usual precautions. It says the format has no built in privacy or integrity mechanism, and it adds that Exif data can contain privacy sensitive information like a geolocation.

We scanned no JPG file for malware and opened none in an app. What we can say is what the public JPG files store. Of 547 Exif files, 409 name a camera make and 404 store a time. Another 66 store GPS positions. Before you post a photo, assume it names more than the picture shows.

The file command on base.jpg (shortened)
file -b base.jpg
JPEG image data, JFIF standard 1.01, ... manufacturer=ExampleCam, ... GPS-Data], comment: "made by us for the JPG page", baseline, precision 8, 480x320, components 3

The ending proves nothing about content. The file command read the markers and named the maker and the GPS block. Our F6 copy, a PNG with a JPG name, showed the other side. Five readers refused it, and the ending alone did not stop anyone from sending it.

What a JPG file can give away

A place The Exif block can store latitude and longitude. Our base.jpg stores 12 N and 77 E, and our script prints it.
A time Exif stores when the picture was taken. 404 of our 547 Exif files do.
A device Exif can store the make, and Wikipedia says the maker note can store a serial number.
An old picture Wikipedia says an editor can leave the small preview unchanged, so an earlier version can stay visible.

Bytes after the end marker

A decoder stops at FF D9 and never reads what follows. In our F2 copy, a zip archive followed the end marker. All five decoders returned the same pixels with no warning, and Python and unzip listed the note inside the zip. Of 956 public JPG files, 83 have bytes after the end marker.

Most of those are second pictures, padding or text from cameras, which is normal. The point is that JPG files can hide data and still look normal. If a JPG file came from someone you do not trust, treat any tail as a reason to look. The ZIP file page covers the container that F2 used.

Remove the metadata before you share

The jpegtran tool from libjpeg-turbo rewrites the segments without decoding the picture. With -copy none it dropped the Exif, XMP, ICC and comment segments and any bytes after the end marker. The pixels stayed identical, and our script found nothing but JFIF afterwards.

Strip metadata with jpegtran
# keep the picture, drop Exif, XMP, ICC, the comment and any bytes after the end marker
jpegtran -copy none -outfile out.jpg photo.jpg
# keep the color profile and drop the rest
jpegtran -copy icc -outfile out.jpg photo.jpg
What we measured
base.jpg           15745 bytes   JFIF 1.01, Exif, ICC profile, comment
out.jpg (none)     14823 bytes   JFIF 1.01
out.jpg (icc)      15429 bytes   JFIF 1.01, ICC profile
F2.jpg (zip tail)  15888 bytes   143 bytes after the end marker
F2 after none      14823 bytes   no complaint

Two cautions. Removing the color profile can change how colors look, so -copy icc keeps it. Removing the orientation tag leaves a sideways picture sideways, so rotate the pixels first. The tool lists an option for 90 degree steps. We tested the strip, the profile copy and one rotate.

Use a copy. Work on copies of JPG files, and write down their SHA256 hashes. The hash shows which file you received, and it shows if a transfer changed it later. Keep the original read only.

Why Will Your JPG File Not Open? Eight causes, and what to do about every one

JPG files stop opening for eight reasons. The file can be another type. Extra bytes can come first, or the file can be cut. End markers, tables or lengths can be missing or wrong. Picture data can be damaged, or your reader can lack support for the kind.

The table lists what our readers did with every kind of damage and what to do about it. The fixes undo one of the edits we made, so they restore a copy by construction. We opened no copy in a browser or a photo app, and an app can behave differently from our five decoders.

Eight causes of a JPG file that fails
Cause What we saw and what to do
The file is not a JPG (1) Base64 text (F4) and a gzip (F5) were refused by all six readers. A PNG with a JPG name (F6) was refused by four decoders, and Pillow opened it by content. Fix: Read the first bytes with head -c 16 file | xxd. If they are not FF D8 FF, unwrap the JPG file or give it the right ending.
Bytes in front of the start marker (2) Three junk bytes (A2) and HTTP headers on top (F7) stopped all five decoders. Only our script read past them. Fix: Cut everything before the first FF D8, or download the JPG file again from the source.
The file is cut (3) Copies cut at 90, 50 or 10 percent (E1 to E3), at the scan header (E5) or by 8 bytes (E8) made djpeg warn and Pillow, Go and jpeg-js refuse. Rust returned another picture with no warning. Fix: Download the JPG file again and compare its size with the source.
The end marker is missing (4) With no FF D9 at the end (E4), djpeg warned and Pillow, Go and jpeg-js refused. Rust returned the same pixels. Fix: Fetch a fresh copy. We did not test adding the marker by hand, so do not trust a JPG file you repaired this way.
Wrong segment lengths (5) A JFIF length that was 20 too long (A5) or 4 too short (A6) made Rust and jpeg-js refuse the JPG file. The djpeg tool warned, and Pillow and Go accepted it. The same file opens in one app and fails in another. Fix: Save the JPG file again in an editor that opens it, or get a fresh copy.
Missing or changed tables and frame (6) Removed quantization tables (B1), changed bit depth (B8), four components (B9) and changed frame type (B10) were refused by most decoders. Go returned another picture for B1. Fix: Compare the JPG file with a good copy, and use a decoder that prints warnings, like djpeg.
Damaged picture data (7) One flipped byte in the scan (D1) made djpeg warn and Go and jpeg-js refuse. Pillow and Rust gave another picture. Deleting 100 bytes (D5) split the readers the same way. Fix: Download the JPG file again. A partial picture is not a repair.
A kind your reader does not support (8) Our arithmetic coded file (m13) opened in djpeg and Pillow, and Go, Rust and jpeg-js refused it. Pillow also refused one public file for its size limit. Fix: Open the JPG file in djpeg, or convert it with a tool that supports the kind. Not every kind works in every app.

Fix a JPG file in seven steps

  1. Copy the JPG file, write its SHA256 hash and work on the copy.
  2. Read the first bytes as in the check steps. Look for FF D8 FF.
  3. Decode the JPG file with djpeg -ppm file.jpg > /dev/null, and read the warnings it prints.
  4. Read the JPG file with the check script. Notes or REFUSED lines name the point where the structure stops making sense.
  5. Compare the size of the JPG file with the source. A smaller file is cut, and a larger file can have a tail.
  6. Open the JPG file with a second decoder, and compare the answers.
  7. If it still fails, get a fresh copy from the source and compare the hashes.

We did not test repairs on files from other people. A file that decodes can still fail in an app that is stricter, and a JPG file that fails in one decoder can open in another. For example, 29 public JPG files that djpeg accepted were refused by Pillow.

What to send when you ask for help

If friends, shops or support teams gave you a JPG file that fails, send them these lines. They show what was read and where it stopped, and they save a round of questions.

A message that gets an answer
Subject: JPG file will not open
File: name, size in bytes and SHA256 hash
First bytes: the output of head -c 16 file | xxd
Decoder: the output of djpeg -ppm file > /dev/null
Script: the output of jpg_peek.py
App: the name and version of the app that fails, and what it printed
Source: where the JPG file came from and how it was copied

Not damage, but a question about other file types? Go to the versus part.

How Do You Make or Convert a JPG File? What 15 files we made show, and what converting costs

Convert JPG files only when you must, because every save in a lossy mode loses detail. Wikipedia calls this generation loss. To make JPG files, save pictures at a quality setting and keep the originals. Rotating and stripping metadata can be lossless.

Making JPG files differs from opening them. You choose a quality and the sampling, and a library writes the segments. We made 15 JPG files, one base and 14 variants, to see what the format allows. Every decoder accepted all but one, the arithmetic coded file.

Make a JPG file

The Python line below saves a picture at quality 85 with 4:2:0 sampling, like our base file. Pillow wrote base.jpg from a drawn picture of 480 by 320 pixels. Other tools write the same segments with other defaults, so compare the output of your tool with the figure in the inside part.

Save a JPG file with Pillow
from PIL import Image
im = Image.open('picture.png').convert('RGB')
im.save('picture.jpg', 'JPEG', quality=85, subsampling=2)

The 14 files we made

The 14 JPG files we made next to base.jpg
File What it shows
m01 4:4:4 Full color detail at quality 85. 23,265 bytes, against 15,745 for the base file.
m02 4:2:2 Half the color detail across. 18,505 bytes.
m03 progressive The same quantized data in several scans. The file has 14,227 bytes and gives the same pixels in all five decoders.
m04 optimized Huffman tables fitted to the picture. The file has 14,480 bytes and gives the same pixels.
m05 quality 10 Strong compression. The file has 5,827 bytes and gives another picture in every decoder.
m06 quality 100 Almost no loss, with 4:4:4. 89,616 bytes.
m07 orientation 6 The Exif tag says rotate 90 right. The file has 15,714 bytes and gives the same pixels.
m08 no metadata No Exif, no profile, no comment. The file has 14,823 bytes and gives the same pixels.
m09 no GPS Exif with the GPS block removed. 15,604 bytes.
m10 grayscale One component. 10,264 bytes.
m11 CMYK Four components. 31,828 bytes. All six readers accepted it.
m12 restart markers A restart marker after every 8 blocks. The file has 15,169 bytes and gives the same pixels.
m13 arithmetic Arithmetic coding instead of Huffman. 11,462 bytes. Go, Rust and jpeg-js refused it.
m14 RGB with Adobe Red, green and blue stored directly, with an Adobe segment. 30,034 bytes.

Pillow, djpeg and our script accepted all 15 JPG files. Go, Rust and jpeg-js accepted 14. Progressive coding, fitted tables and restart markers changed the size and no pixel, which fits the claim on Wikipedia that progressive files can compress a little better. Quality and sampling changed the picture in every decoder.

Convert a JPG file to another format

Converters decode the picture and write it again, so PNG files made from JPG files keep the loss that the JPG files already had. They do not bring back detail. JPG files made from PNG files lose detail once more. Keep the first file, and convert copies.

Some steps change no pixel. The jpegtran tool strips metadata without decoding, and its help lists crop, flip and rotate in 90 degree steps. Wikipedia says rotates and crops are lossless when the size fits the block grid. Our jpegtran rotate made a 480 by 320 file into a 320 by 480 file.

Common conversions and what you get
To Result
PNG Lossless from the decoded pixels. The file grows, and the detail lost earlier stays lost. See the PNG file guide.
PDF A page with the picture inside. Converters can add a watermark in a free version. See our PDF file page.
ZIP A zip does not make a JPG file smaller by much, because the data is already compressed. See ZIP files.
JPG with no metadata Use jpegtran -copy none. The pixels stay the same, and the Exif, the profile and the tail go.

How Does a JPG File Differ From PNG, GIF and BMP Files? Told apart by their first bytes

JPG files are lossy and made for photos, and PNG files are lossless and made for sharp edges. GIF files have 256 colors, and BMP files store raw pixels. They are told apart by their first bytes, which are FF D8 FF for JPG and 89 50 4E 47 for PNG.

People mix these types up, and the ending does not stop them. A PNG with a JPG name, our F6 copy, was refused by four of six readers. Tools that read one type refuse or misread another, so read the first bytes before you choose a tool.

We saved the same drawn picture of 480 by 320 pixels in every format with Pillow and counted the bytes. The picture is gradients, a circle and text, so it favors PNG more than a photo would. Photos are where JPG files shine, and our numbers do not test that.

One 480 by 320 picture in five formats
Format First bytes Bytes
JPG FF D8 FF 14,823
PNG 89 50 4E 47 16,950
GIF 47 49 46 38 26,569
BMP 42 4D 460,854
WebP 52 49 46 46 6,218

The JPG here is 14,823 bytes because it has no metadata. Our base.jpg has 15,745 bytes with its Exif, profile and comment. Wikipedia says JPEG reaches about 10 to 1 with an acceptable loss. On this drawn picture the PNG was only 14 percent larger, and a lossy WebP was far smaller.

The PNG file page covers lossless pictures, and the GIF file page covers palettes and animation. The BMP file page covers raw bitmaps. Other pages on this site cover ICO files and PSD files, which also store pictures.

What Is the JPG File Format Made Of? The facts we could check, and where they came from

The JPG file format is a chain of segments between the start marker and the end marker, with frame, tables, scan and optional metadata. The facts below come from Wikipedia, the Library of Congress, IANA, FileInfo and our checks of 1,052 public JPG files, 15 made files and 50 damaged copies.

Facts about the JPG file format
Part What we could check
Name JPEG, for the Joint Photographic Experts Group. Files end in .jpg or .jpeg. (Wikipedia, FileInfo)
Standard ISO/IEC 10918, also published as ITU-T T.81. First public release on 18 September 1992. (Wikipedia)
MIME type image/jpeg, defined in RFC 2046 and registered with IANA. (IANA)
Magic number FF D8 FF. The start marker alone is FF D8. (IANA, Library of Congress)
Wrapper JFIF 1.02 of 1 September 1992 is the common wrapper. It uses the APP0 segment. (Wikipedia)
Camera data Exif uses the APP1 segment, which is limited to 64 KB. (Wikipedia)
Size limit 65,535 by 65,535 pixels for JPEG and JFIF. (Wikipedia)
Modes Baseline, progressive, lossless and arithmetic. Baseline is the most common. (Wikipedia)
Frame markers FF C0 for baseline and FF C2 for progressive. (Library of Congress)
Security Not inherently executable, and no privacy or integrity mechanism of its own. (IANA)
Our counts 1,052 public JPG files, 15 made files, 50 damaged copies and six readers.

About the values we list

Facts about the standard and wrappers come from sources named in every row. Counts were checked against our own JPG files. FileInfo is a directory, so we use it for the name and programs only. Wikipedia and the Library of Congress give the same start marker.

Wikipedia and the JFIF article disagree slightly on the JFIF date. One text gives 1 September 1992 and a reference list gives 12 September 1992. We use the first and call it version 1.02. The Exif standard has newer versions than those we read about, so we name no current version.

What we left out

We tested on Linux only. We used five decoders and one script. We opened no JPG file in Windows Photos, Apple Preview, a browser or a phone, and we scanned no file for malware. We read the Exif values our script prints, and no others.

Of our 1,052 public JPG files, 98 are test cases made to break readers. Our damaged copies change one thing at a time in copies of one base file made with Pillow. Readers that fail on our JPG files can work on yours, and the reverse is true as well.

Sources checked

For the format and its history, see the JPEG article on Wikipedia. For the wrapper, see the JFIF article. For camera data, see the Exif article.

For the markers, see the Library of Congress format record. For the MIME type and the security notes, see the IANA registration. For the ending, see the FileInfo page on JPG files.

We read the pages of SysTools and Freeviewer for the two tool cards. We could not read the Exif specification from CIPA, because its site blocks automated reads. Every count came from the files and scripts in our research folder.

Frequently Asked Questions About JPG Files

What is a JPG file?

JPG files are pictures saved with lossy JPEG compression. They start with the bytes FF D8 FF and keep the pixels in marked segments. Besides the pixels they can store the camera make, the time, GPS positions and small previews, and even other files after the end marker.

How do I open a JPG file?

Double click it. Every browser, phone and photo app opens JPG files, and Windows Photos, Apple Preview and Paint do too. To look inside, use a command like djpeg or a script that prints the markers and the Exif values. We opened no JPG file in a photo app.

Why does my JPG file not open?

Eight causes cover what we found. The file can be another type. Extra bytes can come first, or the file can be cut. End markers, tables or lengths can be missing or wrong. Picture data can be damaged, or your reader can lack support for the kind, like arithmetic coding.

Is a JPG file the same as a JPEG file?

Yes. FileInfo says both endings name the same format. The ending .jpg is more common because early versions of Windows allowed only three letters after the dot. Wikipedia also lists .jpe, .jif, .jfif and .jfi.

Is a JPG file safe to open?

Looking at pictures is low risk, and IANA says JPEG data is not inherently executable. The privacy risk is higher, because Exif can store GPS positions, times and cameras. We scanned no JPG file for malware and opened none in an app. Remove the metadata before you share a photo.

What does a JPG file store besides the picture?

It can store JFIF segments and Exif blocks with the camera make, the time and GPS positions. It can also store XMP packets, color profiles, comments and bytes after the end marker. Of 956 public JPG files that parse, 547 store Exif and 66 store GPS positions.

Can a JPG file hide a zip archive?

Yes. In our test, a zip placed after the end marker passed five decoders with the same pixels and no warning, and Python and unzip listed the file inside it. Our script warned about the extra bytes. Of 956 public JPG files, 83 have bytes after the end marker.

How can I remove the location from a JPG file?

Remove the Exif data. The jpegtran tool with the option copy none rewrote our test JPG file with the same pixels and no Exif, XMP, profile or comment. It also dropped extra bytes after the end marker. Rotate the pixels first, because removing the orientation tag leaves a sideways picture sideways.

How can I check if a JPG file is damaged?

Hash the JPG file, read its first bytes, decode it with djpeg and use a script that prints the markers and the Exif values. Then open it with a second decoder. Five decoders and our script gave the same answer on only 2 of 50 damaged copies, so one reader proves little.

Does saving a JPG file again lose quality?

Yes, when you save again in a lossy mode. Wikipedia calls this generation loss. Some steps are lossless, like stripping metadata and rotating in 90 degree steps with a tool that works on the segments. In our test, jpegtran kept every pixel when it stripped the metadata.

What is the MIME type of a JPG file?

The MIME type is image/jpeg, registered with IANA. IANA lists jpg and jpeg as endings and FF D8 FF as the magic number. Older Internet Explorer versions sent image/pjpeg when they uploaded files, per Wikipedia. A server sends the type so that browsers show the picture.

Should I use JPG, PNG or WebP?

Use JPG files for photos when small size matters more than perfect edges. Use PNG files for sharp lines and transparency. In our test of one drawn picture, the JPG took 14,823 bytes, the PNG 16,950 and the lossy WebP 6,218. Drawn pictures favor PNG more than photos do.

Still Stuck With a JPG File? Two routes out, and where to look next

Your JPG file will not open

Read the first bytes and follow the six steps. The cause table lists what to try in order.

You want to share it safely

Read what a JPG file can give away, and then how to strip it.

Is it another picture type? The page on PNG files covers lossless pictures, and the page on GIF files covers palettes and animation.

Is it a raw bitmap? The page on BMP files covers raw pixels, and the page on ICO files covers icons.

Is it a zip in disguise? Zips can follow the end marker. The page on ZIP files covers the container, and the tail check shows how to look for one.

Is it an unknown file type? Browse the file extension resource library, or send it on the submit a file type page.