blob: 3fbfe50b27f46ce591f7abc1ab3b93b858465070 [file] [log] [blame]
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "pagespeed/kernel/image/jpeg_optimizer_test_helper.h"
#include <setjmp.h>
#include "pagespeed/kernel/base/mock_message_handler.h"
#include "pagespeed/kernel/base/null_mutex.h"
#include "pagespeed/kernel/image/jpeg_reader.h"
extern "C" {
#ifdef USE_SYSTEM_LIBJPEG
#include "jpeglib.h" // NOLINT
#else
#include "third_party/libjpeg_turbo/src/jpeglib.h"
#endif
}
using net_instaweb::MockMessageHandler;
using net_instaweb::NullMutex;
using pagespeed::image_compression::JpegReader;
namespace pagespeed_testing {
namespace image_compression {
// Marker for APPN segment can obtained by adding N to JPEG_APP0. There is no
// direct constant to refer them. The offsets here are part of jpeg codex, for
// example JPEG_APP0 + 2 refers to APP2 which should always correspond to color
// profile information.
const int kColorProfileMarker = JPEG_APP0 + 2;
const int kExifDataMarker = JPEG_APP0 + 1;
bool GetJpegNumComponentsAndSamplingFactors(
const GoogleString& jpeg,
int* out_num_components,
int* out_h_samp_factor,
int* out_v_samp_factor) {
MockMessageHandler message_handler_(new NullMutex);
JpegReader reader(&message_handler_);
jpeg_decompress_struct* jpeg_decompress = reader.decompress_struct();
jmp_buf env;
if (setjmp(env)) {
return false;
}
// Need to install env so that it will be longjmp()ed to on error.
jpeg_decompress->client_data = static_cast<void *>(&env);
reader.PrepareForRead(jpeg.data(), jpeg.size());
jpeg_read_header(jpeg_decompress, TRUE);
*out_num_components = jpeg_decompress->num_components;
*out_h_samp_factor = jpeg_decompress->comp_info[0].h_samp_factor;
*out_v_samp_factor = jpeg_decompress->comp_info[0].v_samp_factor;
return true;
}
bool IsJpegSegmentPresent(const GoogleString& data, int segment) {
MockMessageHandler message_handler_(new NullMutex);
JpegReader reader(&message_handler_);
jpeg_decompress_struct* jpeg_decompress = reader.decompress_struct();
jmp_buf env;
if (setjmp(env)) {
return false;
}
// Need to install env so that it will be longjmp()ed to on error.
jpeg_decompress->client_data = static_cast<void *>(&env);
reader.PrepareForRead(data.data(), data.size());
jpeg_save_markers(jpeg_decompress, segment, 0xFFFF);
jpeg_read_header(jpeg_decompress, TRUE);
bool is_marker_present = false;
for (jpeg_saved_marker_ptr marker = jpeg_decompress->marker_list;
marker != NULL; marker = marker->next) {
if (marker->marker == segment) {
is_marker_present = true;
break;
}
}
return is_marker_present;
}
int GetNumScansInJpeg(const GoogleString& data) {
MockMessageHandler message_handler_(new NullMutex);
JpegReader reader(&message_handler_);
jpeg_decompress_struct* jpeg_decompress = reader.decompress_struct();
jmp_buf env;
if (setjmp(env)) {
return false;
}
// Need to install env so that it will be longjmp()ed to on error.
jpeg_decompress->client_data = static_cast<void *>(&env);
reader.PrepareForRead(data.data(), data.size());
jpeg_read_header(jpeg_decompress, TRUE);
jpeg_decompress->buffered_image = true;
jpeg_start_decompress(jpeg_decompress);
int num_scans = 0;
while (!jpeg_input_complete(jpeg_decompress)) {
if (jpeg_consume_input(jpeg_decompress) == JPEG_SCAN_COMPLETED) {
num_scans++;
}
}
return num_scans;
}
int GetColorProfileMarker() {
return kColorProfileMarker;
}
int GetExifDataMarker() {
return kExifDataMarker;
}
} // namespace image_compression
} // namespace pagespeed_testing