function image = jpeg_decode(jpg)
%JPEG_DECODE  decode image from jpeg-like format
%   IMAGE = JPEG_DECODE(jpg)

%% Global coding constants

% uint pixel data is represented in the interval 0 : 255
full_range = 256;

% Macro block size
block_size = 8;

% DCT is a 8x8 matrix. The direct cosine transform (DCT) of a column vector
% is computed as   DCT * a
DCT = dct_matrix(block_size);

%% inverse transform each block
Y_mb = decode_blocks(jpg.Y_coded);
Cb_mb = decode_blocks(jpg.Cb_coded);
Cr_mb = decode_blocks(jpg.Cr_coded);

%% get pixel data from blocks
Y = cell2mat(Y_mb);
Cb = cell2mat(Cb_mb);
Cr = cell2mat(Cr_mb);

%% upsample Chroma components
Cb = upsample(Cb, jpg.subsample_ratio, 'rect');
Cr = upsample(Cr, jpg.subsample_ratio, 'rect');

%% Crop matrices to original image size
Y = Y(1:jpg.image_size(1), 1:jpg.image_size(2));
Cb = Cb(1:jpg.image_size(1), 1:jpg.image_size(2));
Cr = Cr(1:jpg.image_size(1), 1:jpg.image_size(2));

%% convert color space
[R, G, B] = ycbcr_to_rgb(Y, Cb, Cr);

%% assemble image
image(:,:,1) = R;
image(:,:,2) = G;
image(:,:,3) = B;
image = uint8(image);


    function blocks = decode_blocks(coded_blocks)
        
        blocks = cell(size(coded_blocks));
        
        for k = 1 : numel(coded_blocks)
            b = coded_blocks{k};
            b = b .* jpg.Q;
            b = DCT' * b * DCT;
            blocks{k} = b + full_range / 2;
        end
    end
end
