зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
43613b3e84
|
@ -136,9 +136,9 @@
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
<vbox>
|
<vbox>
|
||||||
<description>&doNotTrack.pre.label;<html:a
|
<description>&doNotTrack.pre.label;<label
|
||||||
class="inline-link" id="doNotTrackSettings" href="#"
|
class="text-link" id="doNotTrackSettings" href="#"
|
||||||
>&doNotTrack.settings.label;</html:a>&doNotTrack.post.label;</description>
|
>&doNotTrack.settings.label;</label>&doNotTrack.post.label;</description>
|
||||||
</vbox>
|
</vbox>
|
||||||
</groupbox>
|
</groupbox>
|
||||||
|
|
||||||
|
@ -165,11 +165,11 @@
|
||||||
<vbox flex="1">
|
<vbox flex="1">
|
||||||
<description>&rememberDescription.label;</description>
|
<description>&rememberDescription.label;</description>
|
||||||
<separator class="thin"/>
|
<separator class="thin"/>
|
||||||
<description>&rememberActions.pre.label;<html:a
|
<description>&rememberActions.pre.label;<label
|
||||||
class="inline-link" id="historyRememberClear" href="#"
|
class="text-link" id="historyRememberClear" href="#"
|
||||||
>&rememberActions.clearHistory.label;</html:a>&rememberActions.middle.label;<html:a
|
>&rememberActions.clearHistory.label;</label>&rememberActions.middle.label;<label
|
||||||
class="inline-link" id="historyRememberCookies" href="#"
|
class="text-link" id="historyRememberCookies" href="#"
|
||||||
>&rememberActions.removeCookies.label;</html:a>&rememberActions.post.label;</description>
|
>&rememberActions.removeCookies.label;</label>&rememberActions.post.label;</description>
|
||||||
</vbox>
|
</vbox>
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
@ -178,9 +178,9 @@
|
||||||
<vbox flex="1">
|
<vbox flex="1">
|
||||||
<description>&dontrememberDescription.label;</description>
|
<description>&dontrememberDescription.label;</description>
|
||||||
<separator class="thin"/>
|
<separator class="thin"/>
|
||||||
<description>&dontrememberActions.pre.label;<html:a
|
<description>&dontrememberActions.pre.label;<label
|
||||||
class="inline-link" id="historyDontRememberClear" href="#"
|
class="text-link" id="historyDontRememberClear" href="#"
|
||||||
>&dontrememberActions.clearHistory.label;</html:a>&dontrememberActions.post.label;</description>
|
>&dontrememberActions.clearHistory.label;</label>&dontrememberActions.post.label;</description>
|
||||||
</vbox>
|
</vbox>
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
|
@ -36,6 +36,31 @@ DocumentTimeline::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
return DocumentTimelineBinding::Wrap(aCx, this, aGivenProto);
|
return DocumentTimelineBinding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ already_AddRefed<DocumentTimeline>
|
||||||
|
DocumentTimeline::Constructor(const GlobalObject& aGlobal,
|
||||||
|
const DOMHighResTimeStamp& aOriginTime,
|
||||||
|
ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
|
||||||
|
if (!doc) {
|
||||||
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeDuration originTime = TimeDuration::FromMilliseconds(aOriginTime);
|
||||||
|
if (originTime == TimeDuration::Forever() ||
|
||||||
|
originTime == -TimeDuration::Forever()) {
|
||||||
|
nsAutoString inputOriginTime;
|
||||||
|
inputOriginTime.AppendFloat(aOriginTime);
|
||||||
|
aRv.ThrowTypeError<dom::MSG_TIME_VALUE_OUT_OF_RANGE>(
|
||||||
|
NS_LITERAL_STRING("Origin time"));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
RefPtr<DocumentTimeline> timeline = new DocumentTimeline(doc, originTime);
|
||||||
|
|
||||||
|
return timeline.forget();
|
||||||
|
}
|
||||||
|
|
||||||
Nullable<TimeDuration>
|
Nullable<TimeDuration>
|
||||||
DocumentTimeline::GetCurrentTime() const
|
DocumentTimeline::GetCurrentTime() const
|
||||||
{
|
{
|
||||||
|
@ -88,7 +113,9 @@ DocumentTimeline::ToTimelineTime(const TimeStamp& aTimeStamp) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.SetValue(aTimeStamp - timing->GetNavigationStartTimeStamp());
|
result.SetValue(aTimeStamp
|
||||||
|
- timing->GetNavigationStartTimeStamp()
|
||||||
|
- mOriginTime);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +231,7 @@ DocumentTimeline::ToTimeStamp(const TimeDuration& aTimeDuration) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = timing->GetNavigationStartTimeStamp() + aTimeDuration;
|
result = timing->GetNavigationStartTimeStamp() + aTimeDuration + mOriginTime;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/TimeStamp.h"
|
#include "mozilla/TimeStamp.h"
|
||||||
#include "AnimationTimeline.h"
|
#include "AnimationTimeline.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
|
#include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
|
||||||
#include "nsRefreshDriver.h"
|
#include "nsRefreshDriver.h"
|
||||||
|
|
||||||
struct JSContext;
|
struct JSContext;
|
||||||
|
@ -28,10 +29,11 @@ class DocumentTimeline final
|
||||||
, public nsARefreshObserver
|
, public nsARefreshObserver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DocumentTimeline(nsIDocument* aDocument)
|
DocumentTimeline(nsIDocument* aDocument, const TimeDuration& aOriginTime)
|
||||||
: AnimationTimeline(aDocument->GetParentObject())
|
: AnimationTimeline(aDocument->GetParentObject())
|
||||||
, mDocument(aDocument)
|
, mDocument(aDocument)
|
||||||
, mIsObservingRefreshDriver(false)
|
, mIsObservingRefreshDriver(false)
|
||||||
|
, mOriginTime(aOriginTime)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +52,11 @@ public:
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
static already_AddRefed<DocumentTimeline>
|
||||||
|
Constructor(const GlobalObject& aGlobal,
|
||||||
|
const DOMHighResTimeStamp& aOriginTime,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
// AnimationTimeline methods
|
// AnimationTimeline methods
|
||||||
virtual Nullable<TimeDuration> GetCurrentTime() const override;
|
virtual Nullable<TimeDuration> GetCurrentTime() const override;
|
||||||
|
|
||||||
|
@ -84,6 +91,8 @@ protected:
|
||||||
// iframe).
|
// iframe).
|
||||||
mutable TimeStamp mLastRefreshDriverTime;
|
mutable TimeStamp mLastRefreshDriverTime;
|
||||||
bool mIsObservingRefreshDriver;
|
bool mIsObservingRefreshDriver;
|
||||||
|
|
||||||
|
TimeDuration mOriginTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -37,6 +37,7 @@ support-files =
|
||||||
document-timeline/file_document-timeline.html
|
document-timeline/file_document-timeline.html
|
||||||
mozilla/file_deferred_start.html
|
mozilla/file_deferred_start.html
|
||||||
mozilla/file_disabled_properties.html
|
mozilla/file_disabled_properties.html
|
||||||
|
mozilla/file_document-timeline-origin-time-range.html
|
||||||
mozilla/file_hide_and_show.html
|
mozilla/file_hide_and_show.html
|
||||||
mozilla/file_partial_keyframes.html
|
mozilla/file_partial_keyframes.html
|
||||||
style/file_animation-seeking-with-current-time.html
|
style/file_animation-seeking-with-current-time.html
|
||||||
|
@ -82,6 +83,7 @@ skip-if = buildapp == 'mulet'
|
||||||
[mozilla/test_deferred_start.html]
|
[mozilla/test_deferred_start.html]
|
||||||
skip-if = (toolkit == 'gonk' && debug)
|
skip-if = (toolkit == 'gonk' && debug)
|
||||||
[mozilla/test_disabled_properties.html]
|
[mozilla/test_disabled_properties.html]
|
||||||
|
[mozilla/test_document-timeline-origin-time-range.html]
|
||||||
[mozilla/test_hide_and_show.html]
|
[mozilla/test_hide_and_show.html]
|
||||||
[mozilla/test_partial_keyframes.html]
|
[mozilla/test_partial_keyframes.html]
|
||||||
[style/test_animation-seeking-with-current-time.html]
|
[style/test_animation-seeking-with-current-time.html]
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<script src="../testcommon.js"></script>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// If the originTime parameter passed to the DocumentTimeline exceeds
|
||||||
|
// the range of the internal storage type (a signed 64-bit integer number
|
||||||
|
// of ticks--a platform-dependent unit) then we should throw.
|
||||||
|
// Infinity isn't allowed as an origin time value and clamping to just
|
||||||
|
// inside the allowed range will just mean we overflow elsewhere.
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
assert_throws({name: 'TypeError'},
|
||||||
|
function() { new DocumentTimeline(Number.MAX_SAFE_INTEGER); });
|
||||||
|
}, 'Calculated current time is positive infinity');
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
assert_throws({name: 'TypeError'},
|
||||||
|
function() { new DocumentTimeline(-1 * Number.MAX_SAFE_INTEGER); });
|
||||||
|
}, 'Calculated current time is negative infinity');
|
||||||
|
|
||||||
|
done();
|
||||||
|
</script>
|
||||||
|
</body>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
setup({explicit_done: true});
|
||||||
|
SpecialPowers.pushPrefEnv(
|
||||||
|
{ "set": [["dom.animations-api.core.enabled", true]]},
|
||||||
|
function() {
|
||||||
|
window.open("file_document-timeline-origin-time-range.html");
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -15,6 +15,7 @@
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
|
#include "nsContentUtils.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
@ -409,18 +410,23 @@ ScreenOrientation::UnlockDeviceOrientation()
|
||||||
OrientationType
|
OrientationType
|
||||||
ScreenOrientation::DeviceType() const
|
ScreenOrientation::DeviceType() const
|
||||||
{
|
{
|
||||||
return mType;
|
return ShouldResistFingerprinting() ? OrientationType::Landscape_primary
|
||||||
|
: mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t
|
uint16_t
|
||||||
ScreenOrientation::DeviceAngle() const
|
ScreenOrientation::DeviceAngle() const
|
||||||
{
|
{
|
||||||
return mAngle;
|
return ShouldResistFingerprinting() ? 0 : mAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
OrientationType
|
OrientationType
|
||||||
ScreenOrientation::GetType(ErrorResult& aRv) const
|
ScreenOrientation::GetType(ErrorResult& aRv) const
|
||||||
{
|
{
|
||||||
|
if (ShouldResistFingerprinting()) {
|
||||||
|
return OrientationType::Landscape_primary;
|
||||||
|
}
|
||||||
|
|
||||||
nsIDocument* doc = GetResponsibleDocument();
|
nsIDocument* doc = GetResponsibleDocument();
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
|
@ -433,6 +439,10 @@ ScreenOrientation::GetType(ErrorResult& aRv) const
|
||||||
uint16_t
|
uint16_t
|
||||||
ScreenOrientation::GetAngle(ErrorResult& aRv) const
|
ScreenOrientation::GetAngle(ErrorResult& aRv) const
|
||||||
{
|
{
|
||||||
|
if (ShouldResistFingerprinting()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
nsIDocument* doc = GetResponsibleDocument();
|
nsIDocument* doc = GetResponsibleDocument();
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
|
@ -495,6 +505,10 @@ ScreenOrientation::GetResponsibleDocument() const
|
||||||
void
|
void
|
||||||
ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration)
|
ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration)
|
||||||
{
|
{
|
||||||
|
if (ShouldResistFingerprinting()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsIDocument* doc = GetResponsibleDocument();
|
nsIDocument* doc = GetResponsibleDocument();
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
return;
|
return;
|
||||||
|
@ -571,6 +585,16 @@ ScreenOrientation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
return ScreenOrientationBinding::Wrap(aCx, this, aGivenProto);
|
return ScreenOrientationBinding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ScreenOrientation::ShouldResistFingerprinting() const
|
||||||
|
{
|
||||||
|
bool resist = false;
|
||||||
|
if (nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner()) {
|
||||||
|
resist = nsContentUtils::ShouldResistFingerprinting(owner->GetDocShell());
|
||||||
|
}
|
||||||
|
return resist;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(ScreenOrientation::VisibleEventListener, nsIDOMEventListener)
|
NS_IMPL_ISUPPORTS(ScreenOrientation::VisibleEventListener, nsIDOMEventListener)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
|
@ -102,6 +102,8 @@ private:
|
||||||
|
|
||||||
void DispatchChangeEvent();
|
void DispatchChangeEvent();
|
||||||
|
|
||||||
|
bool ShouldResistFingerprinting() const;
|
||||||
|
|
||||||
LockPermission GetLockOrientationPermission(bool aCheckSandbox) const;
|
LockPermission GetLockOrientationPermission(bool aCheckSandbox) const;
|
||||||
|
|
||||||
// Gets the responsible document as defined in the spec.
|
// Gets the responsible document as defined in the spec.
|
||||||
|
|
|
@ -3241,7 +3241,7 @@ DocumentTimeline*
|
||||||
nsDocument::Timeline()
|
nsDocument::Timeline()
|
||||||
{
|
{
|
||||||
if (!mDocumentTimeline) {
|
if (!mDocumentTimeline) {
|
||||||
mDocumentTimeline = new DocumentTimeline(this);
|
mDocumentTimeline = new DocumentTimeline(this, TimeDuration(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mDocumentTimeline;
|
return mDocumentTimeline;
|
||||||
|
|
|
@ -13243,8 +13243,8 @@ void
|
||||||
nsGlobalWindow::EnableOrientationChangeListener()
|
nsGlobalWindow::EnableOrientationChangeListener()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsInnerWindow());
|
MOZ_ASSERT(IsInnerWindow());
|
||||||
|
if (!nsContentUtils::ShouldResistFingerprinting(mDocShell) &&
|
||||||
if (!mOrientationChangeObserver) {
|
!mOrientationChangeObserver) {
|
||||||
mOrientationChangeObserver =
|
mOrientationChangeObserver =
|
||||||
new WindowOrientationObserver(this);
|
new WindowOrientationObserver(this);
|
||||||
}
|
}
|
||||||
|
@ -14087,7 +14087,8 @@ nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
|
||||||
int16_t
|
int16_t
|
||||||
nsGlobalWindow::Orientation() const
|
nsGlobalWindow::Orientation() const
|
||||||
{
|
{
|
||||||
return WindowOrientationObserver::OrientationAngle();
|
return nsContentUtils::ShouldResistFingerprinting(mDocShell) ?
|
||||||
|
0 : WindowOrientationObserver::OrientationAngle();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1842,8 +1842,23 @@ ValidateCurrentNode(nsRange* aRange, RangeSubtreeIterator& aIter)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult res = nsRange::CompareNodeToRange(node, aRange, &before, &after);
|
nsresult res = nsRange::CompareNodeToRange(node, aRange, &before, &after);
|
||||||
|
NS_ENSURE_SUCCESS(res, false);
|
||||||
|
|
||||||
return NS_SUCCEEDED(res) && !before && !after;
|
if (before || after) {
|
||||||
|
nsCOMPtr<nsIDOMCharacterData> charData = do_QueryInterface(node);
|
||||||
|
if (charData) {
|
||||||
|
// If we're dealing with the start/end container which is a character
|
||||||
|
// node, pretend that the node is in the range.
|
||||||
|
if (before && node == aRange->GetStartParent()) {
|
||||||
|
before = false;
|
||||||
|
}
|
||||||
|
if (after && node == aRange->GetEndParent()) {
|
||||||
|
after = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !before && !after;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
|
|
@ -193,25 +193,21 @@ nsScreen::Orientation() const
|
||||||
void
|
void
|
||||||
nsScreen::GetMozOrientation(nsString& aOrientation) const
|
nsScreen::GetMozOrientation(nsString& aOrientation) const
|
||||||
{
|
{
|
||||||
if (ShouldResistFingerprinting()) {
|
switch (mScreenOrientation->DeviceType()) {
|
||||||
|
case OrientationType::Portrait_primary:
|
||||||
|
aOrientation.AssignLiteral("portrait-primary");
|
||||||
|
break;
|
||||||
|
case OrientationType::Portrait_secondary:
|
||||||
|
aOrientation.AssignLiteral("portrait-secondary");
|
||||||
|
break;
|
||||||
|
case OrientationType::Landscape_primary:
|
||||||
aOrientation.AssignLiteral("landscape-primary");
|
aOrientation.AssignLiteral("landscape-primary");
|
||||||
} else {
|
break;
|
||||||
switch (mScreenOrientation->DeviceType()) {
|
case OrientationType::Landscape_secondary:
|
||||||
case OrientationType::Portrait_primary:
|
aOrientation.AssignLiteral("landscape-secondary");
|
||||||
aOrientation.AssignLiteral("portrait-primary");
|
break;
|
||||||
break;
|
default:
|
||||||
case OrientationType::Portrait_secondary:
|
MOZ_CRASH("Unacceptable screen orientation type.");
|
||||||
aOrientation.AssignLiteral("portrait-secondary");
|
|
||||||
break;
|
|
||||||
case OrientationType::Landscape_primary:
|
|
||||||
aOrientation.AssignLiteral("landscape-primary");
|
|
||||||
break;
|
|
||||||
case OrientationType::Landscape_secondary:
|
|
||||||
aOrientation.AssignLiteral("landscape-secondary");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("Unacceptable screen orientation type.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +259,9 @@ bool
|
||||||
nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
|
nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
|
if (ShouldResistFingerprinting()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ScreenOrientationInternal orientation = eScreenOrientation_None;
|
ScreenOrientationInternal orientation = eScreenOrientation_None;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aOrientations.Length(); ++i) {
|
for (uint32_t i = 0; i < aOrientations.Length(); ++i) {
|
||||||
|
@ -310,6 +309,9 @@ nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
|
||||||
void
|
void
|
||||||
nsScreen::MozUnlockOrientation()
|
nsScreen::MozUnlockOrientation()
|
||||||
{
|
{
|
||||||
|
if (ShouldResistFingerprinting()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
UpdateDocShellOrientationLock(GetOwner(), eScreenOrientation_None);
|
UpdateDocShellOrientationLock(GetOwner(), eScreenOrientation_None);
|
||||||
mScreenOrientation->UnlockDeviceOrientation();
|
mScreenOrientation->UnlockDeviceOrientation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ var test = function (isContent) {
|
||||||
["screen.availTop", 0],
|
["screen.availTop", 0],
|
||||||
["screen.width", "innerWidth"],
|
["screen.width", "innerWidth"],
|
||||||
["screen.height", "innerHeight"],
|
["screen.height", "innerHeight"],
|
||||||
|
["screen.orientation.type", "'landscape-primary'"],
|
||||||
|
["screen.orientation.angle", 0],
|
||||||
["screen.mozOrientation", "'landscape-primary'"],
|
["screen.mozOrientation", "'landscape-primary'"],
|
||||||
["devicePixelRatio", 1]
|
["devicePixelRatio", 1]
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title></title>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
var rng = document.createRange();
|
||||||
|
rng.setStart(document.getElementsByTagName("p").item(0).firstChild, 100);
|
||||||
|
rng.setEndAfter(document.getElementsByTagName("p").item(0));
|
||||||
|
try {
|
||||||
|
rng.extractContents();
|
||||||
|
opener.ok(true, "extractContents should not throw when document in iframe is being modified.");
|
||||||
|
} catch(ex) {
|
||||||
|
opener.ok(false, "extractContents shouldn't have thrown: " + ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
opener.setTimeout("SimpleTest.finish();", 0);
|
||||||
|
window.close();
|
||||||
|
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur elit nisi, convallis sed scelerisque sit amet, vestibulum eu odio. Pellentesque et quam et nibh sollicitudin rutrum. Fusce tristique hendrerit ligula, et euismod sapien facilisis quis. Donec tincidunt turpis tortor, in pharetra tellus euismod ac. Vestibulum consectetur nulla lacinia, consectetur mauris ac, tempus libero. Nam non dui id enim dapibus porta id sed lectus. Praesent at suscipit neque. Vestibulum tellus lorem, placerat et volutpat sed, elementum eget lacus. Sed interdum nisi et imperdiet varius. Sed non magna odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus velit risus, accumsan nec efficitur nec, semper sed arcu. Praesent consectetur lectus justo, fringilla imperdiet neque lobortis id. Donec efficitur pulvinar finibus.
|
||||||
|
<iframe src="data:text/html,<script>window.onunload = function() {document.removeChild(document.documentElement); }</script>" width="10" height="10"></iframe>
|
||||||
|
</p>
|
||||||
|
<p>test</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -160,6 +160,7 @@ support-files =
|
||||||
file_bug945152.jar
|
file_bug945152.jar
|
||||||
file_bug1263696_frame_pass.html
|
file_bug1263696_frame_pass.html
|
||||||
file_bug1263696_frame_fail.html
|
file_bug1263696_frame_fail.html
|
||||||
|
file_bug1274806.html
|
||||||
file_general_document.html
|
file_general_document.html
|
||||||
file_html_in_xhr.html
|
file_html_in_xhr.html
|
||||||
file_html_in_xhr.sjs
|
file_html_in_xhr.sjs
|
||||||
|
@ -664,6 +665,7 @@ skip-if = buildapp == 'b2g'
|
||||||
[test_bug1250148.html]
|
[test_bug1250148.html]
|
||||||
[test_bug1259588.html]
|
[test_bug1259588.html]
|
||||||
[test_bug1263696.html]
|
[test_bug1263696.html]
|
||||||
|
[test_bug1274806.html]
|
||||||
[test_caretPositionFromPoint.html]
|
[test_caretPositionFromPoint.html]
|
||||||
[test_change_policy.html]
|
[test_change_policy.html]
|
||||||
skip-if = buildapp == 'b2g' #no ssl support
|
skip-if = buildapp == 'b2g' #no ssl support
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1274806
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1274806</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
/** Test for Bug 1274806 **/
|
||||||
|
function test() {
|
||||||
|
window.testWindow = window.open("file_bug1274806.html", "", "");
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="setTimeout(test, 0);">
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1274806">Mozilla Bug 1274806</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -98,4 +98,5 @@ MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSEXN_TYPEERR, "Invalid easing '{0}'.")
|
||||||
MSG_DEF(MSG_USELESS_SETTIMEOUT, 1, JSEXN_TYPEERR, "Useless {0} call (missing quotes around argument?)")
|
MSG_DEF(MSG_USELESS_SETTIMEOUT, 1, JSEXN_TYPEERR, "Useless {0} call (missing quotes around argument?)")
|
||||||
MSG_DEF(MSG_TOKENLIST_NO_SUPPORTED_TOKENS, 2, JSEXN_TYPEERR, "{0} attribute of <{1}> does not define any supported tokens")
|
MSG_DEF(MSG_TOKENLIST_NO_SUPPORTED_TOKENS, 2, JSEXN_TYPEERR, "{0} attribute of <{1}> does not define any supported tokens")
|
||||||
MSG_DEF(MSG_CACHE_STREAM_CLOSED, 0, JSEXN_TYPEERR, "Response body is a cache file stream that has already been closed.")
|
MSG_DEF(MSG_CACHE_STREAM_CLOSED, 0, JSEXN_TYPEERR, "Response body is a cache file stream that has already been closed.")
|
||||||
|
MSG_DEF(MSG_TIME_VALUE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "{0} is outside the supported range for time values.")
|
||||||
MSG_DEF(MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN, 1, JSEXN_TYPEERR, "Request mode '{0}' was used, but request cache mode 'only-if-cached' can only be used with request mode 'same-origin'.")
|
MSG_DEF(MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN, 1, JSEXN_TYPEERR, "Request mode '{0}' was used, but request cache mode 'only-if-cached' can only be used with request mode 'same-origin'.")
|
||||||
|
|
|
@ -791,10 +791,11 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
||||||
}
|
}
|
||||||
if (mSeekTargetThreshold.isSome()) {
|
if (mSeekTargetThreshold.isSome()) {
|
||||||
media::TimeUnit pts = GetSampleTime(sample);
|
media::TimeUnit pts = GetSampleTime(sample);
|
||||||
if (!pts.IsValid()) {
|
media::TimeUnit duration = GetSampleDuration(sample);
|
||||||
|
if (!pts.IsValid() || !duration.IsValid()) {
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
if (pts < mSeekTargetThreshold.ref()) {
|
if ((pts + duration) < mSeekTargetThreshold.ref()) {
|
||||||
LOG("Dropping video frame which pts is smaller than seek target.");
|
LOG("Dropping video frame which pts is smaller than seek target.");
|
||||||
// It is necessary to clear the pointer to release the previous output
|
// It is necessary to clear the pointer to release the previous output
|
||||||
// buffer.
|
// buffer.
|
||||||
|
|
|
@ -163,6 +163,7 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
|
||||||
case nsIContentPolicy::TYPE_WEBSOCKET:
|
case nsIContentPolicy::TYPE_WEBSOCKET:
|
||||||
case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
|
case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
|
||||||
case nsIContentPolicy::TYPE_BEACON:
|
case nsIContentPolicy::TYPE_BEACON:
|
||||||
|
case nsIContentPolicy::TYPE_PING:
|
||||||
case nsIContentPolicy::TYPE_FETCH:
|
case nsIContentPolicy::TYPE_FETCH:
|
||||||
return nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE;
|
return nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE;
|
||||||
|
|
||||||
|
@ -171,7 +172,6 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
|
||||||
return nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE;
|
return nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE;
|
||||||
|
|
||||||
case nsIContentPolicy::TYPE_XBL:
|
case nsIContentPolicy::TYPE_XBL:
|
||||||
case nsIContentPolicy::TYPE_PING:
|
|
||||||
case nsIContentPolicy::TYPE_DTD:
|
case nsIContentPolicy::TYPE_DTD:
|
||||||
case nsIContentPolicy::TYPE_OTHER:
|
case nsIContentPolicy::TYPE_OTHER:
|
||||||
return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
|
return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Bug 1100181 - CSP: Enforce connect-src when submitting pings</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- we are using an image for the test, but can be anything -->
|
||||||
|
<a id="testlink"
|
||||||
|
href="http://mochi.test:8888/tests/image/test/mochitest/blue.png"
|
||||||
|
ping="http://mochi.test:8888/tests/image/test/mochitest/blue.png?send-ping">
|
||||||
|
Send ping
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var link = document.getElementById("testlink");
|
||||||
|
link.click();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -162,6 +162,7 @@ support-files =
|
||||||
file_form_action_server.sjs
|
file_form_action_server.sjs
|
||||||
!/image/test/mochitest/blue.png
|
!/image/test/mochitest/blue.png
|
||||||
file_meta_whitespace_skipping.html
|
file_meta_whitespace_skipping.html
|
||||||
|
file_ping.html
|
||||||
|
|
||||||
[test_base-uri.html]
|
[test_base-uri.html]
|
||||||
[test_blob_data_schemes.html]
|
[test_blob_data_schemes.html]
|
||||||
|
@ -248,3 +249,4 @@ tags = mcb
|
||||||
tags = mcb
|
tags = mcb
|
||||||
[test_form_action_blocks_url.html]
|
[test_form_action_blocks_url.html]
|
||||||
[test_meta_whitespace_skipping.html]
|
[test_meta_whitespace_skipping.html]
|
||||||
|
[test_ping.html]
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Bug 1100181 - CSP: Enforce connect-src when submitting pings</title>
|
||||||
|
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe style="width:100%;" id="testframe"></iframe>
|
||||||
|
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Description of the test:
|
||||||
|
* We load a page with a given CSP and verify that hyperlink auditing
|
||||||
|
* is correctly evaluated through the "connect-src" directive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Need to pref hyperlink auditing on since it's disabled by default.
|
||||||
|
SpecialPowers.setBoolPref("browser.send_pings", true);
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
{
|
||||||
|
result : "allowed",
|
||||||
|
policy : "connect-src 'self'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
result : "blocked",
|
||||||
|
policy : "connect-src 'none'"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// initializing to -1 so we start at index 0 when we start the test
|
||||||
|
var counter = -1;
|
||||||
|
|
||||||
|
function checkResult(aResult) {
|
||||||
|
is(aResult, tests[counter].result, "should be " + tests[counter].result + " in test " + counter + "!");
|
||||||
|
loadNextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use the examiner to identify requests that hit the wire and requests
|
||||||
|
// that are blocked by CSP and bubble up the result to the including iframe
|
||||||
|
// document (parent).
|
||||||
|
function examiner() {
|
||||||
|
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
|
||||||
|
SpecialPowers.addObserver(this, "specialpowers-http-notify-request", false);
|
||||||
|
}
|
||||||
|
examiner.prototype = {
|
||||||
|
observe: function(subject, topic, data) {
|
||||||
|
if (topic === "specialpowers-http-notify-request") {
|
||||||
|
// making sure we do not bubble a result for something
|
||||||
|
// other then the request in question.
|
||||||
|
if (!data.includes("send-ping")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checkResult("allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topic === "csp-on-violate-policy") {
|
||||||
|
// making sure we do not bubble a result for something
|
||||||
|
// other then the request in question.
|
||||||
|
var asciiSpec = SpecialPowers.getPrivilegedProps(
|
||||||
|
SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
|
||||||
|
if (!asciiSpec.includes("send-ping")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checkResult("blocked");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remove: function() {
|
||||||
|
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
|
||||||
|
SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.ConnectSrcExaminer = new examiner();
|
||||||
|
|
||||||
|
function loadNextTest() {
|
||||||
|
counter++;
|
||||||
|
if (counter == tests.length) {
|
||||||
|
window.ConnectSrcExaminer.remove();
|
||||||
|
SimpleTest.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var src = "file_testserver.sjs";
|
||||||
|
// append the file that should be served
|
||||||
|
src += "?file=" + escape("tests/dom/security/test/csp/file_ping.html");
|
||||||
|
// append the CSP that should be used to serve the file
|
||||||
|
src += "&csp=" + escape(tests[counter].policy);
|
||||||
|
|
||||||
|
document.getElementById("testframe").src = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start running the tests
|
||||||
|
loadNextTest();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -10,8 +10,7 @@
|
||||||
* liability, trademark and document use rules apply.
|
* liability, trademark and document use rules apply.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Not yet implemented:
|
[Func="nsDocument::IsWebAnimationsEnabled",
|
||||||
// [Constructor (DOMHighResTimeStamp originTime)]
|
Constructor (DOMHighResTimeStamp originTime)]
|
||||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
|
||||||
interface DocumentTimeline : AnimationTimeline {
|
interface DocumentTimeline : AnimationTimeline {
|
||||||
};
|
};
|
||||||
|
|
|
@ -852,4 +852,11 @@ gfxPlatformGtk::CreateHardwareVsyncSource()
|
||||||
return gfxPlatform::CreateHardwareVsyncSource();
|
return gfxPlatform::CreateHardwareVsyncSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
gfxPlatformGtk::SupportsApzTouchInput() const
|
||||||
|
{
|
||||||
|
int value = gfxPrefs::TouchEventsEnabled();
|
||||||
|
return value == 1 || value == 2;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -123,6 +123,8 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SupportsApzTouchInput() const override;
|
||||||
|
|
||||||
void FontsPrefsChanged(const char *aPref) override;
|
void FontsPrefsChanged(const char *aPref) override;
|
||||||
|
|
||||||
// maximum number of fonts to substitute for a generic
|
// maximum number of fonts to substitute for a generic
|
||||||
|
|
|
@ -429,7 +429,8 @@ Decoder::PostFrameStop(Opacity aFrameOpacity
|
||||||
DisposalMethod aDisposalMethod
|
DisposalMethod aDisposalMethod
|
||||||
/* = DisposalMethod::KEEP */,
|
/* = DisposalMethod::KEEP */,
|
||||||
int32_t aTimeout /* = 0 */,
|
int32_t aTimeout /* = 0 */,
|
||||||
BlendMethod aBlendMethod /* = BlendMethod::OVER */)
|
BlendMethod aBlendMethod /* = BlendMethod::OVER */,
|
||||||
|
const Maybe<nsIntRect>& aBlendRect /* = Nothing() */)
|
||||||
{
|
{
|
||||||
// We should be mid-frame
|
// We should be mid-frame
|
||||||
MOZ_ASSERT(!IsMetadataDecode(), "Stopping frame during metadata decode");
|
MOZ_ASSERT(!IsMetadataDecode(), "Stopping frame during metadata decode");
|
||||||
|
@ -439,7 +440,8 @@ Decoder::PostFrameStop(Opacity aFrameOpacity
|
||||||
// Update our state
|
// Update our state
|
||||||
mInFrame = false;
|
mInFrame = false;
|
||||||
|
|
||||||
mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout, aBlendMethod);
|
mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout,
|
||||||
|
aBlendMethod, aBlendRect);
|
||||||
|
|
||||||
mProgress |= FLAG_FRAME_COMPLETE;
|
mProgress |= FLAG_FRAME_COMPLETE;
|
||||||
|
|
||||||
|
|
|
@ -332,7 +332,8 @@ protected:
|
||||||
void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
|
void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
|
||||||
DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
|
DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
|
||||||
int32_t aTimeout = 0,
|
int32_t aTimeout = 0,
|
||||||
BlendMethod aBlendMethod = BlendMethod::OVER);
|
BlendMethod aBlendMethod = BlendMethod::OVER,
|
||||||
|
const Maybe<nsIntRect>& aBlendRect = Nothing());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the decoders when they have a region to invalidate. We may not
|
* Called by the decoders when they have a region to invalidate. We may not
|
||||||
|
|
|
@ -625,7 +625,8 @@ FrameAnimator::DoBlend(nsIntRect* aDirtyRect,
|
||||||
prevFrameData.mHasAlpha,
|
prevFrameData.mHasAlpha,
|
||||||
compositingFrameData.mRawData,
|
compositingFrameData.mRawData,
|
||||||
compositingFrameData.mRect,
|
compositingFrameData.mRect,
|
||||||
prevFrameData.mBlendMethod);
|
prevFrameData.mBlendMethod,
|
||||||
|
prevFrameData.mBlendRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -673,7 +674,8 @@ FrameAnimator::DoBlend(nsIntRect* aDirtyRect,
|
||||||
nextFrameData.mHasAlpha,
|
nextFrameData.mHasAlpha,
|
||||||
compositingFrameData.mRawData,
|
compositingFrameData.mRawData,
|
||||||
compositingFrameData.mRect,
|
compositingFrameData.mRect,
|
||||||
nextFrameData.mBlendMethod);
|
nextFrameData.mBlendMethod,
|
||||||
|
nextFrameData.mBlendRect);
|
||||||
|
|
||||||
// Tell the image that it is fully 'downloaded'.
|
// Tell the image that it is fully 'downloaded'.
|
||||||
mCompositingFrame->Finish();
|
mCompositingFrame->Finish();
|
||||||
|
@ -742,7 +744,7 @@ nsresult
|
||||||
FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect,
|
FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect,
|
||||||
uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
|
uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
|
||||||
uint8_t* aDstPixels, const nsIntRect& aDstRect,
|
uint8_t* aDstPixels, const nsIntRect& aDstRect,
|
||||||
BlendMethod aBlendMethod)
|
BlendMethod aBlendMethod, const Maybe<nsIntRect>& aBlendRect)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aSrcData);
|
NS_ENSURE_ARG_POINTER(aSrcData);
|
||||||
NS_ENSURE_ARG_POINTER(aDstPixels);
|
NS_ENSURE_ARG_POINTER(aDstPixels);
|
||||||
|
@ -822,16 +824,53 @@ FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect,
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX(seth): This is inefficient but we'll remove it quite soon when we
|
||||||
|
// move frame compositing into SurfacePipe. For now we need this because
|
||||||
|
// RemoveFrameRectFilter has transformed PNG frames with frame rects into
|
||||||
|
// imgFrame's with no frame rects, but with a region of 0 alpha where the
|
||||||
|
// frame rect should be. This works really nicely if we're using
|
||||||
|
// BlendMethod::OVER, but BlendMethod::SOURCE will result in that frame rect
|
||||||
|
// area overwriting the previous frame, which makes the animation look
|
||||||
|
// wrong. This quick hack fixes that by first compositing the whle new frame
|
||||||
|
// with BlendMethod::OVER, and then recopying the area that uses
|
||||||
|
// BlendMethod::SOURCE if needed. To make this work, the decoder has to
|
||||||
|
// provide a "blend rect" that tells us where to do this. This is just the
|
||||||
|
// frame rect, but hidden in a way that makes it invisible to most of the
|
||||||
|
// system, so we can keep eliminating dependencies on it.
|
||||||
auto op = aBlendMethod == BlendMethod::SOURCE ? PIXMAN_OP_SRC
|
auto op = aBlendMethod == BlendMethod::SOURCE ? PIXMAN_OP_SRC
|
||||||
: PIXMAN_OP_OVER;
|
: PIXMAN_OP_OVER;
|
||||||
pixman_image_composite32(op,
|
|
||||||
src,
|
if (aBlendMethod == BlendMethod::OVER || !aBlendRect ||
|
||||||
nullptr,
|
(aBlendMethod == BlendMethod::SOURCE && aSrcRect.IsEqualEdges(*aBlendRect))) {
|
||||||
dst,
|
// We don't need to do anything clever. (Or, in the case where no blend
|
||||||
0, 0,
|
// rect was specified, we can't.)
|
||||||
0, 0,
|
pixman_image_composite32(op,
|
||||||
aSrcRect.x, aSrcRect.y,
|
src,
|
||||||
aSrcRect.width, aSrcRect.height);
|
nullptr,
|
||||||
|
dst,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
aSrcRect.x, aSrcRect.y,
|
||||||
|
aSrcRect.width, aSrcRect.height);
|
||||||
|
} else {
|
||||||
|
// We need to do the OVER followed by SOURCE trick above.
|
||||||
|
pixman_image_composite32(PIXMAN_OP_OVER,
|
||||||
|
src,
|
||||||
|
nullptr,
|
||||||
|
dst,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
aSrcRect.x, aSrcRect.y,
|
||||||
|
aSrcRect.width, aSrcRect.height);
|
||||||
|
pixman_image_composite32(PIXMAN_OP_SRC,
|
||||||
|
src,
|
||||||
|
nullptr,
|
||||||
|
dst,
|
||||||
|
aBlendRect->x, aBlendRect->y,
|
||||||
|
0, 0,
|
||||||
|
aBlendRect->x, aBlendRect->y,
|
||||||
|
aBlendRect->width, aBlendRect->height);
|
||||||
|
}
|
||||||
|
|
||||||
pixman_image_unref(src);
|
pixman_image_unref(src);
|
||||||
pixman_image_unref(dst);
|
pixman_image_unref(dst);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef mozilla_image_FrameAnimator_h
|
#ifndef mozilla_image_FrameAnimator_h
|
||||||
#define mozilla_image_FrameAnimator_h
|
#define mozilla_image_FrameAnimator_h
|
||||||
|
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/TimeStamp.h"
|
#include "mozilla/TimeStamp.h"
|
||||||
#include "gfx2DGlue.h"
|
#include "gfx2DGlue.h"
|
||||||
|
@ -246,7 +247,8 @@ private: // methods
|
||||||
const nsIntRect& aSrcRect,
|
const nsIntRect& aSrcRect,
|
||||||
uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
|
uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
|
||||||
uint8_t* aDstPixels, const nsIntRect& aDstRect,
|
uint8_t* aDstPixels, const nsIntRect& aDstRect,
|
||||||
BlendMethod aBlendMethod);
|
BlendMethod aBlendMethod,
|
||||||
|
const Maybe<nsIntRect>& aBlendRect);
|
||||||
|
|
||||||
private: // data
|
private: // data
|
||||||
//! A weak pointer to our owning image.
|
//! A weak pointer to our owning image.
|
||||||
|
|
|
@ -32,13 +32,13 @@ struct ShutdownObserver : public nsIObserver
|
||||||
|
|
||||||
NS_IMETHOD Observe(nsISupports*, const char* aTopic, const char16_t*) override
|
NS_IMETHOD Observe(nsISupports*, const char* aTopic, const char16_t*) override
|
||||||
{
|
{
|
||||||
if (strcmp(aTopic, "xpcom-shutdown") != 0) {
|
if (strcmp(aTopic, "xpcom-will-shutdown") != 0) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||||
if (os) {
|
if (os) {
|
||||||
os->RemoveObserver(this, "xpcom-shutdown");
|
os->RemoveObserver(this, "xpcom-will-shutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
sShutdownHasStarted = true;
|
sShutdownHasStarted = true;
|
||||||
|
@ -61,7 +61,7 @@ ShutdownTracker::Initialize()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||||
if (os) {
|
if (os) {
|
||||||
os->AddObserver(new ShutdownObserver, "xpcom-shutdown", false);
|
os->AddObserver(new ShutdownObserver, "xpcom-will-shutdown", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ namespace image {
|
||||||
/**
|
/**
|
||||||
* ShutdownTracker is an imagelib-global service that allows callers to check
|
* ShutdownTracker is an imagelib-global service that allows callers to check
|
||||||
* whether shutdown has started. It exists to avoid the need for registering
|
* whether shutdown has started. It exists to avoid the need for registering
|
||||||
* many 'xpcom-shutdown' notification observers on short-lived objects, which
|
* many 'xpcom-will-shutdown' notification observers on short-lived objects,
|
||||||
* would have an unnecessary performance cost.
|
* which would have an unnecessary performance cost.
|
||||||
*/
|
*/
|
||||||
struct ShutdownTracker
|
struct ShutdownTracker
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef mozilla_image_SurfaceFilters_h
|
#ifndef mozilla_image_SurfaceFilters_h
|
||||||
#define mozilla_image_SurfaceFilters_h
|
#define mozilla_image_SurfaceFilters_h
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -530,6 +531,362 @@ private:
|
||||||
/// that we're currently writing.
|
/// that we're currently writing.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ADAM7InterpolatingFilter
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <typename Next> class ADAM7InterpolatingFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration struct for ADAM7InterpolatingFilter.
|
||||||
|
*/
|
||||||
|
struct ADAM7InterpolatingConfig
|
||||||
|
{
|
||||||
|
template <typename Next> using Filter = ADAM7InterpolatingFilter<Next>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ADAM7InterpolatingFilter performs bilinear interpolation over an ADAM7
|
||||||
|
* interlaced image.
|
||||||
|
*
|
||||||
|
* ADAM7 breaks up the image into 8x8 blocks. On each of the 7 passes, a new set
|
||||||
|
* of pixels in each block receives their final values, according to the
|
||||||
|
* following pattern:
|
||||||
|
*
|
||||||
|
* 1 6 4 6 2 6 4 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
* 5 6 5 6 5 6 5 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
* 3 6 4 6 3 6 4 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
* 5 6 5 6 5 6 5 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
*
|
||||||
|
* When rendering the pixels that have not yet received their final values, we
|
||||||
|
* can get much better intermediate results if we interpolate between
|
||||||
|
* the pixels we *have* gotten so far. This filter performs bilinear
|
||||||
|
* interpolation by first performing linear interpolation horizontally for each
|
||||||
|
* "important" row (which we'll define as a row that has received any pixels
|
||||||
|
* with final values at all) and then performing linear interpolation vertically
|
||||||
|
* to produce pixel values for rows which aren't important on the current pass.
|
||||||
|
*
|
||||||
|
* Note that this filter totally ignores the data which is written to rows which
|
||||||
|
* aren't important on the current pass! It's fine to write nothing at all for
|
||||||
|
* these rows, although doing so won't cause any harm.
|
||||||
|
*
|
||||||
|
* XXX(seth): In bug 1280552 we'll add a SIMD implementation for this filter.
|
||||||
|
*
|
||||||
|
* The 'Next' template parameter specifies the next filter in the chain.
|
||||||
|
*/
|
||||||
|
template <typename Next>
|
||||||
|
class ADAM7InterpolatingFilter final : public SurfaceFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ADAM7InterpolatingFilter()
|
||||||
|
: mPass(0) // The current pass, in the range 1..7. Starts at 0 so that
|
||||||
|
// DoResetToFirstRow() doesn't have to special case the first pass.
|
||||||
|
, mRow(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template <typename... Rest>
|
||||||
|
nsresult Configure(const ADAM7InterpolatingConfig& aConfig, Rest... aRest)
|
||||||
|
{
|
||||||
|
nsresult rv = mNext.Configure(aRest...);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNext.IsValidPalettedPipe()) {
|
||||||
|
NS_WARNING("ADAM7InterpolatingFilter used with paletted pipe?");
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have two intermediate buffers, one for the previous row with final
|
||||||
|
// pixel values and one for the row that the previous filter in the chain is
|
||||||
|
// currently writing to.
|
||||||
|
size_t inputWidthInBytes = mNext.InputSize().width * sizeof(uint32_t);
|
||||||
|
mPreviousRow.reset(new (fallible) uint8_t[inputWidthInBytes]);
|
||||||
|
if (MOZ_UNLIKELY(!mPreviousRow)) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentRow.reset(new (fallible) uint8_t[inputWidthInBytes]);
|
||||||
|
if (MOZ_UNLIKELY(!mCurrentRow)) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(mPreviousRow.get(), 0, inputWidthInBytes);
|
||||||
|
memset(mCurrentRow.get(), 0, inputWidthInBytes);
|
||||||
|
|
||||||
|
ConfigureFilter(mNext.InputSize(), sizeof(uint32_t));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<SurfaceInvalidRect> TakeInvalidRect() override
|
||||||
|
{
|
||||||
|
return mNext.TakeInvalidRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t* DoResetToFirstRow() override
|
||||||
|
{
|
||||||
|
mRow = 0;
|
||||||
|
mPass = std::min(mPass + 1, 7);
|
||||||
|
|
||||||
|
uint8_t* rowPtr = mNext.ResetToFirstRow();
|
||||||
|
if (mPass == 7) {
|
||||||
|
// Short circuit this filter on the final pass, since all pixels have
|
||||||
|
// their final values at that point.
|
||||||
|
return rowPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mCurrentRow.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* DoAdvanceRow() override
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(0 < mPass && mPass <= 7, "Invalid pass");
|
||||||
|
|
||||||
|
int32_t currentRow = mRow;
|
||||||
|
++mRow;
|
||||||
|
|
||||||
|
if (mPass == 7) {
|
||||||
|
// On the final pass we short circuit this filter totally.
|
||||||
|
return mNext.AdvanceRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t lastImportantRow = LastImportantRow(InputSize().height, mPass);
|
||||||
|
if (currentRow > lastImportantRow) {
|
||||||
|
return nullptr; // This pass is already complete.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsImportantRow(currentRow, mPass)) {
|
||||||
|
// We just ignore whatever the caller gives us for these rows. We'll
|
||||||
|
// interpolate them in later.
|
||||||
|
return mCurrentRow.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an important row. We need to perform horizontal interpolation for
|
||||||
|
// these rows.
|
||||||
|
InterpolateHorizontally(mCurrentRow.get(), InputSize().width, mPass);
|
||||||
|
|
||||||
|
// Interpolate vertically between the previous important row and the current
|
||||||
|
// important row. We skip this if the current row is 0 (which is always an
|
||||||
|
// important row), because in that case there is no previous important row
|
||||||
|
// to interpolate with.
|
||||||
|
if (currentRow != 0) {
|
||||||
|
InterpolateVertically(mPreviousRow.get(), mCurrentRow.get(), mPass, mNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out the current row itself, which, being an important row, does not
|
||||||
|
// need vertical interpolation.
|
||||||
|
uint32_t* currentRowAsPixels = reinterpret_cast<uint32_t*>(mCurrentRow.get());
|
||||||
|
mNext.WriteBuffer(currentRowAsPixels);
|
||||||
|
|
||||||
|
if (currentRow == lastImportantRow) {
|
||||||
|
// This is the last important row, which completes this pass. Note that
|
||||||
|
// for very small images, this may be the first row! Since there won't be
|
||||||
|
// another important row, there's nothing to interpolate with vertically,
|
||||||
|
// so we just duplicate this row until the end of the image.
|
||||||
|
while (mNext.WriteBuffer(currentRowAsPixels) == WriteState::NEED_MORE_DATA) { }
|
||||||
|
|
||||||
|
// All of the remaining rows in the image were determined above, so we're done.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The current row is now the previous important row; save it.
|
||||||
|
Swap(mPreviousRow, mCurrentRow);
|
||||||
|
|
||||||
|
MOZ_ASSERT(mRow < InputSize().height, "Reached the end of the surface without "
|
||||||
|
"hitting the last important row?");
|
||||||
|
|
||||||
|
return mCurrentRow.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void InterpolateVertically(uint8_t* aPreviousRow,
|
||||||
|
uint8_t* aCurrentRow,
|
||||||
|
uint8_t aPass,
|
||||||
|
SurfaceFilter& aNext)
|
||||||
|
{
|
||||||
|
const float* weights = InterpolationWeights(ImportantRowStride(aPass));
|
||||||
|
|
||||||
|
// We need to interpolate vertically to generate the rows between the
|
||||||
|
// previous important row and the next one. Recall that important rows are
|
||||||
|
// rows which contain at least some final pixels; see
|
||||||
|
// InterpolateHorizontally() for some additional explanation as to what that
|
||||||
|
// means. Note that we've already written out the previous important row, so
|
||||||
|
// we start the iteration at 1.
|
||||||
|
for (int32_t outRow = 1; outRow < ImportantRowStride(aPass); ++outRow) {
|
||||||
|
const float weight = weights[outRow];
|
||||||
|
|
||||||
|
// We iterate through the previous and current important row every time we
|
||||||
|
// write out an interpolated row, so we need to copy the pointers.
|
||||||
|
uint8_t* prevRowBytes = aPreviousRow;
|
||||||
|
uint8_t* currRowBytes = aCurrentRow;
|
||||||
|
|
||||||
|
// Write out the interpolated pixels. Interpolation is componentwise.
|
||||||
|
aNext.template WritePixelsToRow<uint32_t>([&]{
|
||||||
|
uint32_t pixel = 0;
|
||||||
|
auto* component = reinterpret_cast<uint8_t*>(&pixel);
|
||||||
|
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
|
||||||
|
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
|
||||||
|
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
|
||||||
|
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
|
||||||
|
return AsVariant(pixel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InterpolateHorizontally(uint8_t* aRow, int32_t aWidth, uint8_t aPass)
|
||||||
|
{
|
||||||
|
// Collect the data we'll need to perform horizontal interpolation. The
|
||||||
|
// terminology here bears some explanation: a "final pixel" is a pixel which
|
||||||
|
// has received its final value. On each pass, a new set of pixels receives
|
||||||
|
// their final value; see the diagram above of the 8x8 pattern that ADAM7
|
||||||
|
// uses. Any pixel which hasn't received its final value on this pass
|
||||||
|
// derives its value from either horizontal or vertical interpolation
|
||||||
|
// instead.
|
||||||
|
const size_t finalPixelStride = FinalPixelStride(aPass);
|
||||||
|
const size_t finalPixelStrideBytes = finalPixelStride * sizeof(uint32_t);
|
||||||
|
const size_t lastFinalPixel = LastFinalPixel(aWidth, aPass);
|
||||||
|
const size_t lastFinalPixelBytes = lastFinalPixel * sizeof(uint32_t);
|
||||||
|
const float* weights = InterpolationWeights(finalPixelStride);
|
||||||
|
|
||||||
|
// Interpolate blocks of pixels which lie between two final pixels.
|
||||||
|
// Horizontal interpolation is done in place, as we'll need the results
|
||||||
|
// later when we vertically interpolate.
|
||||||
|
for (size_t blockBytes = 0;
|
||||||
|
blockBytes < lastFinalPixelBytes;
|
||||||
|
blockBytes += finalPixelStrideBytes) {
|
||||||
|
uint8_t* finalPixelA = aRow + blockBytes;
|
||||||
|
uint8_t* finalPixelB = aRow + blockBytes + finalPixelStrideBytes;
|
||||||
|
|
||||||
|
MOZ_ASSERT(finalPixelA < aRow + aWidth * sizeof(uint32_t),
|
||||||
|
"Running off end of buffer");
|
||||||
|
MOZ_ASSERT(finalPixelB < aRow + aWidth * sizeof(uint32_t),
|
||||||
|
"Running off end of buffer");
|
||||||
|
|
||||||
|
// Interpolate the individual pixels componentwise. Note that we start
|
||||||
|
// iteration at 1 since we don't need to apply any interpolation to the
|
||||||
|
// first pixel in the block, which has its final value.
|
||||||
|
for (size_t pixelIndex = 1; pixelIndex < finalPixelStride; ++pixelIndex) {
|
||||||
|
const float weight = weights[pixelIndex];
|
||||||
|
uint8_t* pixel = aRow + blockBytes + pixelIndex * sizeof(uint32_t);
|
||||||
|
|
||||||
|
MOZ_ASSERT(pixel < aRow + aWidth * sizeof(uint32_t), "Running off end of buffer");
|
||||||
|
|
||||||
|
for (size_t component = 0; component < sizeof(uint32_t); ++component) {
|
||||||
|
pixel[component] =
|
||||||
|
InterpolateByte(finalPixelA[component], finalPixelB[component], weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the pixels after the last final pixel in the row, there isn't a
|
||||||
|
// second final pixel to interpolate with, so just duplicate.
|
||||||
|
uint32_t* rowPixels = reinterpret_cast<uint32_t*>(aRow);
|
||||||
|
uint32_t pixelToDuplicate = rowPixels[lastFinalPixel];
|
||||||
|
for (int32_t pixelIndex = lastFinalPixel + 1;
|
||||||
|
pixelIndex < aWidth;
|
||||||
|
++pixelIndex) {
|
||||||
|
MOZ_ASSERT(pixelIndex < aWidth, "Running off end of buffer");
|
||||||
|
rowPixels[pixelIndex] = pixelToDuplicate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t InterpolateByte(uint8_t aByteA, uint8_t aByteB, float aWeight)
|
||||||
|
{
|
||||||
|
return uint8_t(aByteA * aWeight + aByteB * (1.0f - aWeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t ImportantRowStride(uint8_t aPass)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(0 < aPass && aPass <= 7, "Invalid pass");
|
||||||
|
|
||||||
|
// The stride between important rows for each pass, with a dummy value for
|
||||||
|
// the nonexistent pass 0.
|
||||||
|
static int32_t strides[] = { 1, 8, 8, 4, 4, 2, 2, 1 };
|
||||||
|
|
||||||
|
return strides[aPass];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsImportantRow(int32_t aRow, uint8_t aPass)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aRow >= 0);
|
||||||
|
|
||||||
|
// Whether the row is important comes down to divisibility by the stride for
|
||||||
|
// this pass, which is always a power of 2, so we can check using a mask.
|
||||||
|
int32_t mask = ImportantRowStride(aPass) - 1;
|
||||||
|
return (aRow & mask) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t LastImportantRow(int32_t aHeight, uint8_t aPass)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aHeight > 0);
|
||||||
|
|
||||||
|
// We can find the last important row using the same mask trick as above.
|
||||||
|
int32_t lastRow = aHeight - 1;
|
||||||
|
int32_t mask = ImportantRowStride(aPass) - 1;
|
||||||
|
return lastRow - (lastRow & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t FinalPixelStride(uint8_t aPass)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(0 < aPass && aPass <= 7, "Invalid pass");
|
||||||
|
|
||||||
|
// The stride between the final pixels in important rows for each pass, with
|
||||||
|
// a dummy value for the nonexistent pass 0.
|
||||||
|
static size_t strides[] = { 1, 8, 4, 4, 2, 2, 1, 1 };
|
||||||
|
|
||||||
|
return strides[aPass];
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t LastFinalPixel(int32_t aWidth, uint8_t aPass)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aWidth >= 0);
|
||||||
|
|
||||||
|
// Again, we can use the mask trick above to find the last important pixel.
|
||||||
|
int32_t lastColumn = aWidth - 1;
|
||||||
|
size_t mask = FinalPixelStride(aPass) - 1;
|
||||||
|
return lastColumn - (lastColumn & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const float* InterpolationWeights(int32_t aStride)
|
||||||
|
{
|
||||||
|
// Precalculated interpolation weights. These are used to interpolate
|
||||||
|
// between final pixels or between important rows. Although no interpolation
|
||||||
|
// is actually applied to the previous final pixel or important row value,
|
||||||
|
// the arrays still start with 1.0f, which is always skipped, primarily
|
||||||
|
// because otherwise |stride1Weights| would have zero elements.
|
||||||
|
static float stride8Weights[] =
|
||||||
|
{ 1.0f, 7 / 8.0f, 6 / 8.0f, 5 / 8.0f, 4 / 8.0f, 3 / 8.0f, 2 / 8.0f, 1 / 8.0f };
|
||||||
|
static float stride4Weights[] = { 1.0f, 3 / 4.0f, 2 / 4.0f, 1 / 4.0f };
|
||||||
|
static float stride2Weights[] = { 1.0f, 1 / 2.0f };
|
||||||
|
static float stride1Weights[] = { 1.0f };
|
||||||
|
|
||||||
|
switch (aStride) {
|
||||||
|
case 8: return stride8Weights;
|
||||||
|
case 4: return stride4Weights;
|
||||||
|
case 2: return stride2Weights;
|
||||||
|
case 1: return stride1Weights;
|
||||||
|
default: MOZ_CRASH();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Next mNext; /// The next SurfaceFilter in the chain.
|
||||||
|
|
||||||
|
UniquePtr<uint8_t[]> mPreviousRow; /// The last important row (i.e., row with
|
||||||
|
/// final pixel values) that got written to.
|
||||||
|
UniquePtr<uint8_t[]> mCurrentRow; /// The row that's being written to right
|
||||||
|
/// now.
|
||||||
|
uint8_t mPass; /// Which ADAM7 pass we're on. Valid passes
|
||||||
|
/// are 1..7 during processing and 0 prior
|
||||||
|
/// to configuraiton.
|
||||||
|
int32_t mRow; /// The row we're currently reading.
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace image
|
} // namespace image
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,13 @@ enum class SurfacePipeFlags
|
||||||
{
|
{
|
||||||
DEINTERLACE = 1 << 0, // If set, deinterlace the image.
|
DEINTERLACE = 1 << 0, // If set, deinterlace the image.
|
||||||
|
|
||||||
FLIP_VERTICALLY = 1 << 1, // If set, flip the image vertically.
|
ADAM7_INTERPOLATE = 1 << 1, // If set, the caller is deinterlacing the
|
||||||
|
// image using ADAM7, and we may want to
|
||||||
|
// interpolate it for better intermediate results.
|
||||||
|
|
||||||
PROGRESSIVE_DISPLAY = 1 << 2 // If set, we expect the image to be displayed
|
FLIP_VERTICALLY = 1 << 2, // If set, flip the image vertically.
|
||||||
|
|
||||||
|
PROGRESSIVE_DISPLAY = 1 << 3 // If set, we expect the image to be displayed
|
||||||
// progressively. This enables features that
|
// progressively. This enables features that
|
||||||
// result in a better user experience for
|
// result in a better user experience for
|
||||||
// progressive display but which may be more
|
// progressive display but which may be more
|
||||||
|
@ -99,12 +103,26 @@ public:
|
||||||
const bool removeFrameRect =
|
const bool removeFrameRect =
|
||||||
!aFrameRect.IsEqualEdges(nsIntRect(0, 0, aInputSize.width, aInputSize.height));
|
!aFrameRect.IsEqualEdges(nsIntRect(0, 0, aInputSize.width, aInputSize.height));
|
||||||
|
|
||||||
|
// Don't interpolate if we're sure we won't show this surface to the user
|
||||||
|
// until it's completely decoded. The final pass of an ADAM7 image doesn't
|
||||||
|
// need interpolation, so we only need to interpolate if we'll be displaying
|
||||||
|
// the image while it's still being decoded.
|
||||||
|
const bool adam7Interpolate = bool(aFlags & SurfacePipeFlags::ADAM7_INTERPOLATE) &&
|
||||||
|
progressiveDisplay;
|
||||||
|
|
||||||
|
if (deinterlace && adam7Interpolate) {
|
||||||
|
MOZ_ASSERT_UNREACHABLE("ADAM7 deinterlacing is handled by libpng");
|
||||||
|
return Nothing();
|
||||||
|
}
|
||||||
|
|
||||||
// Construct configurations for the SurfaceFilters. Note that the order of
|
// Construct configurations for the SurfaceFilters. Note that the order of
|
||||||
// these filters is significant. We want to deinterlace raw input rows,
|
// these filters is significant. We want to deinterlace or interpolate raw
|
||||||
// before any other transformations, and we want to remove the frame rect
|
// input rows, before any other transformations, and we want to remove the
|
||||||
// (which may involve adding blank rows or columns to the image) before any
|
// frame rect (which may involve adding blank rows or columns to the image)
|
||||||
// downscaling, so that the new rows and columns are taken into account.
|
// before any downscaling, so that the new rows and columns are taken into
|
||||||
|
// account.
|
||||||
DeinterlacingConfig<uint32_t> deinterlacingConfig { progressiveDisplay };
|
DeinterlacingConfig<uint32_t> deinterlacingConfig { progressiveDisplay };
|
||||||
|
ADAM7InterpolatingConfig interpolatingConfig;
|
||||||
RemoveFrameRectConfig removeFrameRectConfig { aFrameRect };
|
RemoveFrameRectConfig removeFrameRectConfig { aFrameRect };
|
||||||
DownscalingConfig downscalingConfig { aInputSize, aFormat };
|
DownscalingConfig downscalingConfig { aInputSize, aFormat };
|
||||||
SurfaceConfig surfaceConfig { aDecoder, aFrameNum, aOutputSize,
|
SurfaceConfig surfaceConfig { aDecoder, aFrameNum, aOutputSize,
|
||||||
|
@ -117,13 +135,18 @@ public:
|
||||||
if (deinterlace) {
|
if (deinterlace) {
|
||||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||||
downscalingConfig, surfaceConfig);
|
downscalingConfig, surfaceConfig);
|
||||||
} else { // (deinterlace is false)
|
} else if (adam7Interpolate) {
|
||||||
|
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||||
|
downscalingConfig, surfaceConfig);
|
||||||
|
} else { // (deinterlace and adam7Interpolate are false)
|
||||||
pipe = MakePipe(removeFrameRectConfig, downscalingConfig, surfaceConfig);
|
pipe = MakePipe(removeFrameRectConfig, downscalingConfig, surfaceConfig);
|
||||||
}
|
}
|
||||||
} else { // (removeFrameRect is false)
|
} else { // (removeFrameRect is false)
|
||||||
if (deinterlace) {
|
if (deinterlace) {
|
||||||
pipe = MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
|
pipe = MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
|
||||||
} else { // (deinterlace is false)
|
} else if (adam7Interpolate) {
|
||||||
|
pipe = MakePipe(interpolatingConfig, downscalingConfig, surfaceConfig);
|
||||||
|
} else { // (deinterlace and adam7Interpolate are false)
|
||||||
pipe = MakePipe(downscalingConfig, surfaceConfig);
|
pipe = MakePipe(downscalingConfig, surfaceConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,13 +154,17 @@ public:
|
||||||
if (removeFrameRect) {
|
if (removeFrameRect) {
|
||||||
if (deinterlace) {
|
if (deinterlace) {
|
||||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, surfaceConfig);
|
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, surfaceConfig);
|
||||||
} else { // (deinterlace is false)
|
} else if (adam7Interpolate) {
|
||||||
|
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, surfaceConfig);
|
||||||
|
} else { // (deinterlace and adam7Interpolate are false)
|
||||||
pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
|
pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
|
||||||
}
|
}
|
||||||
} else { // (removeFrameRect is false)
|
} else { // (removeFrameRect is false)
|
||||||
if (deinterlace) {
|
if (deinterlace) {
|
||||||
pipe = MakePipe(deinterlacingConfig, surfaceConfig);
|
pipe = MakePipe(deinterlacingConfig, surfaceConfig);
|
||||||
} else { // (deinterlace is false)
|
} else if (adam7Interpolate) {
|
||||||
|
pipe = MakePipe(interpolatingConfig, surfaceConfig);
|
||||||
|
} else { // (deinterlace and adam7Interpolate are false)
|
||||||
pipe = MakePipe(surfaceConfig);
|
pipe = MakePipe(surfaceConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include "nspr.h"
|
#include "nspr.h"
|
||||||
#include "png.h"
|
#include "png.h"
|
||||||
#include "RasterImage.h"
|
#include "RasterImage.h"
|
||||||
|
#include "SurfacePipeFactory.h"
|
||||||
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -91,18 +93,23 @@ const uint8_t
|
||||||
nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
||||||
|
|
||||||
nsPNGDecoder::nsPNGDecoder(RasterImage* aImage)
|
nsPNGDecoder::nsPNGDecoder(RasterImage* aImage)
|
||||||
: Decoder(aImage),
|
: Decoder(aImage)
|
||||||
mPNG(nullptr), mInfo(nullptr),
|
, mPNG(nullptr)
|
||||||
mCMSLine(nullptr), interlacebuf(nullptr),
|
, mInfo(nullptr)
|
||||||
mInProfile(nullptr), mTransform(nullptr),
|
, mCMSLine(nullptr)
|
||||||
format(gfx::SurfaceFormat::UNKNOWN),
|
, interlacebuf(nullptr)
|
||||||
mHeaderBytesRead(0), mCMSMode(0),
|
, mInProfile(nullptr)
|
||||||
mChannels(0), mFrameIsHidden(false),
|
, mTransform(nullptr)
|
||||||
mDisablePremultipliedAlpha(false),
|
, format(gfx::SurfaceFormat::UNKNOWN)
|
||||||
mSuccessfulEarlyFinish(false),
|
, mHeaderBytesRead(0)
|
||||||
mNumFrames(0)
|
, mCMSMode(0)
|
||||||
{
|
, mChannels(0)
|
||||||
}
|
, mPass(0)
|
||||||
|
, mFrameIsHidden(false)
|
||||||
|
, mDisablePremultipliedAlpha(false)
|
||||||
|
, mSuccessfulEarlyFinish(false)
|
||||||
|
, mNumFrames(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
nsPNGDecoder::~nsPNGDecoder()
|
nsPNGDecoder::~nsPNGDecoder()
|
||||||
{
|
{
|
||||||
|
@ -125,55 +132,98 @@ nsPNGDecoder::~nsPNGDecoder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
nsPNGDecoder::TransparencyType
|
||||||
nsPNGDecoder::CheckForTransparency(SurfaceFormat aFormat,
|
nsPNGDecoder::GetTransparencyType(SurfaceFormat aFormat,
|
||||||
const IntRect& aFrameRect)
|
const IntRect& aFrameRect)
|
||||||
{
|
{
|
||||||
// Check if the image has a transparent color in its palette.
|
// Check if the image has a transparent color in its palette.
|
||||||
if (aFormat == SurfaceFormat::B8G8R8A8) {
|
if (aFormat == SurfaceFormat::B8G8R8A8) {
|
||||||
PostHasTransparency();
|
return TransparencyType::eAlpha;
|
||||||
|
}
|
||||||
|
if (!IntRect(IntPoint(), GetSize()).IsEqualEdges(aFrameRect)) {
|
||||||
|
MOZ_ASSERT(HasAnimation());
|
||||||
|
return TransparencyType::eFrameRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the first frame of animated image doesn't draw into the whole image,
|
return TransparencyType::eNone;
|
||||||
// then record that it is transparent.
|
}
|
||||||
if (mNumFrames == 0 && !IntRect(IntPoint(), GetSize()).IsEqualEdges(aFrameRect)) {
|
|
||||||
MOZ_ASSERT(HasAnimation());
|
void
|
||||||
PostHasTransparency();
|
nsPNGDecoder::PostHasTransparencyIfNeeded(TransparencyType aTransparencyType)
|
||||||
|
{
|
||||||
|
switch (aTransparencyType) {
|
||||||
|
case TransparencyType::eNone:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TransparencyType::eAlpha:
|
||||||
|
PostHasTransparency();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TransparencyType::eFrameRect:
|
||||||
|
// If the first frame of animated image doesn't draw into the whole image,
|
||||||
|
// then record that it is transparent. For subsequent frames, this doesn't
|
||||||
|
// affect transparency, because they're composited on top of all previous
|
||||||
|
// frames.
|
||||||
|
if (mNumFrames == 0) {
|
||||||
|
PostHasTransparency();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateFrame() is used for both simple and animated images
|
// CreateFrame() is used for both simple and animated images.
|
||||||
nsresult
|
nsresult
|
||||||
nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
|
nsPNGDecoder::CreateFrame(SurfaceFormat aFormat,
|
||||||
int32_t aWidth, int32_t aHeight,
|
const IntRect& aFrameRect,
|
||||||
gfx::SurfaceFormat aFormat)
|
bool aIsInterlaced)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(HasSize());
|
MOZ_ASSERT(HasSize());
|
||||||
MOZ_ASSERT(!IsMetadataDecode());
|
MOZ_ASSERT(!IsMetadataDecode());
|
||||||
|
|
||||||
IntRect frameRect(aXOffset, aYOffset, aWidth, aHeight);
|
// Check if we have transparency, and send notifications if needed.
|
||||||
CheckForTransparency(aFormat, frameRect);
|
auto transparency = GetTransparencyType(aFormat, aFrameRect);
|
||||||
|
PostHasTransparencyIfNeeded(transparency);
|
||||||
|
SurfaceFormat format = transparency == TransparencyType::eNone
|
||||||
|
? SurfaceFormat::B8G8R8X8
|
||||||
|
: SurfaceFormat::B8G8R8A8;
|
||||||
|
|
||||||
// Make sure there's no animation or padding if we're downscaling.
|
// Make sure there's no animation or padding if we're downscaling.
|
||||||
|
MOZ_ASSERT_IF(mDownscaler, mNumFrames == 0);
|
||||||
MOZ_ASSERT_IF(mDownscaler, !GetImageMetadata().HasAnimation());
|
MOZ_ASSERT_IF(mDownscaler, !GetImageMetadata().HasAnimation());
|
||||||
MOZ_ASSERT_IF(mDownscaler,
|
MOZ_ASSERT_IF(mDownscaler, transparency != TransparencyType::eFrameRect);
|
||||||
IntRect(IntPoint(), GetSize()).IsEqualEdges(frameRect));
|
|
||||||
|
|
||||||
IntSize targetSize = mDownscaler ? mDownscaler->TargetSize()
|
IntSize targetSize = mDownscaler ? mDownscaler->TargetSize()
|
||||||
: GetSize();
|
: GetSize();
|
||||||
IntRect targetFrameRect = mDownscaler ? IntRect(IntPoint(), targetSize)
|
|
||||||
: frameRect;
|
// If this image is interlaced, we can display better quality intermediate
|
||||||
nsresult rv = AllocateFrame(mNumFrames, targetSize, targetFrameRect, aFormat);
|
// results to the user by post processing them with ADAM7InterpolatingFilter.
|
||||||
if (NS_FAILED(rv)) {
|
SurfacePipeFlags pipeFlags = aIsInterlaced
|
||||||
return rv;
|
? SurfacePipeFlags::ADAM7_INTERPOLATE
|
||||||
|
: SurfacePipeFlags();
|
||||||
|
|
||||||
|
if (mNumFrames == 0) {
|
||||||
|
// The first frame may be displayed progressively.
|
||||||
|
pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
mFrameRect = frameRect;
|
Maybe<SurfacePipe> pipe =
|
||||||
|
SurfacePipeFactory::CreateSurfacePipe(this, mNumFrames, GetSize(), targetSize,
|
||||||
|
aFrameRect, format, pipeFlags);
|
||||||
|
|
||||||
|
if (!pipe) {
|
||||||
|
mPipe = SurfacePipe();
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPipe = Move(*pipe);
|
||||||
|
|
||||||
|
mFrameRect = aFrameRect;
|
||||||
|
mPass = 0;
|
||||||
|
|
||||||
MOZ_LOG(sPNGDecoderAccountingLog, LogLevel::Debug,
|
MOZ_LOG(sPNGDecoderAccountingLog, LogLevel::Debug,
|
||||||
("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
|
("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
|
||||||
"image frame with %dx%d pixels for decoder %p",
|
"image frame with %dx%d pixels for decoder %p",
|
||||||
aWidth, aHeight, this));
|
aFrameRect.width, aFrameRect.height, this));
|
||||||
|
|
||||||
#ifdef PNG_APNG_SUPPORTED
|
#ifdef PNG_APNG_SUPPORTED
|
||||||
if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
|
if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
|
||||||
|
@ -187,15 +237,6 @@ nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mDownscaler) {
|
|
||||||
bool hasAlpha = aFormat != SurfaceFormat::B8G8R8X8;
|
|
||||||
rv = mDownscaler->BeginFrame(frameRect.Size(), Nothing(),
|
|
||||||
mImageData, hasAlpha);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +256,7 @@ nsPNGDecoder::EndImageFrame()
|
||||||
}
|
}
|
||||||
|
|
||||||
PostFrameStop(opacity, mAnimInfo.mDispose, mAnimInfo.mTimeout,
|
PostFrameStop(opacity, mAnimInfo.mDispose, mAnimInfo.mTimeout,
|
||||||
mAnimInfo.mBlend);
|
mAnimInfo.mBlend, Some(mFrameRect));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -458,7 +499,6 @@ PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr,
|
||||||
void
|
void
|
||||||
nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
{
|
{
|
||||||
// int number_passes; NOT USED
|
|
||||||
png_uint_32 width, height;
|
png_uint_32 width, height;
|
||||||
int bit_depth, color_type, interlace_type, compression_type, filter_type;
|
int bit_depth, color_type, interlace_type, compression_type, filter_type;
|
||||||
unsigned int channels;
|
unsigned int channels;
|
||||||
|
@ -478,8 +518,10 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
png_longjmp(decoder->mPNG, 1);
|
png_longjmp(decoder->mPNG, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IntRect frameRect(0, 0, width, height);
|
||||||
|
|
||||||
// Post our size to the superclass
|
// Post our size to the superclass
|
||||||
decoder->PostSize(width, height);
|
decoder->PostSize(frameRect.width, frameRect.height);
|
||||||
if (decoder->HasError()) {
|
if (decoder->HasError()) {
|
||||||
// Setting the size led to an error.
|
// Setting the size led to an error.
|
||||||
png_longjmp(decoder->mPNG, 1);
|
png_longjmp(decoder->mPNG, 1);
|
||||||
|
@ -564,9 +606,9 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// let libpng expand interlaced images
|
// Let libpng expand interlaced images.
|
||||||
if (interlace_type == PNG_INTERLACE_ADAM7) {
|
const bool isInterlaced = interlace_type == PNG_INTERLACE_ADAM7;
|
||||||
// number_passes =
|
if (isInterlaced) {
|
||||||
png_set_interlace_handling(png_ptr);
|
png_set_interlace_handling(png_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,7 +637,7 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
if (decoder->mDownscaler && !decoder->IsFirstFrameDecode()) {
|
if (decoder->mDownscaler && !decoder->IsFirstFrameDecode()) {
|
||||||
MOZ_ASSERT_UNREACHABLE("Doing downscale-during-decode "
|
MOZ_ASSERT_UNREACHABLE("Doing downscale-during-decode "
|
||||||
"for an animated image?");
|
"for an animated image?");
|
||||||
decoder->mDownscaler.reset();
|
png_longjmp(decoder->mPNG, 1); // Abort the decode.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -607,8 +649,8 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
// call PostHasTransparency in the metadata decode if we need to. So it's okay
|
// call PostHasTransparency in the metadata decode if we need to. So it's okay
|
||||||
// to pass IntRect(0, 0, width, height) here for animated images; they will
|
// to pass IntRect(0, 0, width, height) here for animated images; they will
|
||||||
// call with the proper first frame rect in the full decode.
|
// call with the proper first frame rect in the full decode.
|
||||||
decoder->CheckForTransparency(decoder->format,
|
auto transparency = decoder->GetTransparencyType(decoder->format, frameRect);
|
||||||
IntRect(0, 0, width, height));
|
decoder->PostHasTransparencyIfNeeded(transparency);
|
||||||
|
|
||||||
// We have the metadata we're looking for, so we don't need to decode any
|
// We have the metadata we're looking for, so we don't need to decode any
|
||||||
// further.
|
// further.
|
||||||
|
@ -626,7 +668,7 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
decoder->mFrameIsHidden = true;
|
decoder->mFrameIsHidden = true;
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
nsresult rv = decoder->CreateFrame(0, 0, width, height, decoder->format);
|
nsresult rv = decoder->CreateFrame(decoder->format, frameRect, isInterlaced);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||||
}
|
}
|
||||||
|
@ -635,19 +677,19 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (decoder->mTransform &&
|
if (decoder->mTransform && (channels <= 2 || isInterlaced)) {
|
||||||
(channels <= 2 || interlace_type == PNG_INTERLACE_ADAM7)) {
|
|
||||||
uint32_t bpp[] = { 0, 3, 4, 3, 4 };
|
uint32_t bpp[] = { 0, 3, 4, 3, 4 };
|
||||||
decoder->mCMSLine =
|
decoder->mCMSLine =
|
||||||
(uint8_t*)malloc(bpp[channels] * width);
|
static_cast<uint8_t*>(malloc(bpp[channels] * frameRect.width));
|
||||||
if (!decoder->mCMSLine) {
|
if (!decoder->mCMSLine) {
|
||||||
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interlace_type == PNG_INTERLACE_ADAM7) {
|
if (interlace_type == PNG_INTERLACE_ADAM7) {
|
||||||
if (height < INT32_MAX / (width * channels)) {
|
if (frameRect.height < INT32_MAX / (frameRect.width * int32_t(channels))) {
|
||||||
decoder->interlacebuf = (uint8_t*)malloc(channels * width * height);
|
const size_t bufferSize = channels * frameRect.width * frameRect.height;
|
||||||
|
decoder->interlacebuf = static_cast<uint8_t*>(malloc(bufferSize));
|
||||||
}
|
}
|
||||||
if (!decoder->interlacebuf) {
|
if (!decoder->interlacebuf) {
|
||||||
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||||
|
@ -656,106 +698,44 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsPNGDecoder::PostPartialInvalidation(const IntRect& aInvalidRegion)
|
nsPNGDecoder::PostInvalidationIfNeeded()
|
||||||
{
|
{
|
||||||
if (!mDownscaler) {
|
Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
|
||||||
PostInvalidation(aInvalidRegion);
|
if (!invalidRect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mDownscaler->HasInvalidation()) {
|
PostInvalidation(invalidRect->mInputSpaceRect,
|
||||||
return;
|
Some(invalidRect->mOutputSpaceRect));
|
||||||
}
|
|
||||||
|
|
||||||
DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
|
|
||||||
PostInvalidation(invalidRect.mOriginalSizeRect,
|
|
||||||
Some(invalidRect.mTargetSizeRect));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static NextPixel<uint32_t>
|
||||||
nsPNGDecoder::PostFullInvalidation()
|
PackRGBPixelAndAdvance(uint8_t*& aRawPixelInOut)
|
||||||
{
|
{
|
||||||
PostInvalidation(mFrameRect);
|
const uint32_t pixel =
|
||||||
|
gfxPackedPixel(0xFF, aRawPixelInOut[0], aRawPixelInOut[1], aRawPixelInOut[2]);
|
||||||
if (mDownscaler) {
|
aRawPixelInOut += 3;
|
||||||
mDownscaler->ResetForNextProgressivePass();
|
return AsVariant(pixel);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static NextPixel<uint32_t>
|
||||||
InterpolateInterlacedPNG(const int aPass, const bool aHasAlpha,
|
PackRGBAPixelAndAdvance(uint8_t*& aRawPixelInOut)
|
||||||
const uint32_t aWidth, const uint32_t aHeight,
|
|
||||||
uint8_t* aImageData)
|
|
||||||
{
|
{
|
||||||
// At this point we have a completed pass of an interlaced image in
|
const uint32_t pixel =
|
||||||
// imageData as an array of uint8_t ARGB or XRGB pixels, optionally
|
gfxPackedPixel(aRawPixelInOut[3], aRawPixelInOut[0],
|
||||||
// premultiplied, 4 bytes per pixel. If there are leftover partial
|
aRawPixelInOut[1], aRawPixelInOut[2]);
|
||||||
// blocks at the right edge or bottom of the image, we just use the
|
aRawPixelInOut += 4;
|
||||||
// uninterpolated pixels that libpng gave us.
|
return AsVariant(pixel);
|
||||||
//
|
}
|
||||||
// See Bug #75077, Interpolation of interlaced PNG
|
|
||||||
// See https://en.wikipedia.org/wiki/Bilinear_interpolation
|
|
||||||
//
|
|
||||||
// Note: this doesn't work when downscaling so we simply show
|
|
||||||
// the uninterpolated blocks that libpng gives us.
|
|
||||||
//
|
|
||||||
// Don't try to interpolate images that are less than 8 columns wide
|
|
||||||
// or 8 rows high; do only square passes (0, 2, 4)
|
|
||||||
if ((aPass != 0 && aPass != 2 && aPass != 4) || aWidth < 8 || aHeight < 8) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Block dimensions are defined by the PNG specification */
|
static NextPixel<uint32_t>
|
||||||
uint32_t block_width[] = { 8, 4, 4, 2, 2 };
|
PackUnpremultipliedRGBAPixelAndAdvance(uint8_t*& aRawPixelInOut)
|
||||||
uint32_t bw = block_width[aPass];
|
{
|
||||||
uint32_t bh = bw;
|
const uint32_t pixel =
|
||||||
|
gfxPackedPixelNoPreMultiply(aRawPixelInOut[3], aRawPixelInOut[0],
|
||||||
bool first_component = aHasAlpha ? 0: 1;
|
aRawPixelInOut[1], aRawPixelInOut[2]);
|
||||||
|
aRawPixelInOut += 4;
|
||||||
// Reduced version of the PNG_PASS_ROW_SHIFT(pass) macro in libpng/png.h
|
return AsVariant(pixel);
|
||||||
// Only works with square passes 0, 2, and 4
|
|
||||||
uint32_t divisor_shift = 3 - (aPass >> 1);
|
|
||||||
|
|
||||||
// Loop over blocks
|
|
||||||
for (uint32_t y = 0; y < aHeight - bh; y += bh) {
|
|
||||||
for (uint32_t x = 0; x < aWidth - bw; x += bw) {
|
|
||||||
// (x,y) is the top left corner of the block
|
|
||||||
// topleft is the first component of the top left pixel of the block
|
|
||||||
uint8_t* topleft = aImageData + 4 * (x + aWidth * y);
|
|
||||||
|
|
||||||
// Loop over component=[A,]R,G,B
|
|
||||||
for (uint32_t component = first_component; component < 4; component++) {
|
|
||||||
if (x == 0) {
|
|
||||||
// Interpolate ARGB along the left side of the block
|
|
||||||
uint32_t top = *(topleft + component);
|
|
||||||
uint32_t bottom = *(topleft + component + (bh * 4 * aWidth));
|
|
||||||
for (uint32_t j = 1; j < bh; j++) {
|
|
||||||
*(topleft + component + j * 4 * aWidth) =
|
|
||||||
((top * (bh - j) + bottom * j) >> divisor_shift) & 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpolate ARGB along the right side of the block
|
|
||||||
uint32_t top = *(topleft + component + 4 * bw);
|
|
||||||
uint32_t bottom = *(topleft + component + 4 * (bw + (bh * aWidth)));
|
|
||||||
for (uint32_t j = 1; j < bh; j++) {
|
|
||||||
*(topleft + component + 4 * (bw + j * aWidth)) =
|
|
||||||
((top * (bh - j) + bottom * j) >> divisor_shift) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpolate ARGB in the X-direction along the top edge
|
|
||||||
// and within the block
|
|
||||||
for (uint32_t j = 0; j < bh; j++) {
|
|
||||||
uint32_t left = *(topleft + component + 4 * j * aWidth);
|
|
||||||
uint32_t right = *(topleft + component + 4 * (bw + j * aWidth));
|
|
||||||
for (uint32_t i = 1; i < bw; i++) {
|
|
||||||
*(topleft + component + 4 * (i + j * aWidth)) =
|
|
||||||
((left * (bw - i) + right * i) >> divisor_shift) & 0xff;
|
|
||||||
} // i
|
|
||||||
} // j
|
|
||||||
} // component
|
|
||||||
} // x
|
|
||||||
} // y
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -790,127 +770,102 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
|
||||||
* old row and the new row.
|
* old row and the new row.
|
||||||
*/
|
*/
|
||||||
nsPNGDecoder* decoder =
|
nsPNGDecoder* decoder =
|
||||||
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
||||||
|
|
||||||
// skip this frame
|
|
||||||
if (decoder->mFrameIsHidden) {
|
if (decoder->mFrameIsHidden) {
|
||||||
|
return; // Skip this frame.
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pass > decoder->mPass) {
|
||||||
|
// Advance to the next pass. We may have to do this multiple times because
|
||||||
|
// libpng will skip passes if the image is so small that no pixels have
|
||||||
|
// changed on a given pass, but ADAM7InterpolatingFilter needs to be reset
|
||||||
|
// once for every pass to perform interpolation properly.
|
||||||
|
decoder->mPipe.ResetToFirstRow();
|
||||||
|
decoder->mPass++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const png_uint_32 height = static_cast<png_uint_32>(decoder->mFrameRect.height);
|
||||||
|
|
||||||
|
if (row_num >= height) {
|
||||||
|
// Bail if we receive extra rows. This is especially important because if we
|
||||||
|
// didn't, we might overflow the deinterlacing buffer.
|
||||||
|
MOZ_ASSERT_UNREACHABLE("libpng producing extra rows?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row_num >= static_cast<png_uint_32>(decoder->mFrameRect.height)) {
|
// Note that |new_row| may be null here, indicating that this is an interlaced
|
||||||
return;
|
// image and |row_callback| is being called for a row that hasn't changed.
|
||||||
}
|
MOZ_ASSERT_IF(!new_row, decoder->interlacebuf);
|
||||||
|
uint8_t* rowToWrite = new_row;
|
||||||
|
|
||||||
bool lastRow =
|
|
||||||
row_num == static_cast<png_uint_32>(decoder->mFrameRect.height) - 1;
|
|
||||||
|
|
||||||
if (!new_row && !decoder->mDownscaler && !lastRow) {
|
|
||||||
// If |new_row| is null, that indicates that this is an interlaced image
|
|
||||||
// and |row_callback| is being called for a row that hasn't changed.
|
|
||||||
// Ordinarily we don't need to do anything in this case, but if we're
|
|
||||||
// downscaling, the downscaler doesn't store the rows from previous passes,
|
|
||||||
// so we still need to process the row. If |lastRow| is true we need
|
|
||||||
// to finish the interlace pass.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t width = decoder->mFrameRect.width;
|
|
||||||
uint32_t iwidth = decoder->mFrameRect.width;
|
|
||||||
|
|
||||||
png_bytep line = new_row;
|
|
||||||
if (decoder->interlacebuf) {
|
if (decoder->interlacebuf) {
|
||||||
line = decoder->interlacebuf + (row_num * decoder->mChannels * width);
|
uint32_t width = uint32_t(decoder->mFrameRect.width);
|
||||||
png_progressive_combine_row(png_ptr, line, new_row);
|
|
||||||
|
// We'll output the deinterlaced version of the row.
|
||||||
|
rowToWrite = decoder->interlacebuf + (row_num * decoder->mChannels * width);
|
||||||
|
|
||||||
|
// Update the deinterlaced version of this row with the new data.
|
||||||
|
png_progressive_combine_row(png_ptr, rowToWrite, new_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t bpr = width * sizeof(uint32_t);
|
decoder->WriteRow(rowToWrite);
|
||||||
uint32_t* cptr32 = decoder->mDownscaler
|
}
|
||||||
? reinterpret_cast<uint32_t*>(decoder->mDownscaler->RowBuffer())
|
|
||||||
: reinterpret_cast<uint32_t*>(decoder->mImageData + (row_num*bpr));
|
|
||||||
|
|
||||||
if (decoder->mTransform) {
|
void
|
||||||
if (decoder->mCMSLine) {
|
nsPNGDecoder::WriteRow(uint8_t* aRow)
|
||||||
qcms_transform_data(decoder->mTransform, line, decoder->mCMSLine,
|
{
|
||||||
iwidth);
|
MOZ_ASSERT(aRow);
|
||||||
// copy alpha over
|
|
||||||
uint32_t channels = decoder->mChannels;
|
uint8_t* rowToWrite = aRow;
|
||||||
if (channels == 2 || channels == 4) {
|
uint32_t width = uint32_t(mFrameRect.width);
|
||||||
for (uint32_t i = 0; i < iwidth; i++)
|
|
||||||
decoder->mCMSLine[4 * i + 3] = line[channels * i + channels - 1];
|
// Apply color management to the row, if necessary, before writing it out.
|
||||||
|
if (mTransform) {
|
||||||
|
if (mCMSLine) {
|
||||||
|
qcms_transform_data(mTransform, rowToWrite, mCMSLine, width);
|
||||||
|
|
||||||
|
// Copy alpha over.
|
||||||
|
if (mChannels == 2 || mChannels == 4) {
|
||||||
|
for (uint32_t i = 0; i < width; ++i) {
|
||||||
|
mCMSLine[4 * i + 3] = rowToWrite[mChannels * i + mChannels - 1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
line = decoder->mCMSLine;
|
|
||||||
|
rowToWrite = mCMSLine;
|
||||||
} else {
|
} else {
|
||||||
qcms_transform_data(decoder->mTransform, line, line, iwidth);
|
qcms_transform_data(mTransform, rowToWrite, rowToWrite, width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (decoder->format) {
|
// Write this row to the SurfacePipe.
|
||||||
case gfx::SurfaceFormat::B8G8R8X8: {
|
DebugOnly<WriteState> result = WriteState::FAILURE;
|
||||||
// counter for while() loops below
|
switch (format) {
|
||||||
uint32_t idx = iwidth;
|
case SurfaceFormat::B8G8R8X8:
|
||||||
|
result = mPipe.WritePixelsToRow<uint32_t>([&]{
|
||||||
|
return PackRGBPixelAndAdvance(rowToWrite);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
// copy as bytes until source pointer is 32-bit-aligned
|
case SurfaceFormat::B8G8R8A8:
|
||||||
for (; (NS_PTR_TO_UINT32(line) & 0x3) && idx; --idx) {
|
if (mDisablePremultipliedAlpha) {
|
||||||
*cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]);
|
result = mPipe.WritePixelsToRow<uint32_t>([&]{
|
||||||
line += 3;
|
return PackUnpremultipliedRGBAPixelAndAdvance(rowToWrite);
|
||||||
}
|
});
|
||||||
|
|
||||||
// copy pixels in blocks of 4
|
|
||||||
while (idx >= 4) {
|
|
||||||
GFX_BLOCK_RGB_TO_FRGB(line, cptr32);
|
|
||||||
idx -= 4;
|
|
||||||
line += 12;
|
|
||||||
cptr32 += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy remaining pixel(s)
|
|
||||||
while (idx--) {
|
|
||||||
// 32-bit read of final pixel will exceed buffer, so read bytes
|
|
||||||
*cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]);
|
|
||||||
line += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case gfx::SurfaceFormat::B8G8R8A8: {
|
|
||||||
if (!decoder->mDisablePremultipliedAlpha) {
|
|
||||||
for (uint32_t x=width; x>0; --x) {
|
|
||||||
*cptr32++ = gfxPackedPixel(line[3], line[0], line[1], line[2]);
|
|
||||||
line += 4;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (uint32_t x=width; x>0; --x) {
|
result = mPipe.WritePixelsToRow<uint32_t>([&]{
|
||||||
*cptr32++ = gfxPackedPixelNoPreMultiply(line[3], line[0], line[1],
|
return PackRGBAPixelAndAdvance(rowToWrite);
|
||||||
line[2]);
|
});
|
||||||
line += 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
png_longjmp(decoder->mPNG, 1);
|
png_longjmp(mPNG, 1); // Abort the decode.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decoder->mDownscaler) {
|
MOZ_ASSERT(WriteState(result) != WriteState::FAILURE);
|
||||||
decoder->mDownscaler->CommitRow();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!decoder->interlacebuf) {
|
PostInvalidationIfNeeded();
|
||||||
// Do line-by-line partial invalidations for non-interlaced images.
|
|
||||||
decoder->PostPartialInvalidation(IntRect(0, row_num, width, 1));
|
|
||||||
} else if (lastRow) {
|
|
||||||
// Do only one full image invalidation for each even pass. (Bug 1187569)
|
|
||||||
if (decoder->mDownscaler) {
|
|
||||||
decoder->PostFullInvalidation();
|
|
||||||
} else if (pass % 2 == 0) {
|
|
||||||
|
|
||||||
const bool hasAlpha = decoder->format != SurfaceFormat::B8G8R8X8;
|
|
||||||
InterpolateInterlacedPNG(pass, hasAlpha,
|
|
||||||
static_cast<uint32_t>(width),
|
|
||||||
decoder->mFrameRect.height,
|
|
||||||
decoder->mImageData);
|
|
||||||
decoder->PostFullInvalidation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PNG_APNG_SUPPORTED
|
#ifdef PNG_APNG_SUPPORTED
|
||||||
|
@ -918,9 +873,6 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
|
||||||
void
|
void
|
||||||
nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
|
nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
|
||||||
{
|
{
|
||||||
png_uint_32 x_offset, y_offset;
|
|
||||||
int32_t width, height;
|
|
||||||
|
|
||||||
nsPNGDecoder* decoder =
|
nsPNGDecoder* decoder =
|
||||||
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
|
||||||
|
|
||||||
|
@ -938,13 +890,14 @@ nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
|
||||||
// Only the first frame can be hidden, so unhide unconditionally here.
|
// Only the first frame can be hidden, so unhide unconditionally here.
|
||||||
decoder->mFrameIsHidden = false;
|
decoder->mFrameIsHidden = false;
|
||||||
|
|
||||||
x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
|
const IntRect frameRect(png_get_next_frame_x_offset(png_ptr, decoder->mInfo),
|
||||||
y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
|
png_get_next_frame_y_offset(png_ptr, decoder->mInfo),
|
||||||
width = png_get_next_frame_width(png_ptr, decoder->mInfo);
|
png_get_next_frame_width(png_ptr, decoder->mInfo),
|
||||||
height = png_get_next_frame_height(png_ptr, decoder->mInfo);
|
png_get_next_frame_height(png_ptr, decoder->mInfo));
|
||||||
|
|
||||||
nsresult rv =
|
const bool isInterlaced = bool(decoder->interlacebuf);
|
||||||
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
|
|
||||||
|
nsresult rv = decoder->CreateFrame(decoder->format, frameRect, isInterlaced);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,9 @@
|
||||||
#define mozilla_image_decoders_nsPNGDecoder_h
|
#define mozilla_image_decoders_nsPNGDecoder_h
|
||||||
|
|
||||||
#include "Decoder.h"
|
#include "Decoder.h"
|
||||||
|
|
||||||
#include "gfxTypes.h"
|
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
|
|
||||||
#include "png.h"
|
#include "png.h"
|
||||||
|
|
||||||
#include "qcms.h"
|
#include "qcms.h"
|
||||||
|
#include "SurfacePipe.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace image {
|
namespace image {
|
||||||
|
@ -30,13 +25,33 @@ public:
|
||||||
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
|
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
|
||||||
virtual Telemetry::ID SpeedHistogram() override;
|
virtual Telemetry::ID SpeedHistogram() override;
|
||||||
|
|
||||||
nsresult CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
|
private:
|
||||||
int32_t aWidth, int32_t aHeight,
|
friend class DecoderFactory;
|
||||||
gfx::SurfaceFormat aFormat);
|
friend class nsICODecoder;
|
||||||
|
|
||||||
|
// Decoders should only be instantiated via DecoderFactory.
|
||||||
|
// XXX(seth): nsICODecoder is temporarily an exception to this rule.
|
||||||
|
explicit nsPNGDecoder(RasterImage* aImage);
|
||||||
|
|
||||||
|
nsresult CreateFrame(gfx::SurfaceFormat aFormat,
|
||||||
|
const gfx::IntRect& aFrameRect,
|
||||||
|
bool aIsInterlaced);
|
||||||
void EndImageFrame();
|
void EndImageFrame();
|
||||||
|
|
||||||
void CheckForTransparency(gfx::SurfaceFormat aFormat,
|
enum class TransparencyType
|
||||||
const gfx::IntRect& aFrameRect);
|
{
|
||||||
|
eNone,
|
||||||
|
eAlpha,
|
||||||
|
eFrameRect
|
||||||
|
};
|
||||||
|
|
||||||
|
TransparencyType GetTransparencyType(gfx::SurfaceFormat aFormat,
|
||||||
|
const gfx::IntRect& aFrameRect);
|
||||||
|
void PostHasTransparencyIfNeeded(TransparencyType aTransparencyType);
|
||||||
|
|
||||||
|
void PostInvalidationIfNeeded();
|
||||||
|
|
||||||
|
void WriteRow(uint8_t* aRow);
|
||||||
|
|
||||||
// Check if PNG is valid ICO (32bpp RGBA)
|
// Check if PNG is valid ICO (32bpp RGBA)
|
||||||
// http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
|
// http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
|
||||||
|
@ -69,17 +84,6 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
friend class DecoderFactory;
|
|
||||||
friend class nsICODecoder;
|
|
||||||
|
|
||||||
// Decoders should only be instantiated via DecoderFactory.
|
|
||||||
// XXX(seth): nsICODecoder is temporarily an exception to this rule.
|
|
||||||
explicit nsPNGDecoder(RasterImage* aImage);
|
|
||||||
|
|
||||||
void PostPartialInvalidation(const IntRect& aInvalidRegion);
|
|
||||||
void PostFullInvalidation();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
png_structp mPNG;
|
png_structp mPNG;
|
||||||
png_infop mInfo;
|
png_infop mInfo;
|
||||||
|
@ -99,6 +103,7 @@ public:
|
||||||
uint32_t mCMSMode;
|
uint32_t mCMSMode;
|
||||||
|
|
||||||
uint8_t mChannels;
|
uint8_t mChannels;
|
||||||
|
uint8_t mPass;
|
||||||
bool mFrameIsHidden;
|
bool mFrameIsHidden;
|
||||||
bool mDisablePremultipliedAlpha;
|
bool mDisablePremultipliedAlpha;
|
||||||
bool mSuccessfulEarlyFinish;
|
bool mSuccessfulEarlyFinish;
|
||||||
|
@ -117,6 +122,8 @@ public:
|
||||||
|
|
||||||
AnimFrameInfo mAnimInfo;
|
AnimFrameInfo mAnimInfo;
|
||||||
|
|
||||||
|
SurfacePipe mPipe; /// The SurfacePipe used to write to the output surface.
|
||||||
|
|
||||||
// The number of frames we've finished.
|
// The number of frames we've finished.
|
||||||
uint32_t mNumFrames;
|
uint32_t mNumFrames;
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,14 @@
|
||||||
#include "gfxAlphaRecovery.h"
|
#include "gfxAlphaRecovery.h"
|
||||||
|
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
#include "mozilla/Likely.h"
|
|
||||||
#include "MainThreadUtils.h"
|
#include "MainThreadUtils.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
|
||||||
#include "nsMargin.h"
|
|
||||||
#include "nsThreadUtils.h"
|
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "mozilla/gfx/Tools.h"
|
#include "mozilla/gfx/Tools.h"
|
||||||
|
#include "mozilla/Likely.h"
|
||||||
|
#include "mozilla/MemoryReporting.h"
|
||||||
|
#include "mozilla/Telemetry.h"
|
||||||
|
#include "nsMargin.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -397,12 +398,19 @@ imgFrame::Optimize()
|
||||||
// moment
|
// moment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool usedSingleColorOptimizationUsefully = mSinglePixel &&
|
||||||
|
mFrameRect.Area() > 1;
|
||||||
|
Telemetry::Accumulate(Telemetry::IMAGE_OPTIMIZE_TO_SINGLE_COLOR_USED,
|
||||||
|
usedSingleColorOptimizationUsefully);
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
SurfaceFormat optFormat = gfxPlatform::GetPlatform()
|
SurfaceFormat optFormat = gfxPlatform::GetPlatform()
|
||||||
->Optimal2DFormatForContent(gfxContentType::COLOR);
|
->Optimal2DFormatForContent(gfxContentType::COLOR);
|
||||||
|
|
||||||
if (mFormat != SurfaceFormat::B8G8R8A8 &&
|
if (mFormat != SurfaceFormat::B8G8R8A8 &&
|
||||||
optFormat == SurfaceFormat::R5G6B5_UINT16) {
|
optFormat == SurfaceFormat::R5G6B5_UINT16) {
|
||||||
|
Telemetry::Accumulate(Telemetry::IMAGE_OPTIMIZE_TO_565_USED, true);
|
||||||
|
|
||||||
RefPtr<VolatileBuffer> buf =
|
RefPtr<VolatileBuffer> buf =
|
||||||
AllocateBufferForImage(mFrameRect.Size(), optFormat);
|
AllocateBufferForImage(mFrameRect.Size(), optFormat);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
|
@ -638,7 +646,8 @@ void
|
||||||
imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
|
imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
|
||||||
DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */,
|
DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */,
|
||||||
int32_t aRawTimeout /* = 0 */,
|
int32_t aRawTimeout /* = 0 */,
|
||||||
BlendMethod aBlendMethod /* = BlendMethod::OVER */)
|
BlendMethod aBlendMethod /* = BlendMethod::OVER */,
|
||||||
|
const Maybe<IntRect>& aBlendRect /* = Nothing() */)
|
||||||
{
|
{
|
||||||
MonitorAutoLock lock(mMonitor);
|
MonitorAutoLock lock(mMonitor);
|
||||||
MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
|
MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
|
||||||
|
@ -650,6 +659,7 @@ imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
|
||||||
mDisposalMethod = aDisposalMethod;
|
mDisposalMethod = aDisposalMethod;
|
||||||
mTimeout = aRawTimeout;
|
mTimeout = aRawTimeout;
|
||||||
mBlendMethod = aBlendMethod;
|
mBlendMethod = aBlendMethod;
|
||||||
|
mBlendRect = aBlendRect;
|
||||||
ImageUpdatedInternal(GetRect());
|
ImageUpdatedInternal(GetRect());
|
||||||
mFinished = true;
|
mFinished = true;
|
||||||
|
|
||||||
|
@ -925,7 +935,7 @@ imgFrame::GetAnimationData() const
|
||||||
bool hasAlpha = mFormat == SurfaceFormat::B8G8R8A8;
|
bool hasAlpha = mFormat == SurfaceFormat::B8G8R8A8;
|
||||||
|
|
||||||
return AnimationData(data, PaletteDataLength(), mTimeout, GetRect(),
|
return AnimationData(data, PaletteDataLength(), mTimeout, GetRect(),
|
||||||
mBlendMethod, mDisposalMethod, hasAlpha);
|
mBlendMethod, mBlendRect, mDisposalMethod, hasAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef mozilla_image_imgFrame_h
|
#ifndef mozilla_image_imgFrame_h
|
||||||
#define mozilla_image_imgFrame_h
|
#define mozilla_image_imgFrame_h
|
||||||
|
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/Monitor.h"
|
#include "mozilla/Monitor.h"
|
||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
|
@ -57,13 +58,14 @@ struct AnimationData
|
||||||
{
|
{
|
||||||
AnimationData(uint8_t* aRawData, uint32_t aPaletteDataLength,
|
AnimationData(uint8_t* aRawData, uint32_t aPaletteDataLength,
|
||||||
int32_t aRawTimeout, const nsIntRect& aRect,
|
int32_t aRawTimeout, const nsIntRect& aRect,
|
||||||
BlendMethod aBlendMethod, DisposalMethod aDisposalMethod,
|
BlendMethod aBlendMethod, const Maybe<gfx::IntRect>& aBlendRect,
|
||||||
bool aHasAlpha)
|
DisposalMethod aDisposalMethod, bool aHasAlpha)
|
||||||
: mRawData(aRawData)
|
: mRawData(aRawData)
|
||||||
, mPaletteDataLength(aPaletteDataLength)
|
, mPaletteDataLength(aPaletteDataLength)
|
||||||
, mRawTimeout(aRawTimeout)
|
, mRawTimeout(aRawTimeout)
|
||||||
, mRect(aRect)
|
, mRect(aRect)
|
||||||
, mBlendMethod(aBlendMethod)
|
, mBlendMethod(aBlendMethod)
|
||||||
|
, mBlendRect(aBlendRect)
|
||||||
, mDisposalMethod(aDisposalMethod)
|
, mDisposalMethod(aDisposalMethod)
|
||||||
, mHasAlpha(aHasAlpha)
|
, mHasAlpha(aHasAlpha)
|
||||||
{ }
|
{ }
|
||||||
|
@ -73,6 +75,7 @@ struct AnimationData
|
||||||
int32_t mRawTimeout;
|
int32_t mRawTimeout;
|
||||||
nsIntRect mRect;
|
nsIntRect mRect;
|
||||||
BlendMethod mBlendMethod;
|
BlendMethod mBlendMethod;
|
||||||
|
Maybe<gfx::IntRect> mBlendRect;
|
||||||
DisposalMethod mDisposalMethod;
|
DisposalMethod mDisposalMethod;
|
||||||
bool mHasAlpha;
|
bool mHasAlpha;
|
||||||
};
|
};
|
||||||
|
@ -170,11 +173,15 @@ public:
|
||||||
* used; see FrameAnimator::GetTimeoutForFrame.
|
* used; see FrameAnimator::GetTimeoutForFrame.
|
||||||
* @param aBlendMethod For animation frames, a blending method to be used
|
* @param aBlendMethod For animation frames, a blending method to be used
|
||||||
* when compositing this frame.
|
* when compositing this frame.
|
||||||
|
* @param aBlendRect For animation frames, if present, the subrect in
|
||||||
|
* which @aBlendMethod applies. Outside of this
|
||||||
|
* subrect, BlendMethod::OVER is always used.
|
||||||
*/
|
*/
|
||||||
void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
|
void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
|
||||||
DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
|
DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
|
||||||
int32_t aRawTimeout = 0,
|
int32_t aRawTimeout = 0,
|
||||||
BlendMethod aBlendMethod = BlendMethod::OVER);
|
BlendMethod aBlendMethod = BlendMethod::OVER,
|
||||||
|
const Maybe<IntRect>& aBlendRect = Nothing());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
|
* Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
|
||||||
|
@ -309,6 +316,7 @@ private: // data
|
||||||
|
|
||||||
DisposalMethod mDisposalMethod;
|
DisposalMethod mDisposalMethod;
|
||||||
BlendMethod mBlendMethod;
|
BlendMethod mBlendMethod;
|
||||||
|
Maybe<IntRect> mBlendRect;
|
||||||
SurfaceFormat mFormat;
|
SurfaceFormat mFormat;
|
||||||
|
|
||||||
bool mHasNoAlpha;
|
bool mHasNoAlpha;
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace image {
|
||||||
using namespace gfx;
|
using namespace gfx;
|
||||||
|
|
||||||
using std::abs;
|
using std::abs;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// General Helpers
|
// General Helpers
|
||||||
|
@ -42,9 +43,21 @@ using std::abs;
|
||||||
return rv; \
|
return rv; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ASSERT_GE_OR_RETURN(a, b, rv) \
|
||||||
|
EXPECT_GE(a, b); \
|
||||||
|
if (!((a) >= (b))) { \
|
||||||
|
return rv; \
|
||||||
|
}
|
||||||
|
|
||||||
#define ASSERT_LE_OR_RETURN(a, b, rv) \
|
#define ASSERT_LE_OR_RETURN(a, b, rv) \
|
||||||
EXPECT_LE(a, b); \
|
EXPECT_LE(a, b); \
|
||||||
if (!((a) <= (b))) { \
|
if (!((a) <= (b))) { \
|
||||||
|
return rv; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASSERT_LT_OR_RETURN(a, b, rv) \
|
||||||
|
EXPECT_LT(a, b); \
|
||||||
|
if (!((a) < (b))) { \
|
||||||
return rv; \
|
return rv; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +218,41 @@ PalettedRectIsSolidColor(Decoder* aDecoder, const IntRect& aRect, uint8_t aColor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RowHasPixels(SourceSurface* aSurface,
|
||||||
|
int32_t aRow,
|
||||||
|
const vector<BGRAColor>& aPixels)
|
||||||
|
{
|
||||||
|
ASSERT_GE_OR_RETURN(aRow, 0, false);
|
||||||
|
|
||||||
|
IntSize surfaceSize = aSurface->GetSize();
|
||||||
|
ASSERT_EQ_OR_RETURN(aPixels.size(), size_t(surfaceSize.width), false);
|
||||||
|
ASSERT_LT_OR_RETURN(aRow, surfaceSize.height, false);
|
||||||
|
|
||||||
|
RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
|
||||||
|
ASSERT_TRUE_OR_RETURN(dataSurface, false);
|
||||||
|
|
||||||
|
ASSERT_EQ_OR_RETURN(dataSurface->Stride(), surfaceSize.width * 4, false);
|
||||||
|
|
||||||
|
DataSourceSurface::ScopedMap mapping(dataSurface,
|
||||||
|
DataSourceSurface::MapType::READ);
|
||||||
|
ASSERT_TRUE_OR_RETURN(mapping.IsMapped(), false);
|
||||||
|
|
||||||
|
uint8_t* data = dataSurface->GetData();
|
||||||
|
ASSERT_TRUE_OR_RETURN(data != nullptr, false);
|
||||||
|
|
||||||
|
int32_t rowLength = dataSurface->Stride();
|
||||||
|
for (int32_t col = 0; col < surfaceSize.width; ++col) {
|
||||||
|
int32_t i = aRow * rowLength + col * 4;
|
||||||
|
ASSERT_EQ_OR_RETURN(aPixels[col].mBlue, data[i + 0], false);
|
||||||
|
ASSERT_EQ_OR_RETURN(aPixels[col].mGreen, data[i + 1], false);
|
||||||
|
ASSERT_EQ_OR_RETURN(aPixels[col].mRed, data[i + 2], false);
|
||||||
|
ASSERT_EQ_OR_RETURN(aPixels[col].mAlpha, data[i + 3], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// SurfacePipe Helpers
|
// SurfacePipe Helpers
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#ifndef mozilla_image_test_gtest_Common_h
|
#ifndef mozilla_image_test_gtest_Common_h
|
||||||
#define mozilla_image_test_gtest_Common_h
|
#define mozilla_image_test_gtest_Common_h
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
|
@ -70,6 +72,8 @@ struct ImageTestCase
|
||||||
|
|
||||||
struct BGRAColor
|
struct BGRAColor
|
||||||
{
|
{
|
||||||
|
BGRAColor() : BGRAColor(0, 0, 0, 0) { }
|
||||||
|
|
||||||
BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha)
|
BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha)
|
||||||
: mBlue(aBlue)
|
: mBlue(aBlue)
|
||||||
, mGreen(aGreen)
|
, mGreen(aGreen)
|
||||||
|
@ -79,6 +83,7 @@ struct BGRAColor
|
||||||
|
|
||||||
static BGRAColor Green() { return BGRAColor(0x00, 0xFF, 0x00, 0xFF); }
|
static BGRAColor Green() { return BGRAColor(0x00, 0xFF, 0x00, 0xFF); }
|
||||||
static BGRAColor Red() { return BGRAColor(0x00, 0x00, 0xFF, 0xFF); }
|
static BGRAColor Red() { return BGRAColor(0x00, 0x00, 0xFF, 0xFF); }
|
||||||
|
static BGRAColor Blue() { return BGRAColor(0xFF, 0x00, 0x00, 0xFF); }
|
||||||
static BGRAColor Transparent() { return BGRAColor(0x00, 0x00, 0x00, 0x00); }
|
static BGRAColor Transparent() { return BGRAColor(0x00, 0x00, 0x00, 0x00); }
|
||||||
|
|
||||||
uint32_t AsPixel() const { return gfxPackedPixel(mAlpha, mRed, mGreen, mBlue); }
|
uint32_t AsPixel() const { return gfxPackedPixel(mAlpha, mRed, mGreen, mBlue); }
|
||||||
|
@ -157,6 +162,14 @@ bool PalettedRectIsSolidColor(Decoder* aDecoder,
|
||||||
const gfx::IntRect& aRect,
|
const gfx::IntRect& aRect,
|
||||||
uint8_t aColor);
|
uint8_t aColor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns true if the pixels in @aRow of @aSurface match the pixels given in
|
||||||
|
* @aPixels.
|
||||||
|
*/
|
||||||
|
bool RowHasPixels(gfx::SourceSurface* aSurface,
|
||||||
|
int32_t aRow,
|
||||||
|
const std::vector<BGRAColor>& aPixels);
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// SurfacePipe Helpers
|
// SurfacePipe Helpers
|
||||||
|
|
|
@ -0,0 +1,671 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "mozilla/gfx/2D.h"
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Decoder.h"
|
||||||
|
#include "DecoderFactory.h"
|
||||||
|
#include "SourceBuffer.h"
|
||||||
|
#include "SurfaceFilters.h"
|
||||||
|
#include "SurfacePipe.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::gfx;
|
||||||
|
using namespace mozilla::image;
|
||||||
|
|
||||||
|
using std::generate;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
template <typename Func> void
|
||||||
|
WithADAM7InterpolatingFilter(const IntSize& aSize, Func aFunc)
|
||||||
|
{
|
||||||
|
RefPtr<Decoder> decoder = CreateTrivialDecoder();
|
||||||
|
ASSERT_TRUE(bool(decoder));
|
||||||
|
|
||||||
|
WithFilterPipeline(decoder, Forward<Func>(aFunc),
|
||||||
|
ADAM7InterpolatingConfig { },
|
||||||
|
SurfaceConfig { decoder, 0, aSize,
|
||||||
|
SurfaceFormat::B8G8R8A8, false });
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AssertConfiguringADAM7InterpolatingFilterFails(const IntSize& aSize)
|
||||||
|
{
|
||||||
|
RefPtr<Decoder> decoder = CreateTrivialDecoder();
|
||||||
|
ASSERT_TRUE(bool(decoder));
|
||||||
|
|
||||||
|
AssertConfiguringPipelineFails(decoder,
|
||||||
|
ADAM7InterpolatingConfig { },
|
||||||
|
SurfaceConfig { decoder, 0, aSize,
|
||||||
|
SurfaceFormat::B8G8R8A8, false });
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
InterpolateByte(uint8_t aByteA, uint8_t aByteB, float aWeight)
|
||||||
|
{
|
||||||
|
return uint8_t(aByteA * aWeight + aByteB * (1.0f - aWeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
BGRAColor
|
||||||
|
InterpolateColors(BGRAColor aColor1, BGRAColor aColor2, float aWeight)
|
||||||
|
{
|
||||||
|
return BGRAColor(InterpolateByte(aColor1.mBlue, aColor2.mBlue, aWeight),
|
||||||
|
InterpolateByte(aColor1.mGreen, aColor2.mGreen, aWeight),
|
||||||
|
InterpolateByte(aColor1.mRed, aColor2.mRed, aWeight),
|
||||||
|
InterpolateByte(aColor1.mAlpha, aColor2.mAlpha, aWeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ShouldInterpolate
|
||||||
|
{
|
||||||
|
eYes,
|
||||||
|
eNo
|
||||||
|
};
|
||||||
|
|
||||||
|
BGRAColor
|
||||||
|
HorizontallyInterpolatedPixel(uint32_t aCol,
|
||||||
|
uint32_t aWidth,
|
||||||
|
const vector<float>& aWeights,
|
||||||
|
ShouldInterpolate aShouldInterpolate,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
// We cycle through the vector of weights forever.
|
||||||
|
float weight = aWeights[aCol % aWeights.size()];
|
||||||
|
|
||||||
|
// Find the columns of the two final pixels for this set of weights.
|
||||||
|
uint32_t finalPixel1 = aCol - aCol % aWeights.size();
|
||||||
|
uint32_t finalPixel2 = finalPixel1 + aWeights.size();
|
||||||
|
|
||||||
|
// If |finalPixel2| is past the end of the row, that means that there is no
|
||||||
|
// final pixel after the pixel at |finalPixel1|. In that case, we just want to
|
||||||
|
// duplicate |finalPixel1|'s color until the end of the row. We can do that by
|
||||||
|
// setting |finalPixel2| equal to |finalPixel1| so that the interpolation has
|
||||||
|
// no effect.
|
||||||
|
if (finalPixel2 >= aWidth) {
|
||||||
|
finalPixel2 = finalPixel1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We cycle through the vector of colors forever (subject to the above
|
||||||
|
// constraint about the end of the row).
|
||||||
|
BGRAColor color1 = aColors[finalPixel1 % aColors.size()];
|
||||||
|
BGRAColor color2 = aColors[finalPixel2 % aColors.size()];
|
||||||
|
|
||||||
|
// If we're not interpolating, we treat all pixels which aren't final as
|
||||||
|
// transparent. Since the number of weights we have is equal to the stride
|
||||||
|
// between final pixels, we can check if |aCol| is a final pixel by checking
|
||||||
|
// whether |aCol| is a multiple of |aWeights.size()|.
|
||||||
|
if (aShouldInterpolate == ShouldInterpolate::eNo) {
|
||||||
|
return aCol % aWeights.size() == 0 ? color1
|
||||||
|
: BGRAColor::Transparent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate.
|
||||||
|
return InterpolateColors(color1, color2, weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<float>&
|
||||||
|
InterpolationWeights(int32_t aStride)
|
||||||
|
{
|
||||||
|
// Precalculated interpolation weights. These are used to interpolate
|
||||||
|
// between final pixels or between important rows. Although no interpolation
|
||||||
|
// is actually applied to the previous final pixel or important row value,
|
||||||
|
// the arrays still start with 1.0f, which is always skipped, primarily
|
||||||
|
// because otherwise |stride1Weights| would have zero elements.
|
||||||
|
static vector<float> stride8Weights =
|
||||||
|
{ 1.0f, 7 / 8.0f, 6 / 8.0f, 5 / 8.0f, 4 / 8.0f, 3 / 8.0f, 2 / 8.0f, 1 / 8.0f };
|
||||||
|
static vector<float> stride4Weights = { 1.0f, 3 / 4.0f, 2 / 4.0f, 1 / 4.0f };
|
||||||
|
static vector<float> stride2Weights = { 1.0f, 1 / 2.0f };
|
||||||
|
static vector<float> stride1Weights = { 1.0f };
|
||||||
|
|
||||||
|
switch (aStride) {
|
||||||
|
case 8: return stride8Weights;
|
||||||
|
case 4: return stride4Weights;
|
||||||
|
case 2: return stride2Weights;
|
||||||
|
case 1: return stride1Weights;
|
||||||
|
default:
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
ImportantRowStride(uint8_t aPass)
|
||||||
|
{
|
||||||
|
// The stride between important rows for each pass, with a dummy value for
|
||||||
|
// the nonexistent pass 0 and for pass 8, since the tests run an extra pass to
|
||||||
|
// make sure nothing breaks.
|
||||||
|
static int32_t strides[] = { 1, 8, 8, 4, 4, 2, 2, 1, 1 };
|
||||||
|
|
||||||
|
return strides[aPass];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
FinalPixelStride(uint8_t aPass)
|
||||||
|
{
|
||||||
|
// The stride between the final pixels in important rows for each pass, with
|
||||||
|
// a dummy value for the nonexistent pass 0 and for pass 8, since the tests
|
||||||
|
// run an extra pass to make sure nothing breaks.
|
||||||
|
static size_t strides[] = { 1, 8, 4, 4, 2, 2, 1, 1, 1 };
|
||||||
|
|
||||||
|
return strides[aPass];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsImportantRow(int32_t aRow, uint8_t aPass)
|
||||||
|
{
|
||||||
|
return aRow % ImportantRowStride(aPass) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ADAM7 breaks up the image into 8x8 blocks. On each of the 7 passes, a new
|
||||||
|
* set of pixels in each block receives their final values, according to the
|
||||||
|
* following pattern:
|
||||||
|
*
|
||||||
|
* 1 6 4 6 2 6 4 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
* 5 6 5 6 5 6 5 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
* 3 6 4 6 3 6 4 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
* 5 6 5 6 5 6 5 6
|
||||||
|
* 7 7 7 7 7 7 7 7
|
||||||
|
*
|
||||||
|
* This function produces a row of pixels @aWidth wide, suitable for testing
|
||||||
|
* horizontal interpolation on pass @aPass. The pattern of pixels used is
|
||||||
|
* determined by @aPass and @aRow, which determine which pixels are final
|
||||||
|
* according to the table above, and @aColors, from which the pixel values
|
||||||
|
* are selected.
|
||||||
|
*
|
||||||
|
* There are two different behaviors: if |eNo| is passed for
|
||||||
|
* @aShouldInterpolate, non-final pixels are treated as transparent. If |eNo|
|
||||||
|
* is passed, non-final pixels get interpolated in from the surrounding final
|
||||||
|
* pixels. The intention is that |eNo| is passed to generate input which will
|
||||||
|
* be run through ADAM7InterpolatingFilter, and |eYes| is passed to generate
|
||||||
|
* reference data to check that the filter is performing horizontal
|
||||||
|
* interpolation correctly.
|
||||||
|
*
|
||||||
|
* This function does not perform vertical interpolation. Rows which aren't on
|
||||||
|
* the current pass are filled with transparent pixels.
|
||||||
|
*
|
||||||
|
* @return a vector<BGRAColor> representing a row of pixels.
|
||||||
|
*/
|
||||||
|
vector<BGRAColor>
|
||||||
|
ADAM7HorizontallyInterpolatedRow(uint8_t aPass,
|
||||||
|
uint32_t aRow,
|
||||||
|
uint32_t aWidth,
|
||||||
|
ShouldInterpolate aShouldInterpolate,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
EXPECT_GT(aPass, 0);
|
||||||
|
EXPECT_LE(aPass, 8);
|
||||||
|
EXPECT_GT(aColors.size(), 0u);
|
||||||
|
|
||||||
|
vector<BGRAColor> result(aWidth);
|
||||||
|
|
||||||
|
if (IsImportantRow(aRow, aPass)) {
|
||||||
|
vector<float>& weights = InterpolationWeights(FinalPixelStride(aPass));
|
||||||
|
|
||||||
|
// Compute the horizontally interpolated row.
|
||||||
|
uint32_t col = 0;
|
||||||
|
generate(result.begin(), result.end(), [&]{
|
||||||
|
return HorizontallyInterpolatedPixel(col++, aWidth, weights,
|
||||||
|
aShouldInterpolate, aColors);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// This is an unimportant row; just make the entire thing transparent.
|
||||||
|
generate(result.begin(), result.end(), []{
|
||||||
|
return BGRAColor::Transparent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(result.size(), size_t(aWidth));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteState
|
||||||
|
WriteUninterpolatedPixels(SurfaceFilter* aFilter,
|
||||||
|
const IntSize& aSize,
|
||||||
|
uint8_t aPass,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
WriteState result = WriteState::NEED_MORE_DATA;
|
||||||
|
|
||||||
|
for (int32_t row = 0; row < aSize.height; ++row) {
|
||||||
|
// Compute uninterpolated pixels for this row.
|
||||||
|
vector<BGRAColor> pixels =
|
||||||
|
Move(ADAM7HorizontallyInterpolatedRow(aPass, row, aSize.width,
|
||||||
|
ShouldInterpolate::eNo, aColors));
|
||||||
|
|
||||||
|
// Write them to the surface.
|
||||||
|
auto pixelIterator = pixels.cbegin();
|
||||||
|
result = aFilter->WritePixelsToRow<uint32_t>([&]{
|
||||||
|
return AsVariant((*pixelIterator++).AsPixel());
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result != WriteState::NEED_MORE_DATA) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CheckHorizontallyInterpolatedImage(Decoder* aDecoder,
|
||||||
|
const IntSize& aSize,
|
||||||
|
uint8_t aPass,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
|
||||||
|
RefPtr<SourceSurface> surface = currentFrame->GetSurface();
|
||||||
|
|
||||||
|
for (int32_t row = 0; row < aSize.height; ++row) {
|
||||||
|
if (!IsImportantRow(row, aPass)) {
|
||||||
|
continue; // Don't check rows which aren't important on this pass.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the expected pixels, *with* interpolation to match what the
|
||||||
|
// filter should have done.
|
||||||
|
vector<BGRAColor> expectedPixels =
|
||||||
|
Move(ADAM7HorizontallyInterpolatedRow(aPass, row, aSize.width,
|
||||||
|
ShouldInterpolate::eYes, aColors));
|
||||||
|
|
||||||
|
if (!RowHasPixels(surface, row, expectedPixels)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CheckHorizontalInterpolation(const IntSize& aSize,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
const IntRect surfaceRect(IntPoint(0, 0), aSize);
|
||||||
|
|
||||||
|
WithADAM7InterpolatingFilter(aSize,
|
||||||
|
[&](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||||
|
// We check horizontal interpolation behavior for each pass individually. In
|
||||||
|
// addition to the normal 7 passes that ADAM7 includes, we also check an
|
||||||
|
// eighth pass to verify that nothing breaks if extra data is written.
|
||||||
|
for (uint8_t pass = 1; pass <= 8; ++pass) {
|
||||||
|
// Write our color pattern to the surface. We don't perform any
|
||||||
|
// interpolation when writing to the filter so that we can check that the
|
||||||
|
// filter itself *does*.
|
||||||
|
WriteState result =
|
||||||
|
WriteUninterpolatedPixels(aFilter, aSize, pass, aColors);
|
||||||
|
|
||||||
|
EXPECT_EQ(WriteState::FINISHED, result);
|
||||||
|
AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
|
||||||
|
|
||||||
|
// Check that the generated image matches the expected pattern, with
|
||||||
|
// interpolation applied.
|
||||||
|
EXPECT_TRUE(CheckHorizontallyInterpolatedImage(aDecoder, aSize,
|
||||||
|
pass, aColors));
|
||||||
|
|
||||||
|
// Prepare for the next pass.
|
||||||
|
aFilter->ResetToFirstRow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
BGRAColor
|
||||||
|
ADAM7RowColor(int32_t aRow,
|
||||||
|
uint8_t aPass,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
EXPECT_LT(0, aPass);
|
||||||
|
EXPECT_GE(8, aPass);
|
||||||
|
EXPECT_LT(0u, aColors.size());
|
||||||
|
|
||||||
|
// If this is an important row, select the color from the provided vector of
|
||||||
|
// colors, which we cycle through infinitely. If not, just fill the row with
|
||||||
|
// transparent pixels.
|
||||||
|
return IsImportantRow(aRow, aPass) ? aColors[aRow % aColors.size()]
|
||||||
|
: BGRAColor::Transparent();
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteState
|
||||||
|
WriteRowColorPixels(SurfaceFilter* aFilter,
|
||||||
|
const IntSize& aSize,
|
||||||
|
uint8_t aPass,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
WriteState result = WriteState::NEED_MORE_DATA;
|
||||||
|
|
||||||
|
for (int32_t row = 0; row < aSize.height; ++row) {
|
||||||
|
const uint32_t color = ADAM7RowColor(row, aPass, aColors).AsPixel();
|
||||||
|
|
||||||
|
// Fill the surface with |color| pixels.
|
||||||
|
result = aFilter->WritePixelsToRow<uint32_t>([&]{ return AsVariant(color); });
|
||||||
|
|
||||||
|
if (result != WriteState::NEED_MORE_DATA) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CheckVerticallyInterpolatedImage(Decoder* aDecoder,
|
||||||
|
const IntSize& aSize,
|
||||||
|
uint8_t aPass,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
vector<float>& weights = InterpolationWeights(ImportantRowStride(aPass));
|
||||||
|
|
||||||
|
for (int32_t row = 0; row < aSize.height; ++row) {
|
||||||
|
// Vertically interpolation takes place between two important rows. The
|
||||||
|
// separation between the important rows is determined by the stride of this
|
||||||
|
// pass. When there is no "next" important row because we'd run off the
|
||||||
|
// bottom of the image, we use the same row for both. This matches
|
||||||
|
// ADAM7InterpolatingFilter's behavior of duplicating the last important row
|
||||||
|
// since there isn't another important row to vertically interpolate it
|
||||||
|
// with.
|
||||||
|
const int32_t stride = ImportantRowStride(aPass);
|
||||||
|
const int32_t prevImportantRow = row - row % stride;
|
||||||
|
const int32_t maybeNextImportantRow = prevImportantRow + stride;
|
||||||
|
const int32_t nextImportantRow = maybeNextImportantRow < aSize.height
|
||||||
|
? maybeNextImportantRow
|
||||||
|
: prevImportantRow;
|
||||||
|
|
||||||
|
// Retrieve the colors for the important rows we're going to interpolate.
|
||||||
|
const BGRAColor prevImportantRowColor =
|
||||||
|
ADAM7RowColor(prevImportantRow, aPass, aColors);
|
||||||
|
const BGRAColor nextImportantRowColor =
|
||||||
|
ADAM7RowColor(nextImportantRow, aPass, aColors);
|
||||||
|
|
||||||
|
// The weight we'll use for interpolation is also determined by the stride.
|
||||||
|
// A row halfway between two important rows should have pixels that have a
|
||||||
|
// 50% contribution from each of the important rows, for example.
|
||||||
|
const float weight = weights[row % stride];
|
||||||
|
const BGRAColor interpolatedColor =
|
||||||
|
InterpolateColors(prevImportantRowColor, nextImportantRowColor, weight);
|
||||||
|
|
||||||
|
// Generate a row of expected pixels. Every pixel in the row is always the
|
||||||
|
// same color since we're only testing vertical interpolation between
|
||||||
|
// solid-colored rows.
|
||||||
|
vector<BGRAColor> expectedPixels(aSize.width);
|
||||||
|
generate(expectedPixels.begin(), expectedPixels.end(), [&]{
|
||||||
|
return interpolatedColor;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the pixels match.
|
||||||
|
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
|
||||||
|
RefPtr<SourceSurface> surface = currentFrame->GetSurface();
|
||||||
|
if (!RowHasPixels(surface, row, expectedPixels)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CheckVerticalInterpolation(const IntSize& aSize,
|
||||||
|
const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
const IntRect surfaceRect(IntPoint(0, 0), aSize);
|
||||||
|
|
||||||
|
WithADAM7InterpolatingFilter(aSize,
|
||||||
|
[&](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||||
|
for (uint8_t pass = 1; pass <= 8; ++pass) {
|
||||||
|
// Write a pattern of rows to the surface. Important rows will receive a
|
||||||
|
// color selected from |aColors|; unimportant rows will be transparent.
|
||||||
|
WriteState result = WriteRowColorPixels(aFilter, aSize, pass, aColors);
|
||||||
|
|
||||||
|
EXPECT_EQ(WriteState::FINISHED, result);
|
||||||
|
AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
|
||||||
|
|
||||||
|
// Check that the generated image matches the expected pattern, with
|
||||||
|
// interpolation applied.
|
||||||
|
EXPECT_TRUE(CheckVerticallyInterpolatedImage(aDecoder, aSize,
|
||||||
|
pass, aColors));
|
||||||
|
|
||||||
|
// Prepare for the next pass.
|
||||||
|
aFilter->ResetToFirstRow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CheckInterpolation(const IntSize& aSize, const vector<BGRAColor>& aColors)
|
||||||
|
{
|
||||||
|
CheckHorizontalInterpolation(aSize, aColors);
|
||||||
|
CheckVerticalInterpolation(aSize, aColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CheckADAM7InterpolatingWritePixels(const IntSize& aSize)
|
||||||
|
{
|
||||||
|
// This test writes 8 passes of green pixels (the seven ADAM7 passes, plus one
|
||||||
|
// extra to make sure nothing goes wrong if we write too much input) and verifies
|
||||||
|
// that the output is a solid green surface each time. Because all the pixels
|
||||||
|
// are the same color, interpolation doesn't matter; we test the correctness
|
||||||
|
// of the interpolation algorithm itself separately.
|
||||||
|
WithADAM7InterpolatingFilter(aSize,
|
||||||
|
[&](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||||
|
IntRect rect(IntPoint(0, 0), aSize);
|
||||||
|
|
||||||
|
for (int32_t pass = 1; pass <= 8; ++pass) {
|
||||||
|
// We only actually write up to the last important row for each pass,
|
||||||
|
// because that row unambiguously determines the remaining rows.
|
||||||
|
const int32_t lastRow = aSize.height - 1;
|
||||||
|
const int32_t lastImportantRow =
|
||||||
|
lastRow - (lastRow % ImportantRowStride(pass));
|
||||||
|
const IntRect inputWriteRect(0, 0, aSize.width, lastImportantRow + 1);
|
||||||
|
|
||||||
|
CheckWritePixels(aDecoder, aFilter,
|
||||||
|
/* aOutputRect = */ Some(rect),
|
||||||
|
/* aInputRect = */ Some(rect),
|
||||||
|
/* aInputWriteRect = */ Some(inputWriteRect));
|
||||||
|
|
||||||
|
aFilter->ResetToFirstRow();
|
||||||
|
EXPECT_FALSE(aFilter->IsSurfaceFinished());
|
||||||
|
Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
|
||||||
|
EXPECT_TRUE(invalidRect.isNothing());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels100_100)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels99_99)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(99, 99));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels66_33)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(66, 33));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels33_66)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(33, 66));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels15_15)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(15, 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels9_9)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(9, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels8_8)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(8, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels7_7)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(7, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels3_3)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(3, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, WritePixels1_1)
|
||||||
|
{
|
||||||
|
CheckADAM7InterpolatingWritePixels(IntSize(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, TrivialInterpolation48_48)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(48, 48), { BGRAColor::Green() });
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput33_17)
|
||||||
|
{
|
||||||
|
// We check interpolation using irregular patterns to make sure that the
|
||||||
|
// interpolation will look different for different passes.
|
||||||
|
CheckInterpolation(IntSize(33, 17), {
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput32_16)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(32, 16), {
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput31_15)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(31, 15), {
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput17_33)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(17, 33), {
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput16_32)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(16, 32), {
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput15_31)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(15, 31), {
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
|
||||||
|
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput9_9)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(9, 9), {
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput8_8)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(8, 8), {
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput7_7)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(7, 7), {
|
||||||
|
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput3_3)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(3, 3), {
|
||||||
|
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Red()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput1_1)
|
||||||
|
{
|
||||||
|
CheckInterpolation(IntSize(1, 1), { BGRAColor::Blue() });
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsFor0_0)
|
||||||
|
{
|
||||||
|
// A 0x0 input size is invalid, so configuration should fail.
|
||||||
|
AssertConfiguringADAM7InterpolatingFilterFails(IntSize(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsForMinus1_Minus1)
|
||||||
|
{
|
||||||
|
// A negative input size is invalid, so configuration should fail.
|
||||||
|
AssertConfiguringADAM7InterpolatingFilterFails(IntSize(-1, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ImageADAM7InterpolatingFilter, ConfiguringPalettedADAM7InterpolatingFilterFails)
|
||||||
|
{
|
||||||
|
RefPtr<Decoder> decoder = CreateTrivialDecoder();
|
||||||
|
ASSERT_TRUE(decoder != nullptr);
|
||||||
|
|
||||||
|
// ADAM7InterpolatingFilter does not support paletted images, so configuration
|
||||||
|
// should fail.
|
||||||
|
AssertConfiguringPipelineFails(decoder,
|
||||||
|
ADAM7InterpolatingConfig { },
|
||||||
|
PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
|
||||||
|
IntRect(0, 0, 50, 50),
|
||||||
|
SurfaceFormat::B8G8R8A8, 8,
|
||||||
|
false });
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ Library('imagetest')
|
||||||
|
|
||||||
UNIFIED_SOURCES = [
|
UNIFIED_SOURCES = [
|
||||||
'Common.cpp',
|
'Common.cpp',
|
||||||
|
'TestADAM7InterpolatingFilter.cpp',
|
||||||
'TestCopyOnWrite.cpp',
|
'TestCopyOnWrite.cpp',
|
||||||
'TestDecoders.cpp',
|
'TestDecoders.cpp',
|
||||||
'TestDecodeToSurface.cpp',
|
'TestDecodeToSurface.cpp',
|
||||||
|
|
|
@ -81,8 +81,21 @@ assertEq(Function.prototype[Symbol.hasInstance].call(doubleBound, instance), tru
|
||||||
assertEq(Function.prototype[Symbol.hasInstance].call(tripleBound, instance), true);
|
assertEq(Function.prototype[Symbol.hasInstance].call(tripleBound, instance), true);
|
||||||
|
|
||||||
// Function.prototype[Symbol.hasInstance] is not configurable
|
// Function.prototype[Symbol.hasInstance] is not configurable
|
||||||
let desc = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance)
|
let desc = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance);
|
||||||
assertEq(desc.configurable, false)
|
assertEq(desc.configurable, false);
|
||||||
|
|
||||||
|
// Attempting to use a non-callable @@hasInstance triggers a type error
|
||||||
|
// Bug 1280892
|
||||||
|
assertThrowsInstanceOf(() => {
|
||||||
|
var fun = function() {}
|
||||||
|
var p = new Proxy(fun, {
|
||||||
|
get(target, key) {
|
||||||
|
return /not-callable/;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fun instanceof p;
|
||||||
|
}, TypeError);
|
||||||
|
|
||||||
|
|
||||||
if (typeof reportCompare === "function")
|
if (typeof reportCompare === "function")
|
||||||
reportCompare(true, true);
|
reportCompare(true, true);
|
||||||
|
|
|
@ -725,7 +725,7 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, MutableHandleValue v, bo
|
||||||
|
|
||||||
if (!hasInstance.isNullOrUndefined()) {
|
if (!hasInstance.isNullOrUndefined()) {
|
||||||
if (!IsCallable(hasInstance))
|
if (!IsCallable(hasInstance))
|
||||||
ReportIsNotFunction(cx, hasInstance);
|
return ReportIsNotFunction(cx, hasInstance);
|
||||||
|
|
||||||
/* Step 3. */
|
/* Step 3. */
|
||||||
RootedValue rval(cx);
|
RootedValue rval(cx);
|
||||||
|
@ -738,8 +738,7 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, MutableHandleValue v, bo
|
||||||
/* Step 4. */
|
/* Step 4. */
|
||||||
if (!obj->isCallable()) {
|
if (!obj->isCallable()) {
|
||||||
RootedValue val(cx, ObjectValue(*obj));
|
RootedValue val(cx, ObjectValue(*obj));
|
||||||
ReportIsNotFunction(cx, val);
|
return ReportIsNotFunction(cx, val);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 5. */
|
/* Step 5. */
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html style="transform: translateX(3px); display: grid;">
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
user_pref("layout.event-regions.enabled", true);
|
||||||
|
-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="position: absolute;">Z</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -473,3 +473,4 @@ load 1234622-1.html
|
||||||
load 1235467-1.html
|
load 1235467-1.html
|
||||||
pref(dom.webcomponents.enabled,true) load 1261351.html
|
pref(dom.webcomponents.enabled,true) load 1261351.html
|
||||||
load 1270797-1.html
|
load 1270797-1.html
|
||||||
|
load 1278455-1.html
|
||||||
|
|
|
@ -2496,14 +2496,14 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
||||||
// Make sure to start any background image loads for the root element now.
|
// Make sure to start any background image loads for the root element now.
|
||||||
styleContext->StartBackgroundImageLoads();
|
styleContext->StartBackgroundImageLoads();
|
||||||
|
|
||||||
nsFrameConstructorSaveState absoluteSaveState;
|
nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
|
||||||
if (mHasRootAbsPosContainingBlock) {
|
if (mHasRootAbsPosContainingBlock) {
|
||||||
// Push the absolute containing block now so we can absolutely position
|
// Push the absolute containing block now so we can absolutely position
|
||||||
// the root element
|
// the root element
|
||||||
mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
|
mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
|
||||||
state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
|
state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
|
||||||
mDocElementContainingBlock,
|
mDocElementContainingBlock,
|
||||||
absoluteSaveState);
|
docElementContainingBlockAbsoluteSaveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The rules from CSS 2.1, section 9.2.4, have already been applied
|
// The rules from CSS 2.1, section 9.2.4, have already been applied
|
||||||
|
@ -2520,6 +2520,8 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
||||||
nsIFrame* newFrame;
|
nsIFrame* newFrame;
|
||||||
bool processChildren = false;
|
bool processChildren = false;
|
||||||
|
|
||||||
|
nsFrameConstructorSaveState absoluteSaveState;
|
||||||
|
|
||||||
// Check whether we need to build a XUL box or SVG root frame
|
// Check whether we need to build a XUL box or SVG root frame
|
||||||
#ifdef MOZ_XUL
|
#ifdef MOZ_XUL
|
||||||
if (aDocElement->IsXULElement()) {
|
if (aDocElement->IsXULElement()) {
|
||||||
|
@ -2565,12 +2567,26 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
||||||
contentFrame);
|
contentFrame);
|
||||||
newFrame = contentFrame;
|
newFrame = contentFrame;
|
||||||
processChildren = true;
|
processChildren = true;
|
||||||
|
|
||||||
|
newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
|
||||||
|
if (display->IsAbsPosContainingBlock(newFrame)) {
|
||||||
|
state.PushAbsoluteContainingBlock(contentFrame, newFrame,
|
||||||
|
absoluteSaveState);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (display->mDisplay == NS_STYLE_DISPLAY_GRID) {
|
} else if (display->mDisplay == NS_STYLE_DISPLAY_GRID) {
|
||||||
contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext);
|
contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext);
|
||||||
InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
|
InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
|
||||||
contentFrame);
|
contentFrame);
|
||||||
newFrame = contentFrame;
|
newFrame = contentFrame;
|
||||||
processChildren = true;
|
processChildren = true;
|
||||||
|
|
||||||
|
newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
|
||||||
|
if (display->IsAbsPosContainingBlock(newFrame)) {
|
||||||
|
state.PushAbsoluteContainingBlock(contentFrame, newFrame,
|
||||||
|
absoluteSaveState);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (display->mDisplay == NS_STYLE_DISPLAY_TABLE) {
|
} else if (display->mDisplay == NS_STYLE_DISPLAY_TABLE) {
|
||||||
// We're going to call the right function ourselves, so no need to give a
|
// We're going to call the right function ourselves, so no need to give a
|
||||||
// function to this FrameConstructionData.
|
// function to this FrameConstructionData.
|
||||||
|
|
|
@ -71,10 +71,12 @@ TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument,
|
||||||
if (aProperty == eCSSProperty_mask_image) {
|
if (aProperty == eCSSProperty_mask_image) {
|
||||||
nsIURI* docURI = aDocument->GetDocumentURI();
|
nsIURI* docURI = aDocument->GetDocumentURI();
|
||||||
nsIURI* imageURI = aValue.GetURLValue();
|
nsIURI* imageURI = aValue.GetURLValue();
|
||||||
bool isEqualExceptRef = false;
|
if (imageURI) {
|
||||||
nsresult rv = imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
|
bool isEqualExceptRef = false;
|
||||||
if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
|
nsresult rv = imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
|
||||||
return;
|
if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,6 +9,12 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<div id="target-div">
|
||||||
|
<svg>
|
||||||
|
<rect id="svg-rect" width="100%" height="100%" fill="lime"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -60,16 +66,10 @@ function waitForPaintFlushed() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTestElement() {
|
SimpleTest.waitForExplicitFinish();
|
||||||
var div = document.createElement("div");
|
|
||||||
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
||||||
div.appendChild(svg);
|
|
||||||
|
|
||||||
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
add_task(function* smil_is_in_display_none_subtree() {
|
||||||
rect.setAttribute("width", "100%");
|
yield waitForPaintFlushed();
|
||||||
rect.setAttribute("height", "100%");
|
|
||||||
rect.setAttribute("fill", "lime");
|
|
||||||
svg.appendChild(rect);
|
|
||||||
|
|
||||||
var animate =
|
var animate =
|
||||||
document.createElementNS("http://www.w3.org/2000/svg", "animate");
|
document.createElementNS("http://www.w3.org/2000/svg", "animate");
|
||||||
|
@ -78,21 +78,15 @@ function addTestElement() {
|
||||||
animate.setAttribute("values", "red;lime");
|
animate.setAttribute("values", "red;lime");
|
||||||
animate.setAttribute("dur", "1s");
|
animate.setAttribute("dur", "1s");
|
||||||
animate.setAttribute("repeatCount", "indefinite");
|
animate.setAttribute("repeatCount", "indefinite");
|
||||||
rect.appendChild(animate);
|
document.getElementById("svg-rect").appendChild(animate);
|
||||||
|
|
||||||
document.body.appendChild(div);
|
|
||||||
return div;
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
|
|
||||||
add_task(function* smil_is_in_display_none_subtree() {
|
|
||||||
var div = addTestElement();
|
|
||||||
yield waitForPaintFlushed();
|
yield waitForPaintFlushed();
|
||||||
|
|
||||||
var displayMarkers = yield observeStyling(5);
|
var displayMarkers = yield observeStyling(5);
|
||||||
is(displayMarkers.length, 5, "should restyle in every frame");
|
is(displayMarkers.length, 5, "should restyle in every frame");
|
||||||
|
|
||||||
|
var div = document.getElementById("target-div");
|
||||||
|
|
||||||
div.style.display = "none";
|
div.style.display = "none";
|
||||||
getComputedStyle(div).display;
|
getComputedStyle(div).display;
|
||||||
var displayNoneMarkers = yield observeStyling(5);
|
var displayNoneMarkers = yield observeStyling(5);
|
||||||
|
@ -103,7 +97,7 @@ add_task(function* smil_is_in_display_none_subtree() {
|
||||||
var displayAgainMarkers = yield observeStyling(5);
|
var displayAgainMarkers = yield observeStyling(5);
|
||||||
is(displayAgainMarkers.length, 5, "should restyle again");
|
is(displayAgainMarkers.length, 5, "should restyle again");
|
||||||
|
|
||||||
yield ensureElementRemoval(div);
|
yield ensureElementRemoval(animate);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -5,13 +5,13 @@ This change comes from the blink repo https://codereview.appspot.com/229430043/
|
||||||
diff --git jdhuff.c jdhuff.c
|
diff --git jdhuff.c jdhuff.c
|
||||||
--- jdhuff.c
|
--- jdhuff.c
|
||||||
+++ jdhuff.c
|
+++ jdhuff.c
|
||||||
@@ -661,34 +661,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
|
@@ -664,17 +664,17 @@ decode_mcu_fast (j_decompress_ptr cinfo,
|
||||||
ASSIGN_STATE(state, entropy->saved);
|
ASSIGN_STATE(state, entropy->saved);
|
||||||
|
|
||||||
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||||
JBLOCKROW block = MCU_data[blkn];
|
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
|
||||||
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
|
d_derived_tbl *dctbl = entropy->dc_cur_tbls[blkn];
|
||||||
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
|
d_derived_tbl *actbl = entropy->ac_cur_tbls[blkn];
|
||||||
register int s, k, r, l;
|
register int s, k, r, l;
|
||||||
|
|
||||||
- HUFF_DECODE_FAST(s, l, dctbl);
|
- HUFF_DECODE_FAST(s, l, dctbl);
|
||||||
|
@ -24,12 +24,13 @@ diff --git jdhuff.c jdhuff.c
|
||||||
|
|
||||||
if (entropy->dc_needed[blkn]) {
|
if (entropy->dc_needed[blkn]) {
|
||||||
int ci = cinfo->MCU_membership[blkn];
|
int ci = cinfo->MCU_membership[blkn];
|
||||||
s += state.last_dc_val[ci];
|
@@ -682,17 +682,17 @@ decode_mcu_fast (j_decompress_ptr cinfo,
|
||||||
state.last_dc_val[ci] = s;
|
state.last_dc_val[ci] = s;
|
||||||
(*block)[0] = (JCOEF) s;
|
if (block)
|
||||||
|
(*block)[0] = (JCOEF) s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entropy->ac_needed[blkn]) {
|
if (entropy->ac_needed[blkn] && block) {
|
||||||
|
|
||||||
for (k = 1; k < DCTSIZE2; k++) {
|
for (k = 1; k < DCTSIZE2; k++) {
|
||||||
- HUFF_DECODE_FAST(s, l, actbl);
|
- HUFF_DECODE_FAST(s, l, actbl);
|
||||||
|
@ -42,7 +43,7 @@ diff --git jdhuff.c jdhuff.c
|
||||||
FILL_BIT_BUFFER_FAST
|
FILL_BIT_BUFFER_FAST
|
||||||
r = GET_BITS(s);
|
r = GET_BITS(s);
|
||||||
s = HUFF_EXTEND(r, s);
|
s = HUFF_EXTEND(r, s);
|
||||||
@@ -697,33 +697,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
|
@@ -701,33 +701,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
|
||||||
if (r != 15) break;
|
if (r != 15) break;
|
||||||
k += 15;
|
k += 15;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +82,7 @@ diff --git jdhuff.c jdhuff.c
|
||||||
diff --git jdhuff.h jdhuff.h
|
diff --git jdhuff.h jdhuff.h
|
||||||
--- jdhuff.h
|
--- jdhuff.h
|
||||||
+++ jdhuff.h
|
+++ jdhuff.h
|
||||||
@@ -200,32 +200,34 @@ EXTERN(boolean) jpeg_fill_bit_buffer
|
@@ -203,32 +203,34 @@ EXTERN(boolean) jpeg_fill_bit_buffer
|
||||||
} else { \
|
} else { \
|
||||||
slowlabel: \
|
slowlabel: \
|
||||||
if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
|
if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
|
||||||
|
@ -116,5 +117,5 @@ diff --git jdhuff.h jdhuff.h
|
||||||
|
|
||||||
/* Out-of-line case for Huffman code fetching */
|
/* Out-of-line case for Huffman code fetching */
|
||||||
EXTERN(int) jpeg_huff_decode
|
EXTERN(int) jpeg_huff_decode
|
||||||
(bitread_working_state * state, register bit_buf_type get_buffer,
|
(bitread_working_state *state, register bit_buf_type get_buffer,
|
||||||
register int bits_left, d_derived_tbl * htbl, int min_bits);
|
register int bits_left, d_derived_tbl *htbl, int min_bits);
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
libjpeg-turbo Licenses
|
||||||
|
======================
|
||||||
|
|
||||||
|
libjpeg-turbo is covered by three compatible BSD-style open source licenses:
|
||||||
|
|
||||||
|
- The IJG (Independent JPEG Group) License, which is listed in
|
||||||
|
[README.ijg](README.ijg)
|
||||||
|
|
||||||
|
This license applies to the libjpeg API library and associated programs
|
||||||
|
(any code inherited from libjpeg, and any modifications to that code.)
|
||||||
|
|
||||||
|
- The Modified (3-clause) BSD License, which is listed in
|
||||||
|
[turbojpeg.c](turbojpeg.c)
|
||||||
|
|
||||||
|
This license covers the TurboJPEG API library and associated programs.
|
||||||
|
|
||||||
|
- The zlib License, which is listed in [simd/jsimdext.inc](simd/jsimdext.inc)
|
||||||
|
|
||||||
|
This license is a subset of the other two, and it covers the libjpeg-turbo
|
||||||
|
SIMD extensions.
|
||||||
|
|
||||||
|
|
||||||
|
Complying with the libjpeg-turbo Licenses
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
This section provides a roll-up of the libjpeg-turbo licensing terms, to the
|
||||||
|
best of our understanding.
|
||||||
|
|
||||||
|
1. If you are distributing a modified version of the libjpeg-turbo source,
|
||||||
|
then:
|
||||||
|
|
||||||
|
1. You cannot alter or remove any existing copyright or license notices
|
||||||
|
from the source.
|
||||||
|
|
||||||
|
**Origin**
|
||||||
|
- Clause 1 of the IJG License
|
||||||
|
- Clause 1 of the Modified BSD License
|
||||||
|
- Clauses 1 and 3 of the zlib License
|
||||||
|
|
||||||
|
2. You must add your own copyright notice to the header of each source
|
||||||
|
file you modified, so others can tell that you modified that file (if
|
||||||
|
there is not an existing copyright header in that file, then you can
|
||||||
|
simply add a notice stating that you modified the file.)
|
||||||
|
|
||||||
|
**Origin**
|
||||||
|
- Clause 1 of the IJG License
|
||||||
|
- Clause 2 of the zlib License
|
||||||
|
|
||||||
|
3. You must include the IJG README file, and you must not alter any of the
|
||||||
|
copyright or license text in that file.
|
||||||
|
|
||||||
|
**Origin**
|
||||||
|
- Clause 1 of the IJG License
|
||||||
|
|
||||||
|
2. If you are distributing only libjpeg-turbo binaries without the source, or
|
||||||
|
if you are distributing an application that statically links with
|
||||||
|
libjpeg-turbo, then:
|
||||||
|
|
||||||
|
1. Your product documentation must include a message stating:
|
||||||
|
|
||||||
|
This software is based in part on the work of the Independent JPEG
|
||||||
|
Group.
|
||||||
|
|
||||||
|
**Origin**
|
||||||
|
- Clause 2 of the IJG license
|
||||||
|
|
||||||
|
2. If your binary distribution includes or uses the TurboJPEG API, then
|
||||||
|
your product documentation must include the text of the Modified BSD
|
||||||
|
License.
|
||||||
|
|
||||||
|
**Origin**
|
||||||
|
- Clause 2 of the Modified BSD License
|
||||||
|
|
||||||
|
3. You cannot use the name of the IJG or The libjpeg-turbo Project or the
|
||||||
|
contributors thereof in advertising, publicity, etc.
|
||||||
|
|
||||||
|
**Origin**
|
||||||
|
- IJG License
|
||||||
|
- Clause 3 of the Modified BSD License
|
||||||
|
|
||||||
|
4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be
|
||||||
|
free of defects, nor do we accept any liability for undesirable
|
||||||
|
consequences resulting from your use of the software.
|
||||||
|
|
||||||
|
**Origin**
|
||||||
|
- IJG License
|
||||||
|
- Modified BSD License
|
||||||
|
- zlib License
|
|
@ -24,13 +24,13 @@ To upgrade to a new revision of libjpeg-turbo, do the following:
|
||||||
|
|
||||||
You can easily look for all non *.c, *.h, *.asm, and *.inc files by running
|
You can easily look for all non *.c, *.h, *.asm, and *.inc files by running
|
||||||
|
|
||||||
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\)$'
|
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\|md\|ijg\)$'
|
||||||
|
|
||||||
Once you're comfortable that you're only deleting files you want to delete
|
Once you're comfortable that you're only deleting files you want to delete
|
||||||
(and you've hg add'ed the files you want to keep), you can nuke the remaining
|
(and you've hg add'ed the files you want to keep), you can nuke the remaining
|
||||||
files with
|
files with
|
||||||
|
|
||||||
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\)$' | xargs rm
|
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\|md\|ijg\)$' | xargs rm
|
||||||
|
|
||||||
A helpful command for finding the *.c files which aren't *currently* part of
|
A helpful command for finding the *.c files which aren't *currently* part of
|
||||||
the build is
|
the build is
|
||||||
|
@ -48,6 +48,10 @@ To upgrade to a new revision of libjpeg-turbo, do the following:
|
||||||
|
|
||||||
$ hg addremove
|
$ hg addremove
|
||||||
|
|
||||||
|
== June 23, 2016 (libjpeg-turbo v1.5.0 3ff13e651bbe6de9c6f15d05235d1d4f26f63ffc 2016-05-31) ==
|
||||||
|
|
||||||
|
* Updated to v1.5.0 release.
|
||||||
|
|
||||||
== October 5, 2015 (libjpeg-turbo v1.4.2 d8da49effe6460d55239c4c009c57f42d8e4a494 2015-09-21) ==
|
== October 5, 2015 (libjpeg-turbo v1.4.2 d8da49effe6460d55239c4c009c57f42d8e4a494 2015-09-21) ==
|
||||||
|
|
||||||
* Updated to v1.4.2 release.
|
* Updated to v1.4.2 release.
|
||||||
|
|
|
@ -1,339 +0,0 @@
|
||||||
*******************************************************************************
|
|
||||||
** Background
|
|
||||||
*******************************************************************************
|
|
||||||
|
|
||||||
libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
|
|
||||||
NEON) to accelerate baseline JPEG compression and decompression on x86, x86-64,
|
|
||||||
and ARM systems. On such systems, libjpeg-turbo is generally 2-4x as fast as
|
|
||||||
libjpeg, all else being equal. On other types of systems, libjpeg-turbo can
|
|
||||||
still outperform libjpeg by a significant amount, by virtue of its
|
|
||||||
highly-optimized Huffman coding routines. In many cases, the performance of
|
|
||||||
libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
|
|
||||||
|
|
||||||
libjpeg-turbo implements both the traditional libjpeg API as well as the less
|
|
||||||
powerful but more straightforward TurboJPEG API. libjpeg-turbo also features
|
|
||||||
colorspace extensions that allow it to compress from/decompress to 32-bit and
|
|
||||||
big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java
|
|
||||||
interface.
|
|
||||||
|
|
||||||
libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated
|
|
||||||
derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and
|
|
||||||
VirtualGL projects made numerous enhancements to the codec in 2009, and in
|
|
||||||
early 2010, libjpeg-turbo spun off into an independent project, with the goal
|
|
||||||
of making high-speed JPEG compression/decompression technology available to a
|
|
||||||
broader range of users and developers.
|
|
||||||
|
|
||||||
|
|
||||||
*******************************************************************************
|
|
||||||
** License
|
|
||||||
*******************************************************************************
|
|
||||||
|
|
||||||
libjpeg-turbo is covered by three compatible BSD-style open source licenses.
|
|
||||||
Refer to LICENSE.txt for a roll-up of license terms.
|
|
||||||
|
|
||||||
|
|
||||||
*******************************************************************************
|
|
||||||
** Using libjpeg-turbo
|
|
||||||
*******************************************************************************
|
|
||||||
|
|
||||||
libjpeg-turbo includes two APIs that can be used to compress and decompress
|
|
||||||
JPEG images:
|
|
||||||
|
|
||||||
TurboJPEG API: This API provides an easy-to-use interface for compressing
|
|
||||||
and decompressing JPEG images in memory. It also provides some functionality
|
|
||||||
that would not be straightforward to achieve using the underlying libjpeg
|
|
||||||
API, such as generating planar YUV images and performing multiple
|
|
||||||
simultaneous lossless transforms on an image. The Java interface for
|
|
||||||
libjpeg-turbo is written on top of the TurboJPEG API.
|
|
||||||
|
|
||||||
libjpeg API: This is the de facto industry-standard API for compressing and
|
|
||||||
decompressing JPEG images. It is more difficult to use than the TurboJPEG
|
|
||||||
API but also more powerful. The libjpeg API implementation in libjpeg-turbo
|
|
||||||
is both API/ABI-compatible and mathematically compatible with libjpeg v6b.
|
|
||||||
It can also optionally be configured to be API/ABI-compatible with libjpeg v7
|
|
||||||
and v8 (see below.)
|
|
||||||
|
|
||||||
There is no significant performance advantage to either API when both are used
|
|
||||||
to perform similar operations.
|
|
||||||
|
|
||||||
=====================
|
|
||||||
Colorspace Extensions
|
|
||||||
=====================
|
|
||||||
|
|
||||||
libjpeg-turbo includes extensions that allow JPEG images to be compressed
|
|
||||||
directly from (and decompressed directly to) buffers that use BGR, BGRX,
|
|
||||||
RGBX, XBGR, and XRGB pixel ordering. This is implemented with ten new
|
|
||||||
colorspace constants:
|
|
||||||
|
|
||||||
JCS_EXT_RGB /* red/green/blue */
|
|
||||||
JCS_EXT_RGBX /* red/green/blue/x */
|
|
||||||
JCS_EXT_BGR /* blue/green/red */
|
|
||||||
JCS_EXT_BGRX /* blue/green/red/x */
|
|
||||||
JCS_EXT_XBGR /* x/blue/green/red */
|
|
||||||
JCS_EXT_XRGB /* x/red/green/blue */
|
|
||||||
JCS_EXT_RGBA /* red/green/blue/alpha */
|
|
||||||
JCS_EXT_BGRA /* blue/green/red/alpha */
|
|
||||||
JCS_EXT_ABGR /* alpha/blue/green/red */
|
|
||||||
JCS_EXT_ARGB /* alpha/red/green/blue */
|
|
||||||
|
|
||||||
Setting cinfo.in_color_space (compression) or cinfo.out_color_space
|
|
||||||
(decompression) to one of these values will cause libjpeg-turbo to read the
|
|
||||||
red, green, and blue values from (or write them to) the appropriate position in
|
|
||||||
the pixel when compressing from/decompressing to an RGB buffer.
|
|
||||||
|
|
||||||
Your application can check for the existence of these extensions at compile
|
|
||||||
time with:
|
|
||||||
|
|
||||||
#ifdef JCS_EXTENSIONS
|
|
||||||
|
|
||||||
At run time, attempting to use these extensions with a libjpeg implementation
|
|
||||||
that does not support them will result in a "Bogus input colorspace" error.
|
|
||||||
Applications can trap this error in order to test whether run-time support is
|
|
||||||
available for the colorspace extensions.
|
|
||||||
|
|
||||||
When using the RGBX, BGRX, XBGR, and XRGB colorspaces during decompression, the
|
|
||||||
X byte is undefined, and in order to ensure the best performance, libjpeg-turbo
|
|
||||||
can set that byte to whatever value it wishes. If an application expects the X
|
|
||||||
byte to be used as an alpha channel, then it should specify JCS_EXT_RGBA,
|
|
||||||
JCS_EXT_BGRA, JCS_EXT_ABGR, or JCS_EXT_ARGB. When these colorspace constants
|
|
||||||
are used, the X byte is guaranteed to be 0xFF, which is interpreted as opaque.
|
|
||||||
|
|
||||||
Your application can check for the existence of the alpha channel colorspace
|
|
||||||
extensions at compile time with:
|
|
||||||
|
|
||||||
#ifdef JCS_ALPHA_EXTENSIONS
|
|
||||||
|
|
||||||
jcstest.c, located in the libjpeg-turbo source tree, demonstrates how to check
|
|
||||||
for the existence of the colorspace extensions at compile time and run time.
|
|
||||||
|
|
||||||
===================================
|
|
||||||
libjpeg v7 and v8 API/ABI Emulation
|
|
||||||
===================================
|
|
||||||
|
|
||||||
With libjpeg v7 and v8, new features were added that necessitated extending the
|
|
||||||
compression and decompression structures. Unfortunately, due to the exposed
|
|
||||||
nature of those structures, extending them also necessitated breaking backward
|
|
||||||
ABI compatibility with previous libjpeg releases. Thus, programs that were
|
|
||||||
built to use libjpeg v7 or v8 did not work with libjpeg-turbo, since it is
|
|
||||||
based on the libjpeg v6b code base. Although libjpeg v7 and v8 are not
|
|
||||||
as widely used as v6b, enough programs (including a few Linux distros) made
|
|
||||||
the switch that there was a demand to emulate the libjpeg v7 and v8 ABIs
|
|
||||||
in libjpeg-turbo. It should be noted, however, that this feature was added
|
|
||||||
primarily so that applications that had already been compiled to use libjpeg
|
|
||||||
v7+ could take advantage of accelerated baseline JPEG encoding/decoding
|
|
||||||
without recompiling. libjpeg-turbo does not claim to support all of the
|
|
||||||
libjpeg v7+ features, nor to produce identical output to libjpeg v7+ in all
|
|
||||||
cases (see below.)
|
|
||||||
|
|
||||||
By passing an argument of --with-jpeg7 or --with-jpeg8 to configure, or an
|
|
||||||
argument of -DWITH_JPEG7=1 or -DWITH_JPEG8=1 to cmake, you can build a version
|
|
||||||
of libjpeg-turbo that emulates the libjpeg v7 or v8 ABI, so that programs
|
|
||||||
that are built against libjpeg v7 or v8 can be run with libjpeg-turbo. The
|
|
||||||
following section describes which libjpeg v7+ features are supported and which
|
|
||||||
aren't.
|
|
||||||
|
|
||||||
Support for libjpeg v7 and v8 Features:
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
Fully supported:
|
|
||||||
|
|
||||||
-- libjpeg: IDCT scaling extensions in decompressor
|
|
||||||
libjpeg-turbo supports IDCT scaling with scaling factors of 1/8, 1/4, 3/8,
|
|
||||||
1/2, 5/8, 3/4, 7/8, 9/8, 5/4, 11/8, 3/2, 13/8, 7/4, 15/8, and 2/1 (only 1/4
|
|
||||||
and 1/2 are SIMD-accelerated.)
|
|
||||||
|
|
||||||
-- libjpeg: arithmetic coding
|
|
||||||
|
|
||||||
-- libjpeg: In-memory source and destination managers
|
|
||||||
See notes below.
|
|
||||||
|
|
||||||
-- cjpeg: Separate quality settings for luminance and chrominance
|
|
||||||
Note that the libpjeg v7+ API was extended to accommodate this feature only
|
|
||||||
for convenience purposes. It has always been possible to implement this
|
|
||||||
feature with libjpeg v6b (see rdswitch.c for an example.)
|
|
||||||
|
|
||||||
-- cjpeg: 32-bit BMP support
|
|
||||||
|
|
||||||
-- cjpeg: -rgb option
|
|
||||||
|
|
||||||
-- jpegtran: lossless cropping
|
|
||||||
|
|
||||||
-- jpegtran: -perfect option
|
|
||||||
|
|
||||||
-- jpegtran: forcing width/height when performing lossless crop
|
|
||||||
|
|
||||||
-- rdjpgcom: -raw option
|
|
||||||
|
|
||||||
-- rdjpgcom: locale awareness
|
|
||||||
|
|
||||||
|
|
||||||
Not supported:
|
|
||||||
|
|
||||||
NOTE: As of this writing, extensive research has been conducted into the
|
|
||||||
usefulness of DCT scaling as a means of data reduction and SmartScale as a
|
|
||||||
means of quality improvement. The reader is invited to peruse the research at
|
|
||||||
http://www.libjpeg-turbo.org/About/SmartScale and draw his/her own conclusions,
|
|
||||||
but it is the general belief of our project that these features have not
|
|
||||||
demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo.
|
|
||||||
|
|
||||||
-- libjpeg: DCT scaling in compressor
|
|
||||||
cinfo.scale_num and cinfo.scale_denom are silently ignored.
|
|
||||||
There is no technical reason why DCT scaling could not be supported when
|
|
||||||
emulating the libjpeg v7+ API/ABI, but without the SmartScale extension (see
|
|
||||||
below), only scaling factors of 1/2, 8/15, 4/7, 8/13, 2/3, 8/11, 4/5, and
|
|
||||||
8/9 would be available, which is of limited usefulness.
|
|
||||||
|
|
||||||
-- libjpeg: SmartScale
|
|
||||||
cinfo.block_size is silently ignored.
|
|
||||||
SmartScale is an extension to the JPEG format that allows for DCT block
|
|
||||||
sizes other than 8x8. Providing support for this new format would be
|
|
||||||
feasible (particularly without full acceleration.) However, until/unless
|
|
||||||
the format becomes either an official industry standard or, at minimum, an
|
|
||||||
accepted solution in the community, we are hesitant to implement it, as
|
|
||||||
there is no sense of whether or how it might change in the future. It is
|
|
||||||
our belief that SmartScale has not demonstrated sufficient usefulness as a
|
|
||||||
lossless format nor as a means of quality enhancement, and thus, our primary
|
|
||||||
interest in providing this feature would be as a means of supporting
|
|
||||||
additional DCT scaling factors.
|
|
||||||
|
|
||||||
-- libjpeg: Fancy downsampling in compressor
|
|
||||||
cinfo.do_fancy_downsampling is silently ignored.
|
|
||||||
This requires the DCT scaling feature, which is not supported.
|
|
||||||
|
|
||||||
-- jpegtran: Scaling
|
|
||||||
This requires both the DCT scaling and SmartScale features, which are not
|
|
||||||
supported.
|
|
||||||
|
|
||||||
-- Lossless RGB JPEG files
|
|
||||||
This requires the SmartScale feature, which is not supported.
|
|
||||||
|
|
||||||
What About libjpeg v9?
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
libjpeg v9 introduced yet another field to the JPEG compression structure
|
|
||||||
(color_transform), thus making the ABI backward incompatible with that of
|
|
||||||
libjpeg v8. This new field was introduced solely for the purpose of supporting
|
|
||||||
lossless SmartScale encoding. Further, there was actually no reason to extend
|
|
||||||
the API in this manner, as the color transform could have just as easily been
|
|
||||||
activated by way of a new JPEG colorspace constant, thus preserving backward
|
|
||||||
ABI compatibility.
|
|
||||||
|
|
||||||
Our research (see link above) has shown that lossless SmartScale does not
|
|
||||||
generally accomplish anything that can't already be accomplished better with
|
|
||||||
existing, standard lossless formats. Thus, at this time, it is our belief that
|
|
||||||
there is not sufficient technical justification for software to upgrade from
|
|
||||||
libjpeg v8 to libjpeg v9, and therefore, not sufficient technical justification
|
|
||||||
for us to emulate the libjpeg v9 ABI.
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
In-Memory Source/Destination Managers
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
By default, libjpeg-turbo 1.3 and later includes the jpeg_mem_src() and
|
|
||||||
jpeg_mem_dest() functions, even when not emulating the libjpeg v8 API/ABI.
|
|
||||||
Previously, it was necessary to build libjpeg-turbo from source with libjpeg v8
|
|
||||||
API/ABI emulation in order to use the in-memory source/destination managers,
|
|
||||||
but several projects requested that those functions be included when emulating
|
|
||||||
the libjpeg v6b API/ABI as well. This allows the use of those functions by
|
|
||||||
programs that need them without breaking ABI compatibility for programs that
|
|
||||||
don't, and it allows those functions to be provided in the "official"
|
|
||||||
libjpeg-turbo binaries.
|
|
||||||
|
|
||||||
Those who are concerned about maintaining strict conformance with the libjpeg
|
|
||||||
v6b or v7 API can pass an argument of --without-mem-srcdst to configure or
|
|
||||||
an argument of -DWITH_MEM_SRCDST=0 to CMake prior to building libjpeg-turbo.
|
|
||||||
This will restore the pre-1.3 behavior, in which jpeg_mem_src() and
|
|
||||||
jpeg_mem_dest() are only included when emulating the libjpeg v8 API/ABI.
|
|
||||||
|
|
||||||
On Un*x systems, including the in-memory source/destination managers changes
|
|
||||||
the dynamic library version from 62.0.0 to 62.1.0 if using libjpeg v6b API/ABI
|
|
||||||
emulation and from 7.0.0 to 7.1.0 if using libjpeg v7 API/ABI emulation.
|
|
||||||
|
|
||||||
Note that, on most Un*x systems, the dynamic linker will not look for a
|
|
||||||
function in a library until that function is actually used. Thus, if a program
|
|
||||||
is built against libjpeg-turbo 1.3+ and uses jpeg_mem_src() or jpeg_mem_dest(),
|
|
||||||
that program will not fail if run against an older version of libjpeg-turbo or
|
|
||||||
against libjpeg v7- until the program actually tries to call jpeg_mem_src() or
|
|
||||||
jpeg_mem_dest(). Such is not the case on Windows. If a program is built
|
|
||||||
against the libjpeg-turbo 1.3+ DLL and uses jpeg_mem_src() or jpeg_mem_dest(),
|
|
||||||
then it must use the libjpeg-turbo 1.3+ DLL at run time.
|
|
||||||
|
|
||||||
Both cjpeg and djpeg have been extended to allow testing the in-memory
|
|
||||||
source/destination manager functions. See their respective man pages for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
|
|
||||||
*******************************************************************************
|
|
||||||
** Mathematical Compatibility
|
|
||||||
*******************************************************************************
|
|
||||||
|
|
||||||
For the most part, libjpeg-turbo should produce identical output to libjpeg
|
|
||||||
v6b. The one exception to this is when using the floating point DCT/IDCT, in
|
|
||||||
which case the outputs of libjpeg v6b and libjpeg-turbo can differ for the
|
|
||||||
following reasons:
|
|
||||||
|
|
||||||
-- The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever so
|
|
||||||
slightly more accurate than the implementation in libjpeg v6b, but not by
|
|
||||||
any amount perceptible to human vision (generally in the range of 0.01 to
|
|
||||||
0.08 dB gain in PNSR.)
|
|
||||||
-- When not using the SIMD extensions, libjpeg-turbo uses the more accurate
|
|
||||||
(and slightly faster) floating point IDCT algorithm introduced in libjpeg
|
|
||||||
v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
|
|
||||||
however, that this algorithm basically brings the accuracy of the floating
|
|
||||||
point IDCT in line with the accuracy of the slow integer IDCT. The floating
|
|
||||||
point DCT/IDCT algorithms are mainly a legacy feature, and they do not
|
|
||||||
produce significantly more accuracy than the slow integer algorithms (to put
|
|
||||||
numbers on this, the typical difference in PNSR between the two algorithms
|
|
||||||
is less than 0.10 dB, whereas changing the quality level by 1 in the upper
|
|
||||||
range of the quality scale is typically more like a 1.0 dB difference.)
|
|
||||||
-- If the floating point algorithms in libjpeg-turbo are not implemented using
|
|
||||||
SIMD instructions on a particular platform, then the accuracy of the
|
|
||||||
floating point DCT/IDCT can depend on the compiler settings.
|
|
||||||
|
|
||||||
While libjpeg-turbo does emulate the libjpeg v8 API/ABI, under the hood, it is
|
|
||||||
still using the same algorithms as libjpeg v6b, so there are several specific
|
|
||||||
cases in which libjpeg-turbo cannot be expected to produce the same output as
|
|
||||||
libjpeg v8:
|
|
||||||
|
|
||||||
-- When decompressing using scaling factors of 1/2 and 1/4, because libjpeg v8
|
|
||||||
implements those scaling algorithms differently than libjpeg v6b does, and
|
|
||||||
libjpeg-turbo's SIMD extensions are based on the libjpeg v6b behavior.
|
|
||||||
|
|
||||||
-- When using chrominance subsampling, because libjpeg v8 implements this
|
|
||||||
with its DCT/IDCT scaling algorithms rather than with a separate
|
|
||||||
downsampling/upsampling algorithm. In our testing, the subsampled/upsampled
|
|
||||||
output of libjpeg v8 is less accurate than that of libjpeg v6b for this
|
|
||||||
reason.
|
|
||||||
|
|
||||||
-- When decompressing using a scaling factor > 1 and merged (AKA "non-fancy" or
|
|
||||||
"non-smooth") chrominance upsampling, because libjpeg v8 does not support
|
|
||||||
merged upsampling with scaling factors > 1.
|
|
||||||
|
|
||||||
|
|
||||||
*******************************************************************************
|
|
||||||
** Performance Pitfalls
|
|
||||||
*******************************************************************************
|
|
||||||
|
|
||||||
===============
|
|
||||||
Restart Markers
|
|
||||||
===============
|
|
||||||
|
|
||||||
The optimized Huffman decoder in libjpeg-turbo does not handle restart markers
|
|
||||||
in a way that makes the rest of the libjpeg infrastructure happy, so it is
|
|
||||||
necessary to use the slow Huffman decoder when decompressing a JPEG image that
|
|
||||||
has restart markers. This can cause the decompression performance to drop by
|
|
||||||
as much as 20%, but the performance will still be much greater than that of
|
|
||||||
libjpeg. Many consumer packages, such as PhotoShop, use restart markers when
|
|
||||||
generating JPEG images, so images generated by those programs will experience
|
|
||||||
this issue.
|
|
||||||
|
|
||||||
===============================================
|
|
||||||
Fast Integer Forward DCT at High Quality Levels
|
|
||||||
===============================================
|
|
||||||
|
|
||||||
The algorithm used by the SIMD-accelerated quantization function cannot produce
|
|
||||||
correct results whenever the fast integer forward DCT is used along with a JPEG
|
|
||||||
quality of 98-100. Thus, libjpeg-turbo must use the non-SIMD quantization
|
|
||||||
function in those cases. This causes performance to drop by as much as 40%.
|
|
||||||
It is therefore strongly advised that you use the slow integer forward DCT
|
|
||||||
whenever encoding images with a JPEG quality of 98 or higher.
|
|
|
@ -1,7 +1,7 @@
|
||||||
libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project
|
libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project
|
||||||
to include only information relevant to libjpeg-turbo, to wordsmith certain
|
to include only information relevant to libjpeg-turbo, to wordsmith certain
|
||||||
sections, and to remove impolitic language that existed in the libjpeg v8
|
sections, and to remove impolitic language that existed in the libjpeg v8
|
||||||
README. It is included only for reference. Please see README-turbo.txt for
|
README. It is included only for reference. Please see README.md for
|
||||||
information specific to libjpeg-turbo.
|
information specific to libjpeg-turbo.
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ with respect to this software, its quality, accuracy, merchantability, or
|
||||||
fitness for a particular purpose. This software is provided "AS IS", and you,
|
fitness for a particular purpose. This software is provided "AS IS", and you,
|
||||||
its user, assume the entire risk as to its quality and accuracy.
|
its user, assume the entire risk as to its quality and accuracy.
|
||||||
|
|
||||||
This software is copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
|
This software is copyright (C) 1991-2016, Thomas G. Lane, Guido Vollbeding.
|
||||||
All Rights Reserved except as specified below.
|
All Rights Reserved except as specified below.
|
||||||
|
|
||||||
Permission is hereby granted to use, copy, modify, and distribute this
|
Permission is hereby granted to use, copy, modify, and distribute this
|
||||||
|
@ -166,11 +166,11 @@ ltmain.sh). Another support script, install-sh, is copyright by X Consortium
|
||||||
but is also freely distributable.
|
but is also freely distributable.
|
||||||
|
|
||||||
The IJG distribution formerly included code to read and write GIF files.
|
The IJG distribution formerly included code to read and write GIF files.
|
||||||
To avoid entanglement with the Unisys LZW patent, GIF reading support has
|
To avoid entanglement with the Unisys LZW patent (now expired), GIF reading
|
||||||
been removed altogether, and the GIF writer has been simplified to produce
|
support has been removed altogether, and the GIF writer has been simplified
|
||||||
"uncompressed GIFs". This technique does not use the LZW algorithm; the
|
to produce "uncompressed GIFs". This technique does not use the LZW
|
||||||
resulting GIF files are larger than usual, but are readable by all standard
|
algorithm; the resulting GIF files are larger than usual, but are readable
|
||||||
GIF decoders.
|
by all standard GIF decoders.
|
||||||
|
|
||||||
We are required to state that
|
We are required to state that
|
||||||
"The Graphics Interchange Format(c) is the Copyright property of
|
"The Graphics Interchange Format(c) is the Copyright property of
|
||||||
|
@ -189,8 +189,8 @@ The best short technical introduction to the JPEG compression algorithm is
|
||||||
Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
|
Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
|
||||||
(Adjacent articles in that issue discuss MPEG motion picture compression,
|
(Adjacent articles in that issue discuss MPEG motion picture compression,
|
||||||
applications of JPEG, and related topics.) If you don't have the CACM issue
|
applications of JPEG, and related topics.) If you don't have the CACM issue
|
||||||
handy, a PostScript file containing a revised version of Wallace's article is
|
handy, a PDF file containing a revised version of Wallace's article is
|
||||||
available at http://www.ijg.org/files/wallace.ps.gz. The file (actually
|
available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually
|
||||||
a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
|
a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
|
||||||
omits the sample images that appeared in CACM, but it includes corrections
|
omits the sample images that appeared in CACM, but it includes corrections
|
||||||
and some added material. Note: the Wallace article is copyright ACM and IEEE,
|
and some added material. Note: the Wallace article is copyright ACM and IEEE,
|
||||||
|
@ -246,9 +246,7 @@ ARCHIVE LOCATIONS
|
||||||
|
|
||||||
The "official" archive site for this software is www.ijg.org.
|
The "official" archive site for this software is www.ijg.org.
|
||||||
The most recent released version can always be found there in
|
The most recent released version can always be found there in
|
||||||
directory "files". This particular version will be archived as
|
directory "files".
|
||||||
http://www.ijg.org/files/jpegsrc.v8d.tar.gz, and in Windows-compatible
|
|
||||||
"zip" archive format as http://www.ijg.org/files/jpegsr8d.zip.
|
|
||||||
|
|
||||||
The JPEG FAQ (Frequently Asked Questions) article is a source of some
|
The JPEG FAQ (Frequently Asked Questions) article is a source of some
|
||||||
general information about JPEG.
|
general information about JPEG.
|
|
@ -0,0 +1,341 @@
|
||||||
|
Background
|
||||||
|
==========
|
||||||
|
|
||||||
|
libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
|
||||||
|
NEON, AltiVec) to accelerate baseline JPEG compression and decompression on
|
||||||
|
x86, x86-64, ARM, and PowerPC systems. On such systems, libjpeg-turbo is
|
||||||
|
generally 2-6x as fast as libjpeg, all else being equal. On other types of
|
||||||
|
systems, libjpeg-turbo can still outperform libjpeg by a significant amount, by
|
||||||
|
virtue of its highly-optimized Huffman coding routines. In many cases, the
|
||||||
|
performance of libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
|
||||||
|
|
||||||
|
libjpeg-turbo implements both the traditional libjpeg API as well as the less
|
||||||
|
powerful but more straightforward TurboJPEG API. libjpeg-turbo also features
|
||||||
|
colorspace extensions that allow it to compress from/decompress to 32-bit and
|
||||||
|
big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java
|
||||||
|
interface.
|
||||||
|
|
||||||
|
libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated
|
||||||
|
derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and
|
||||||
|
VirtualGL projects made numerous enhancements to the codec in 2009, and in
|
||||||
|
early 2010, libjpeg-turbo spun off into an independent project, with the goal
|
||||||
|
of making high-speed JPEG compression/decompression technology available to a
|
||||||
|
broader range of users and developers.
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
=======
|
||||||
|
|
||||||
|
libjpeg-turbo is covered by three compatible BSD-style open source licenses.
|
||||||
|
Refer to [LICENSE.md](LICENSE.md) for a roll-up of license terms.
|
||||||
|
|
||||||
|
|
||||||
|
Building libjpeg-turbo
|
||||||
|
======================
|
||||||
|
|
||||||
|
Refer to [BUILDING.md](BUILDING.md) for complete instructions.
|
||||||
|
|
||||||
|
|
||||||
|
Using libjpeg-turbo
|
||||||
|
===================
|
||||||
|
|
||||||
|
libjpeg-turbo includes two APIs that can be used to compress and decompress
|
||||||
|
JPEG images:
|
||||||
|
|
||||||
|
- **TurboJPEG API**
|
||||||
|
This API provides an easy-to-use interface for compressing and decompressing
|
||||||
|
JPEG images in memory. It also provides some functionality that would not be
|
||||||
|
straightforward to achieve using the underlying libjpeg API, such as
|
||||||
|
generating planar YUV images and performing multiple simultaneous lossless
|
||||||
|
transforms on an image. The Java interface for libjpeg-turbo is written on
|
||||||
|
top of the TurboJPEG API.
|
||||||
|
|
||||||
|
- **libjpeg API**
|
||||||
|
This is the de facto industry-standard API for compressing and decompressing
|
||||||
|
JPEG images. It is more difficult to use than the TurboJPEG API but also
|
||||||
|
more powerful. The libjpeg API implementation in libjpeg-turbo is both
|
||||||
|
API/ABI-compatible and mathematically compatible with libjpeg v6b. It can
|
||||||
|
also optionally be configured to be API/ABI-compatible with libjpeg v7 and v8
|
||||||
|
(see below.)
|
||||||
|
|
||||||
|
There is no significant performance advantage to either API when both are used
|
||||||
|
to perform similar operations.
|
||||||
|
|
||||||
|
Colorspace Extensions
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
libjpeg-turbo includes extensions that allow JPEG images to be compressed
|
||||||
|
directly from (and decompressed directly to) buffers that use BGR, BGRX,
|
||||||
|
RGBX, XBGR, and XRGB pixel ordering. This is implemented with ten new
|
||||||
|
colorspace constants:
|
||||||
|
|
||||||
|
JCS_EXT_RGB /* red/green/blue */
|
||||||
|
JCS_EXT_RGBX /* red/green/blue/x */
|
||||||
|
JCS_EXT_BGR /* blue/green/red */
|
||||||
|
JCS_EXT_BGRX /* blue/green/red/x */
|
||||||
|
JCS_EXT_XBGR /* x/blue/green/red */
|
||||||
|
JCS_EXT_XRGB /* x/red/green/blue */
|
||||||
|
JCS_EXT_RGBA /* red/green/blue/alpha */
|
||||||
|
JCS_EXT_BGRA /* blue/green/red/alpha */
|
||||||
|
JCS_EXT_ABGR /* alpha/blue/green/red */
|
||||||
|
JCS_EXT_ARGB /* alpha/red/green/blue */
|
||||||
|
|
||||||
|
Setting `cinfo.in_color_space` (compression) or `cinfo.out_color_space`
|
||||||
|
(decompression) to one of these values will cause libjpeg-turbo to read the
|
||||||
|
red, green, and blue values from (or write them to) the appropriate position in
|
||||||
|
the pixel when compressing from/decompressing to an RGB buffer.
|
||||||
|
|
||||||
|
Your application can check for the existence of these extensions at compile
|
||||||
|
time with:
|
||||||
|
|
||||||
|
#ifdef JCS_EXTENSIONS
|
||||||
|
|
||||||
|
At run time, attempting to use these extensions with a libjpeg implementation
|
||||||
|
that does not support them will result in a "Bogus input colorspace" error.
|
||||||
|
Applications can trap this error in order to test whether run-time support is
|
||||||
|
available for the colorspace extensions.
|
||||||
|
|
||||||
|
When using the RGBX, BGRX, XBGR, and XRGB colorspaces during decompression, the
|
||||||
|
X byte is undefined, and in order to ensure the best performance, libjpeg-turbo
|
||||||
|
can set that byte to whatever value it wishes. If an application expects the X
|
||||||
|
byte to be used as an alpha channel, then it should specify `JCS_EXT_RGBA`,
|
||||||
|
`JCS_EXT_BGRA`, `JCS_EXT_ABGR`, or `JCS_EXT_ARGB`. When these colorspace
|
||||||
|
constants are used, the X byte is guaranteed to be 0xFF, which is interpreted
|
||||||
|
as opaque.
|
||||||
|
|
||||||
|
Your application can check for the existence of the alpha channel colorspace
|
||||||
|
extensions at compile time with:
|
||||||
|
|
||||||
|
#ifdef JCS_ALPHA_EXTENSIONS
|
||||||
|
|
||||||
|
[jcstest.c](jcstest.c), located in the libjpeg-turbo source tree, demonstrates
|
||||||
|
how to check for the existence of the colorspace extensions at compile time and
|
||||||
|
run time.
|
||||||
|
|
||||||
|
libjpeg v7 and v8 API/ABI Emulation
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
With libjpeg v7 and v8, new features were added that necessitated extending the
|
||||||
|
compression and decompression structures. Unfortunately, due to the exposed
|
||||||
|
nature of those structures, extending them also necessitated breaking backward
|
||||||
|
ABI compatibility with previous libjpeg releases. Thus, programs that were
|
||||||
|
built to use libjpeg v7 or v8 did not work with libjpeg-turbo, since it is
|
||||||
|
based on the libjpeg v6b code base. Although libjpeg v7 and v8 are not
|
||||||
|
as widely used as v6b, enough programs (including a few Linux distros) made
|
||||||
|
the switch that there was a demand to emulate the libjpeg v7 and v8 ABIs
|
||||||
|
in libjpeg-turbo. It should be noted, however, that this feature was added
|
||||||
|
primarily so that applications that had already been compiled to use libjpeg
|
||||||
|
v7+ could take advantage of accelerated baseline JPEG encoding/decoding
|
||||||
|
without recompiling. libjpeg-turbo does not claim to support all of the
|
||||||
|
libjpeg v7+ features, nor to produce identical output to libjpeg v7+ in all
|
||||||
|
cases (see below.)
|
||||||
|
|
||||||
|
By passing an argument of `--with-jpeg7` or `--with-jpeg8` to `configure`, or
|
||||||
|
an argument of `-DWITH_JPEG7=1` or `-DWITH_JPEG8=1` to `cmake`, you can build a
|
||||||
|
version of libjpeg-turbo that emulates the libjpeg v7 or v8 ABI, so that
|
||||||
|
programs that are built against libjpeg v7 or v8 can be run with libjpeg-turbo.
|
||||||
|
The following section describes which libjpeg v7+ features are supported and
|
||||||
|
which aren't.
|
||||||
|
|
||||||
|
### Support for libjpeg v7 and v8 Features
|
||||||
|
|
||||||
|
#### Fully supported
|
||||||
|
|
||||||
|
- **libjpeg: IDCT scaling extensions in decompressor**
|
||||||
|
libjpeg-turbo supports IDCT scaling with scaling factors of 1/8, 1/4, 3/8,
|
||||||
|
1/2, 5/8, 3/4, 7/8, 9/8, 5/4, 11/8, 3/2, 13/8, 7/4, 15/8, and 2/1 (only 1/4
|
||||||
|
and 1/2 are SIMD-accelerated.)
|
||||||
|
|
||||||
|
- **libjpeg: Arithmetic coding**
|
||||||
|
|
||||||
|
- **libjpeg: In-memory source and destination managers**
|
||||||
|
See notes below.
|
||||||
|
|
||||||
|
- **cjpeg: Separate quality settings for luminance and chrominance**
|
||||||
|
Note that the libpjeg v7+ API was extended to accommodate this feature only
|
||||||
|
for convenience purposes. It has always been possible to implement this
|
||||||
|
feature with libjpeg v6b (see rdswitch.c for an example.)
|
||||||
|
|
||||||
|
- **cjpeg: 32-bit BMP support**
|
||||||
|
|
||||||
|
- **cjpeg: `-rgb` option**
|
||||||
|
|
||||||
|
- **jpegtran: Lossless cropping**
|
||||||
|
|
||||||
|
- **jpegtran: `-perfect` option**
|
||||||
|
|
||||||
|
- **jpegtran: Forcing width/height when performing lossless crop**
|
||||||
|
|
||||||
|
- **rdjpgcom: `-raw` option**
|
||||||
|
|
||||||
|
- **rdjpgcom: Locale awareness**
|
||||||
|
|
||||||
|
|
||||||
|
#### Not supported
|
||||||
|
|
||||||
|
NOTE: As of this writing, extensive research has been conducted into the
|
||||||
|
usefulness of DCT scaling as a means of data reduction and SmartScale as a
|
||||||
|
means of quality improvement. The reader is invited to peruse the research at
|
||||||
|
<http://www.libjpeg-turbo.org/About/SmartScale> and draw his/her own conclusions,
|
||||||
|
but it is the general belief of our project that these features have not
|
||||||
|
demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo.
|
||||||
|
|
||||||
|
- **libjpeg: DCT scaling in compressor**
|
||||||
|
`cinfo.scale_num` and `cinfo.scale_denom` are silently ignored.
|
||||||
|
There is no technical reason why DCT scaling could not be supported when
|
||||||
|
emulating the libjpeg v7+ API/ABI, but without the SmartScale extension (see
|
||||||
|
below), only scaling factors of 1/2, 8/15, 4/7, 8/13, 2/3, 8/11, 4/5, and
|
||||||
|
8/9 would be available, which is of limited usefulness.
|
||||||
|
|
||||||
|
- **libjpeg: SmartScale**
|
||||||
|
`cinfo.block_size` is silently ignored.
|
||||||
|
SmartScale is an extension to the JPEG format that allows for DCT block
|
||||||
|
sizes other than 8x8. Providing support for this new format would be
|
||||||
|
feasible (particularly without full acceleration.) However, until/unless
|
||||||
|
the format becomes either an official industry standard or, at minimum, an
|
||||||
|
accepted solution in the community, we are hesitant to implement it, as
|
||||||
|
there is no sense of whether or how it might change in the future. It is
|
||||||
|
our belief that SmartScale has not demonstrated sufficient usefulness as a
|
||||||
|
lossless format nor as a means of quality enhancement, and thus our primary
|
||||||
|
interest in providing this feature would be as a means of supporting
|
||||||
|
additional DCT scaling factors.
|
||||||
|
|
||||||
|
- **libjpeg: Fancy downsampling in compressor**
|
||||||
|
`cinfo.do_fancy_downsampling` is silently ignored.
|
||||||
|
This requires the DCT scaling feature, which is not supported.
|
||||||
|
|
||||||
|
- **jpegtran: Scaling**
|
||||||
|
This requires both the DCT scaling and SmartScale features, which are not
|
||||||
|
supported.
|
||||||
|
|
||||||
|
- **Lossless RGB JPEG files**
|
||||||
|
This requires the SmartScale feature, which is not supported.
|
||||||
|
|
||||||
|
### What About libjpeg v9?
|
||||||
|
|
||||||
|
libjpeg v9 introduced yet another field to the JPEG compression structure
|
||||||
|
(`color_transform`), thus making the ABI backward incompatible with that of
|
||||||
|
libjpeg v8. This new field was introduced solely for the purpose of supporting
|
||||||
|
lossless SmartScale encoding. Furthermore, there was actually no reason to
|
||||||
|
extend the API in this manner, as the color transform could have just as easily
|
||||||
|
been activated by way of a new JPEG colorspace constant, thus preserving
|
||||||
|
backward ABI compatibility.
|
||||||
|
|
||||||
|
Our research (see link above) has shown that lossless SmartScale does not
|
||||||
|
generally accomplish anything that can't already be accomplished better with
|
||||||
|
existing, standard lossless formats. Therefore, at this time it is our belief
|
||||||
|
that there is not sufficient technical justification for software projects to
|
||||||
|
upgrade from libjpeg v8 to libjpeg v9, and thus there is not sufficient
|
||||||
|
echnical justification for us to emulate the libjpeg v9 ABI.
|
||||||
|
|
||||||
|
In-Memory Source/Destination Managers
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
By default, libjpeg-turbo 1.3 and later includes the `jpeg_mem_src()` and
|
||||||
|
`jpeg_mem_dest()` functions, even when not emulating the libjpeg v8 API/ABI.
|
||||||
|
Previously, it was necessary to build libjpeg-turbo from source with libjpeg v8
|
||||||
|
API/ABI emulation in order to use the in-memory source/destination managers,
|
||||||
|
but several projects requested that those functions be included when emulating
|
||||||
|
the libjpeg v6b API/ABI as well. This allows the use of those functions by
|
||||||
|
programs that need them, without breaking ABI compatibility for programs that
|
||||||
|
don't, and it allows those functions to be provided in the "official"
|
||||||
|
libjpeg-turbo binaries.
|
||||||
|
|
||||||
|
Those who are concerned about maintaining strict conformance with the libjpeg
|
||||||
|
v6b or v7 API can pass an argument of `--without-mem-srcdst` to `configure` or
|
||||||
|
an argument of `-DWITH_MEM_SRCDST=0` to `cmake` prior to building
|
||||||
|
libjpeg-turbo. This will restore the pre-1.3 behavior, in which
|
||||||
|
`jpeg_mem_src()` and `jpeg_mem_dest()` are only included when emulating the
|
||||||
|
libjpeg v8 API/ABI.
|
||||||
|
|
||||||
|
On Un*x systems, including the in-memory source/destination managers changes
|
||||||
|
the dynamic library version from 62.0.0 to 62.1.0 if using libjpeg v6b API/ABI
|
||||||
|
emulation and from 7.0.0 to 7.1.0 if using libjpeg v7 API/ABI emulation.
|
||||||
|
|
||||||
|
Note that, on most Un*x systems, the dynamic linker will not look for a
|
||||||
|
function in a library until that function is actually used. Thus, if a program
|
||||||
|
is built against libjpeg-turbo 1.3+ and uses `jpeg_mem_src()` or
|
||||||
|
`jpeg_mem_dest()`, that program will not fail if run against an older version
|
||||||
|
of libjpeg-turbo or against libjpeg v7- until the program actually tries to
|
||||||
|
call `jpeg_mem_src()` or `jpeg_mem_dest()`. Such is not the case on Windows.
|
||||||
|
If a program is built against the libjpeg-turbo 1.3+ DLL and uses
|
||||||
|
`jpeg_mem_src()` or `jpeg_mem_dest()`, then it must use the libjpeg-turbo 1.3+
|
||||||
|
DLL at run time.
|
||||||
|
|
||||||
|
Both cjpeg and djpeg have been extended to allow testing the in-memory
|
||||||
|
source/destination manager functions. See their respective man pages for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
|
||||||
|
Mathematical Compatibility
|
||||||
|
==========================
|
||||||
|
|
||||||
|
For the most part, libjpeg-turbo should produce identical output to libjpeg
|
||||||
|
v6b. The one exception to this is when using the floating point DCT/IDCT, in
|
||||||
|
which case the outputs of libjpeg v6b and libjpeg-turbo can differ for the
|
||||||
|
following reasons:
|
||||||
|
|
||||||
|
- The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever so
|
||||||
|
slightly more accurate than the implementation in libjpeg v6b, but not by
|
||||||
|
any amount perceptible to human vision (generally in the range of 0.01 to
|
||||||
|
0.08 dB gain in PNSR.)
|
||||||
|
|
||||||
|
- When not using the SIMD extensions, libjpeg-turbo uses the more accurate
|
||||||
|
(and slightly faster) floating point IDCT algorithm introduced in libjpeg
|
||||||
|
v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
|
||||||
|
however, that this algorithm basically brings the accuracy of the floating
|
||||||
|
point IDCT in line with the accuracy of the slow integer IDCT. The floating
|
||||||
|
point DCT/IDCT algorithms are mainly a legacy feature, and they do not
|
||||||
|
produce significantly more accuracy than the slow integer algorithms (to put
|
||||||
|
numbers on this, the typical difference in PNSR between the two algorithms
|
||||||
|
is less than 0.10 dB, whereas changing the quality level by 1 in the upper
|
||||||
|
range of the quality scale is typically more like a 1.0 dB difference.)
|
||||||
|
|
||||||
|
- If the floating point algorithms in libjpeg-turbo are not implemented using
|
||||||
|
SIMD instructions on a particular platform, then the accuracy of the
|
||||||
|
floating point DCT/IDCT can depend on the compiler settings.
|
||||||
|
|
||||||
|
While libjpeg-turbo does emulate the libjpeg v8 API/ABI, under the hood it is
|
||||||
|
still using the same algorithms as libjpeg v6b, so there are several specific
|
||||||
|
cases in which libjpeg-turbo cannot be expected to produce the same output as
|
||||||
|
libjpeg v8:
|
||||||
|
|
||||||
|
- When decompressing using scaling factors of 1/2 and 1/4, because libjpeg v8
|
||||||
|
implements those scaling algorithms differently than libjpeg v6b does, and
|
||||||
|
libjpeg-turbo's SIMD extensions are based on the libjpeg v6b behavior.
|
||||||
|
|
||||||
|
- When using chrominance subsampling, because libjpeg v8 implements this
|
||||||
|
with its DCT/IDCT scaling algorithms rather than with a separate
|
||||||
|
downsampling/upsampling algorithm. In our testing, the subsampled/upsampled
|
||||||
|
output of libjpeg v8 is less accurate than that of libjpeg v6b for this
|
||||||
|
reason.
|
||||||
|
|
||||||
|
- When decompressing using a scaling factor > 1 and merged (AKA "non-fancy" or
|
||||||
|
"non-smooth") chrominance upsampling, because libjpeg v8 does not support
|
||||||
|
merged upsampling with scaling factors > 1.
|
||||||
|
|
||||||
|
|
||||||
|
Performance Pitfalls
|
||||||
|
====================
|
||||||
|
|
||||||
|
Restart Markers
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The optimized Huffman decoder in libjpeg-turbo does not handle restart markers
|
||||||
|
in a way that makes the rest of the libjpeg infrastructure happy, so it is
|
||||||
|
necessary to use the slow Huffman decoder when decompressing a JPEG image that
|
||||||
|
has restart markers. This can cause the decompression performance to drop by
|
||||||
|
as much as 20%, but the performance will still be much greater than that of
|
||||||
|
libjpeg. Many consumer packages, such as PhotoShop, use restart markers when
|
||||||
|
generating JPEG images, so images generated by those programs will experience
|
||||||
|
this issue.
|
||||||
|
|
||||||
|
Fast Integer Forward DCT at High Quality Levels
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
The algorithm used by the SIMD-accelerated quantization function cannot produce
|
||||||
|
correct results whenever the fast integer forward DCT is used along with a JPEG
|
||||||
|
quality of 98-100. Thus, libjpeg-turbo must use the non-SIMD quantization
|
||||||
|
function in those cases. This causes performance to drop by as much as 40%.
|
||||||
|
It is therefore strongly advised that you use the slow integer forward DCT
|
||||||
|
whenever encoding images with a JPEG quality of 98 or higher.
|
|
@ -1,9 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* jaricom.c
|
* jaricom.c
|
||||||
*
|
*
|
||||||
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Developed 1997-2009 by Guido Vollbeding.
|
* Developed 1997-2009 by Guido Vollbeding.
|
||||||
* This file is part of the Independent JPEG Group's software.
|
* libjpeg-turbo Modifications:
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains probability estimation tables for common use in
|
* This file contains probability estimation tables for common use in
|
||||||
* arithmetic entropy encoding and decoding routines.
|
* arithmetic entropy encoding and decoding routines.
|
||||||
|
@ -18,7 +21,7 @@
|
||||||
#include "jpeglib.h"
|
#include "jpeglib.h"
|
||||||
|
|
||||||
/* The following #define specifies the packing of the four components
|
/* The following #define specifies the packing of the four components
|
||||||
* into the compact INT32 representation.
|
* into the compact JLONG representation.
|
||||||
* Note that this formula must match the actual arithmetic encoder
|
* Note that this formula must match the actual arithmetic encoder
|
||||||
* and decoder implementation. The implementation has to be changed
|
* and decoder implementation. The implementation has to be changed
|
||||||
* if this formula is changed.
|
* if this formula is changed.
|
||||||
|
@ -26,9 +29,9 @@
|
||||||
* implementation (jbig_tab.c).
|
* implementation (jbig_tab.c).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)
|
#define V(i,a,b,c,d) (((JLONG)a << 16) | ((JLONG)c << 8) | ((JLONG)d << 7) | b)
|
||||||
|
|
||||||
const INT32 jpeg_aritab[113+1] = {
|
const JLONG jpeg_aritab[113+1] = {
|
||||||
/*
|
/*
|
||||||
* Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
|
* Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
* Modified 2003-2010 by Guido Vollbeding.
|
* Modified 2003-2010 by Guido Vollbeding.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||||
* to libjpeg-turbo.
|
* to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains application interface code for the compression half
|
* This file contains application interface code for the compression half
|
||||||
* of the JPEG library. These are the "minimum" API routines that may be
|
* of the JPEG library. These are the "minimum" API routines that may be
|
||||||
|
@ -49,8 +50,8 @@ jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
|
||||||
* complain here.
|
* complain here.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
struct jpeg_error_mgr * err = cinfo->err;
|
struct jpeg_error_mgr *err = cinfo->err;
|
||||||
void * client_data = cinfo->client_data; /* ignore Purify complaint here */
|
void *client_data = cinfo->client_data; /* ignore Purify complaint here */
|
||||||
MEMZERO(cinfo, sizeof(struct jpeg_compress_struct));
|
MEMZERO(cinfo, sizeof(struct jpeg_compress_struct));
|
||||||
cinfo->err = err;
|
cinfo->err = err;
|
||||||
cinfo->client_data = client_data;
|
cinfo->client_data = client_data;
|
||||||
|
@ -133,8 +134,8 @@ GLOBAL(void)
|
||||||
jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
|
jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
JQUANT_TBL * qtbl;
|
JQUANT_TBL *qtbl;
|
||||||
JHUFF_TBL * htbl;
|
JHUFF_TBL *htbl;
|
||||||
|
|
||||||
for (i = 0; i < NUM_QUANT_TBLS; i++) {
|
for (i = 0; i < NUM_QUANT_TBLS; i++) {
|
||||||
if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)
|
if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* This file is part of the Independent JPEG Group's software.
|
* This file is part of the Independent JPEG Group's software.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains application interface code for the compression half
|
* This file contains application interface code for the compression half
|
||||||
* of the JPEG library. These are the "standard" API routines that are
|
* of the JPEG library. These are the "standard" API routines that are
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Developed 1997-2009 by Guido Vollbeding.
|
* Developed 1997-2009 by Guido Vollbeding.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* libjpeg-turbo Modifications:
|
||||||
* to libjpeg-turbo.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains portable arithmetic entropy encoding routines for JPEG
|
* This file contains portable arithmetic entropy encoding routines for JPEG
|
||||||
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
|
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
|
||||||
|
@ -25,10 +26,10 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct jpeg_entropy_encoder pub; /* public fields */
|
struct jpeg_entropy_encoder pub; /* public fields */
|
||||||
|
|
||||||
INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */
|
JLONG c; /* C register, base of coding interval, layout as in sec. D.1.3 */
|
||||||
INT32 a; /* A register, normalized size of coding interval */
|
JLONG a; /* A register, normalized size of coding interval */
|
||||||
INT32 sc; /* counter for stacked 0xFF values which might overflow */
|
JLONG sc; /* counter for stacked 0xFF values which might overflow */
|
||||||
INT32 zc; /* counter for pending 0x00 output values which might *
|
JLONG zc; /* counter for pending 0x00 output values which might *
|
||||||
* be discarded at the end ("Pacman" termination) */
|
* be discarded at the end ("Pacman" termination) */
|
||||||
int ct; /* bit shift counter, determines when next byte will be written */
|
int ct; /* bit shift counter, determines when next byte will be written */
|
||||||
int buffer; /* buffer for most recent output byte != 0xFF */
|
int buffer; /* buffer for most recent output byte != 0xFF */
|
||||||
|
@ -40,14 +41,14 @@ typedef struct {
|
||||||
int next_restart_num; /* next restart number to write (0-7) */
|
int next_restart_num; /* next restart number to write (0-7) */
|
||||||
|
|
||||||
/* Pointers to statistics areas (these workspaces have image lifespan) */
|
/* Pointers to statistics areas (these workspaces have image lifespan) */
|
||||||
unsigned char * dc_stats[NUM_ARITH_TBLS];
|
unsigned char *dc_stats[NUM_ARITH_TBLS];
|
||||||
unsigned char * ac_stats[NUM_ARITH_TBLS];
|
unsigned char *ac_stats[NUM_ARITH_TBLS];
|
||||||
|
|
||||||
/* Statistics bin for coding with fixed probability 0.5 */
|
/* Statistics bin for coding with fixed probability 0.5 */
|
||||||
unsigned char fixed_bin[4];
|
unsigned char fixed_bin[4];
|
||||||
} arith_entropy_encoder;
|
} arith_entropy_encoder;
|
||||||
|
|
||||||
typedef arith_entropy_encoder * arith_entropy_ptr;
|
typedef arith_entropy_encoder *arith_entropy_ptr;
|
||||||
|
|
||||||
/* The following two definitions specify the allocation chunk size
|
/* The following two definitions specify the allocation chunk size
|
||||||
* for the statistics area.
|
* for the statistics area.
|
||||||
|
@ -97,8 +98,8 @@ typedef arith_entropy_encoder * arith_entropy_ptr;
|
||||||
#define CALCULATE_SPECTRAL_CONDITIONING
|
#define CALCULATE_SPECTRAL_CONDITIONING
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
|
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than JLONG.
|
||||||
* We assume that int right shift is unsigned if INT32 right shift is,
|
* We assume that int right shift is unsigned if JLONG right shift is,
|
||||||
* which should be safe.
|
* which should be safe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -118,7 +119,7 @@ LOCAL(void)
|
||||||
emit_byte (int val, j_compress_ptr cinfo)
|
emit_byte (int val, j_compress_ptr cinfo)
|
||||||
/* Write next output byte; we do not support suspension in this module. */
|
/* Write next output byte; we do not support suspension in this module. */
|
||||||
{
|
{
|
||||||
struct jpeg_destination_mgr * dest = cinfo->dest;
|
struct jpeg_destination_mgr *dest = cinfo->dest;
|
||||||
|
|
||||||
*dest->next_output_byte++ = (JOCTET) val;
|
*dest->next_output_byte++ = (JOCTET) val;
|
||||||
if (--dest->free_in_buffer == 0)
|
if (--dest->free_in_buffer == 0)
|
||||||
|
@ -135,7 +136,7 @@ METHODDEF(void)
|
||||||
finish_pass (j_compress_ptr cinfo)
|
finish_pass (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
|
arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
|
||||||
INT32 temp;
|
JLONG temp;
|
||||||
|
|
||||||
/* Section D.1.8: Termination of encoding */
|
/* Section D.1.8: Termination of encoding */
|
||||||
|
|
||||||
|
@ -222,7 +223,7 @@ arith_encode (j_compress_ptr cinfo, unsigned char *st, int val)
|
||||||
{
|
{
|
||||||
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
|
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
|
||||||
register unsigned char nl, nm;
|
register unsigned char nl, nm;
|
||||||
register INT32 qe, temp;
|
register JLONG qe, temp;
|
||||||
register int sv;
|
register int sv;
|
||||||
|
|
||||||
/* Fetch values from our compact representation of Table D.2:
|
/* Fetch values from our compact representation of Table D.2:
|
||||||
|
@ -322,7 +323,7 @@ emit_restart (j_compress_ptr cinfo, int restart_num)
|
||||||
{
|
{
|
||||||
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
||||||
int ci;
|
int ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
finish_pass(cinfo);
|
finish_pass(cinfo);
|
||||||
|
|
||||||
|
@ -682,7 +683,7 @@ METHODDEF(boolean)
|
||||||
encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
{
|
{
|
||||||
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
JBLOCKROW block;
|
JBLOCKROW block;
|
||||||
unsigned char *st;
|
unsigned char *st;
|
||||||
int blkn, ci, tbl, k, ke;
|
int blkn, ci, tbl, k, ke;
|
||||||
|
@ -825,7 +826,7 @@ start_pass (j_compress_ptr cinfo, boolean gather_statistics)
|
||||||
{
|
{
|
||||||
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
||||||
int ci, tbl;
|
int ci, tbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
if (gather_statistics)
|
if (gather_statistics)
|
||||||
/* Make sure to avoid that in the master control logic!
|
/* Make sure to avoid that in the master control logic!
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code and
|
* It was modified by The libjpeg-turbo Project to include only code and
|
||||||
* information relevant to libjpeg-turbo.
|
* information relevant to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the coefficient buffer controller for compression.
|
* This file contains the coefficient buffer controller for compression.
|
||||||
* This controller is the top level of the JPEG compressor proper.
|
* This controller is the top level of the JPEG compressor proper.
|
||||||
|
@ -53,7 +54,7 @@ typedef struct {
|
||||||
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
|
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
|
||||||
} my_coef_controller;
|
} my_coef_controller;
|
||||||
|
|
||||||
typedef my_coef_controller * my_coef_ptr;
|
typedef my_coef_controller *my_coef_ptr;
|
||||||
|
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2009-2012, D. R. Commander.
|
* Copyright (C) 2009-2012, 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains input colorspace conversion routines.
|
* This file contains input colorspace conversion routines.
|
||||||
*/
|
*/
|
||||||
|
@ -34,7 +35,7 @@ rgb_ycc_convert_internal (j_compress_ptr cinfo,
|
||||||
{
|
{
|
||||||
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
||||||
register int r, g, b;
|
register int r, g, b;
|
||||||
register INT32 * ctab = cconvert->rgb_ycc_tab;
|
register JLONG * ctab = cconvert->rgb_ycc_tab;
|
||||||
register JSAMPROW inptr;
|
register JSAMPROW inptr;
|
||||||
register JSAMPROW outptr0, outptr1, outptr2;
|
register JSAMPROW outptr0, outptr1, outptr2;
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
|
@ -91,7 +92,7 @@ rgb_gray_convert_internal (j_compress_ptr cinfo,
|
||||||
{
|
{
|
||||||
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
||||||
register int r, g, b;
|
register int r, g, b;
|
||||||
register INT32 * ctab = cconvert->rgb_ycc_tab;
|
register JLONG * ctab = cconvert->rgb_ycc_tab;
|
||||||
register JSAMPROW inptr;
|
register JSAMPROW inptr;
|
||||||
register JSAMPROW outptr;
|
register JSAMPROW outptr;
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
* Copyright (C) 2009-2012, 2015 D. R. Commander.
|
* Copyright (C) 2009-2012, 2015, D. R. Commander.
|
||||||
* Copyright (C) 2014, MIPS Technologies, Inc., California
|
* Copyright (C) 2014, MIPS Technologies, Inc., California.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains input colorspace conversion routines.
|
* This file contains input colorspace conversion routines.
|
||||||
*/
|
*/
|
||||||
|
@ -25,10 +26,10 @@ typedef struct {
|
||||||
struct jpeg_color_converter pub; /* public fields */
|
struct jpeg_color_converter pub; /* public fields */
|
||||||
|
|
||||||
/* Private state for RGB->YCC conversion */
|
/* Private state for RGB->YCC conversion */
|
||||||
INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
|
JLONG *rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
|
||||||
} my_color_converter;
|
} my_color_converter;
|
||||||
|
|
||||||
typedef my_color_converter * my_cconvert_ptr;
|
typedef my_color_converter *my_cconvert_ptr;
|
||||||
|
|
||||||
|
|
||||||
/**************** RGB -> YCbCr conversion: most common case **************/
|
/**************** RGB -> YCbCr conversion: most common case **************/
|
||||||
|
@ -62,9 +63,9 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SCALEBITS 16 /* speediest right-shift on some machines */
|
#define SCALEBITS 16 /* speediest right-shift on some machines */
|
||||||
#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS)
|
#define CBCR_OFFSET ((JLONG) CENTERJSAMPLE << SCALEBITS)
|
||||||
#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
|
#define ONE_HALF ((JLONG) 1 << (SCALEBITS-1))
|
||||||
#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
|
#define FIX(x) ((JLONG) ((x) * (1L<<SCALEBITS) + 0.5))
|
||||||
|
|
||||||
/* We allocate one big table and divide it up into eight parts, instead of
|
/* We allocate one big table and divide it up into eight parts, instead of
|
||||||
* doing eight alloc_small requests. This lets us use a single table base
|
* doing eight alloc_small requests. This lets us use a single table base
|
||||||
|
@ -197,13 +198,13 @@ METHODDEF(void)
|
||||||
rgb_ycc_start (j_compress_ptr cinfo)
|
rgb_ycc_start (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
||||||
INT32 * rgb_ycc_tab;
|
JLONG *rgb_ycc_tab;
|
||||||
INT32 i;
|
JLONG i;
|
||||||
|
|
||||||
/* Allocate and fill in the conversion tables. */
|
/* Allocate and fill in the conversion tables. */
|
||||||
cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
|
cconvert->rgb_ycc_tab = rgb_ycc_tab = (JLONG *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(TABLE_SIZE * sizeof(INT32)));
|
(TABLE_SIZE * sizeof(JLONG)));
|
||||||
|
|
||||||
for (i = 0; i <= MAXJSAMPLE; i++) {
|
for (i = 0; i <= MAXJSAMPLE; i++) {
|
||||||
rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
|
rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
|
||||||
|
@ -381,7 +382,7 @@ cmyk_ycck_convert (j_compress_ptr cinfo,
|
||||||
{
|
{
|
||||||
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
||||||
register int r, g, b;
|
register int r, g, b;
|
||||||
register INT32 * ctab = cconvert->rgb_ycc_tab;
|
register JLONG *ctab = cconvert->rgb_ycc_tab;
|
||||||
register JSAMPROW inptr;
|
register JSAMPROW inptr;
|
||||||
register JSAMPROW outptr0, outptr1, outptr2, outptr3;
|
register JSAMPROW outptr0, outptr1, outptr2, outptr3;
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 1999-2006, MIYASAKA Masaru.
|
* Copyright (C) 1999-2006, MIYASAKA Masaru.
|
||||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
* Copyright (C) 2011, 2014-2015 D. R. Commander
|
* Copyright (C) 2011, 2014-2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the forward-DCT management logic.
|
* This file contains the forward-DCT management logic.
|
||||||
* This code selects a particular DCT implementation to be used,
|
* This code selects a particular DCT implementation to be used,
|
||||||
|
@ -24,21 +25,21 @@
|
||||||
|
|
||||||
/* Private subobject for this module */
|
/* Private subobject for this module */
|
||||||
|
|
||||||
typedef void (*forward_DCT_method_ptr) (DCTELEM * data);
|
typedef void (*forward_DCT_method_ptr) (DCTELEM *data);
|
||||||
typedef void (*float_DCT_method_ptr) (FAST_FLOAT * data);
|
typedef void (*float_DCT_method_ptr) (FAST_FLOAT *data);
|
||||||
|
|
||||||
typedef void (*convsamp_method_ptr) (JSAMPARRAY sample_data,
|
typedef void (*convsamp_method_ptr) (JSAMPARRAY sample_data,
|
||||||
JDIMENSION start_col,
|
JDIMENSION start_col,
|
||||||
DCTELEM * workspace);
|
DCTELEM *workspace);
|
||||||
typedef void (*float_convsamp_method_ptr) (JSAMPARRAY sample_data,
|
typedef void (*float_convsamp_method_ptr) (JSAMPARRAY sample_data,
|
||||||
JDIMENSION start_col,
|
JDIMENSION start_col,
|
||||||
FAST_FLOAT *workspace);
|
FAST_FLOAT *workspace);
|
||||||
|
|
||||||
typedef void (*quantize_method_ptr) (JCOEFPTR coef_block, DCTELEM * divisors,
|
typedef void (*quantize_method_ptr) (JCOEFPTR coef_block, DCTELEM *divisors,
|
||||||
DCTELEM * workspace);
|
DCTELEM *workspace);
|
||||||
typedef void (*float_quantize_method_ptr) (JCOEFPTR coef_block,
|
typedef void (*float_quantize_method_ptr) (JCOEFPTR coef_block,
|
||||||
FAST_FLOAT * divisors,
|
FAST_FLOAT *divisors,
|
||||||
FAST_FLOAT * workspace);
|
FAST_FLOAT *workspace);
|
||||||
|
|
||||||
METHODDEF(void) quantize (JCOEFPTR, DCTELEM *, DCTELEM *);
|
METHODDEF(void) quantize (JCOEFPTR, DCTELEM *, DCTELEM *);
|
||||||
|
|
||||||
|
@ -54,22 +55,22 @@ typedef struct {
|
||||||
* entries, because of scaling (especially for an unnormalized DCT).
|
* entries, because of scaling (especially for an unnormalized DCT).
|
||||||
* Each table is given in normal array order.
|
* Each table is given in normal array order.
|
||||||
*/
|
*/
|
||||||
DCTELEM * divisors[NUM_QUANT_TBLS];
|
DCTELEM *divisors[NUM_QUANT_TBLS];
|
||||||
|
|
||||||
/* work area for FDCT subroutine */
|
/* work area for FDCT subroutine */
|
||||||
DCTELEM * workspace;
|
DCTELEM *workspace;
|
||||||
|
|
||||||
#ifdef DCT_FLOAT_SUPPORTED
|
#ifdef DCT_FLOAT_SUPPORTED
|
||||||
/* Same as above for the floating-point case. */
|
/* Same as above for the floating-point case. */
|
||||||
float_DCT_method_ptr float_dct;
|
float_DCT_method_ptr float_dct;
|
||||||
float_convsamp_method_ptr float_convsamp;
|
float_convsamp_method_ptr float_convsamp;
|
||||||
float_quantize_method_ptr float_quantize;
|
float_quantize_method_ptr float_quantize;
|
||||||
FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
|
FAST_FLOAT *float_divisors[NUM_QUANT_TBLS];
|
||||||
FAST_FLOAT * float_workspace;
|
FAST_FLOAT *float_workspace;
|
||||||
#endif
|
#endif
|
||||||
} my_fdct_controller;
|
} my_fdct_controller;
|
||||||
|
|
||||||
typedef my_fdct_controller * my_fdct_ptr;
|
typedef my_fdct_controller *my_fdct_ptr;
|
||||||
|
|
||||||
|
|
||||||
#if BITS_IN_JSAMPLE == 8
|
#if BITS_IN_JSAMPLE == 8
|
||||||
|
@ -169,7 +170,7 @@ flss (UINT16 val)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LOCAL(int)
|
LOCAL(int)
|
||||||
compute_reciprocal (UINT16 divisor, DCTELEM * dtbl)
|
compute_reciprocal (UINT16 divisor, DCTELEM *dtbl)
|
||||||
{
|
{
|
||||||
UDCTELEM2 fq, fr;
|
UDCTELEM2 fq, fr;
|
||||||
UDCTELEM c;
|
UDCTELEM c;
|
||||||
|
@ -184,7 +185,7 @@ compute_reciprocal (UINT16 divisor, DCTELEM * dtbl)
|
||||||
dtbl[DCTSIZE2 * 0] = (DCTELEM) 1; /* reciprocal */
|
dtbl[DCTSIZE2 * 0] = (DCTELEM) 1; /* reciprocal */
|
||||||
dtbl[DCTSIZE2 * 1] = (DCTELEM) 0; /* correction */
|
dtbl[DCTSIZE2 * 1] = (DCTELEM) 0; /* correction */
|
||||||
dtbl[DCTSIZE2 * 2] = (DCTELEM) 1; /* scale */
|
dtbl[DCTSIZE2 * 2] = (DCTELEM) 1; /* scale */
|
||||||
dtbl[DCTSIZE2 * 3] = (DCTELEM) (-sizeof(DCTELEM) * 8); /* shift */
|
dtbl[DCTSIZE2 * 3] = -(DCTELEM) (sizeof(DCTELEM) * 8); /* shift */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +209,11 @@ compute_reciprocal (UINT16 divisor, DCTELEM * dtbl)
|
||||||
|
|
||||||
dtbl[DCTSIZE2 * 0] = (DCTELEM) fq; /* reciprocal */
|
dtbl[DCTSIZE2 * 0] = (DCTELEM) fq; /* reciprocal */
|
||||||
dtbl[DCTSIZE2 * 1] = (DCTELEM) c; /* correction + roundfactor */
|
dtbl[DCTSIZE2 * 1] = (DCTELEM) c; /* correction + roundfactor */
|
||||||
|
#ifdef WITH_SIMD
|
||||||
dtbl[DCTSIZE2 * 2] = (DCTELEM) (1 << (sizeof(DCTELEM)*8*2 - r)); /* scale */
|
dtbl[DCTSIZE2 * 2] = (DCTELEM) (1 << (sizeof(DCTELEM)*8*2 - r)); /* scale */
|
||||||
|
#else
|
||||||
|
dtbl[DCTSIZE2 * 2] = 1;
|
||||||
|
#endif
|
||||||
dtbl[DCTSIZE2 * 3] = (DCTELEM) r - sizeof(DCTELEM)*8; /* shift */
|
dtbl[DCTSIZE2 * 3] = (DCTELEM) r - sizeof(DCTELEM)*8; /* shift */
|
||||||
|
|
||||||
if(r <= 16) return 0;
|
if(r <= 16) return 0;
|
||||||
|
@ -233,8 +238,8 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
|
||||||
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
|
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
|
||||||
int ci, qtblno, i;
|
int ci, qtblno, i;
|
||||||
jpeg_component_info *compptr;
|
jpeg_component_info *compptr;
|
||||||
JQUANT_TBL * qtbl;
|
JQUANT_TBL *qtbl;
|
||||||
DCTELEM * dtbl;
|
DCTELEM *dtbl;
|
||||||
|
|
||||||
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
||||||
ci++, compptr++) {
|
ci++, compptr++) {
|
||||||
|
@ -260,8 +265,8 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
|
||||||
dtbl = fdct->divisors[qtblno];
|
dtbl = fdct->divisors[qtblno];
|
||||||
for (i = 0; i < DCTSIZE2; i++) {
|
for (i = 0; i < DCTSIZE2; i++) {
|
||||||
#if BITS_IN_JSAMPLE == 8
|
#if BITS_IN_JSAMPLE == 8
|
||||||
if(!compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i])
|
if (!compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i]) &&
|
||||||
&& fdct->quantize == jsimd_quantize)
|
fdct->quantize == jsimd_quantize)
|
||||||
fdct->quantize = quantize;
|
fdct->quantize = quantize;
|
||||||
#else
|
#else
|
||||||
dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
|
dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
|
||||||
|
@ -300,16 +305,16 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
|
||||||
dtbl = fdct->divisors[qtblno];
|
dtbl = fdct->divisors[qtblno];
|
||||||
for (i = 0; i < DCTSIZE2; i++) {
|
for (i = 0; i < DCTSIZE2; i++) {
|
||||||
#if BITS_IN_JSAMPLE == 8
|
#if BITS_IN_JSAMPLE == 8
|
||||||
if(!compute_reciprocal(
|
if (!compute_reciprocal(
|
||||||
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
|
DESCALE(MULTIPLY16V16((JLONG) qtbl->quantval[i],
|
||||||
(INT32) aanscales[i]),
|
(JLONG) aanscales[i]),
|
||||||
CONST_BITS-3), &dtbl[i])
|
CONST_BITS-3), &dtbl[i]) &&
|
||||||
&& fdct->quantize == jsimd_quantize)
|
fdct->quantize == jsimd_quantize)
|
||||||
fdct->quantize = quantize;
|
fdct->quantize = quantize;
|
||||||
#else
|
#else
|
||||||
dtbl[i] = (DCTELEM)
|
dtbl[i] = (DCTELEM)
|
||||||
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
|
DESCALE(MULTIPLY16V16((JLONG) qtbl->quantval[i],
|
||||||
(INT32) aanscales[i]),
|
(JLONG) aanscales[i]),
|
||||||
CONST_BITS-3);
|
CONST_BITS-3);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -327,7 +332,7 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
|
||||||
* What's actually stored is 1/divisor so that the inner loop can
|
* What's actually stored is 1/divisor so that the inner loop can
|
||||||
* use a multiplication rather than a division.
|
* use a multiplication rather than a division.
|
||||||
*/
|
*/
|
||||||
FAST_FLOAT * fdtbl;
|
FAST_FLOAT *fdtbl;
|
||||||
int row, col;
|
int row, col;
|
||||||
static const double aanscalefactor[DCTSIZE] = {
|
static const double aanscalefactor[DCTSIZE] = {
|
||||||
1.0, 1.387039845, 1.306562965, 1.175875602,
|
1.0, 1.387039845, 1.306562965, 1.175875602,
|
||||||
|
@ -365,7 +370,7 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
convsamp (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM * workspace)
|
convsamp (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
|
||||||
{
|
{
|
||||||
register DCTELEM *workspaceptr;
|
register DCTELEM *workspaceptr;
|
||||||
register JSAMPROW elemptr;
|
register JSAMPROW elemptr;
|
||||||
|
@ -400,7 +405,7 @@ convsamp (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM * workspace)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
quantize (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace)
|
quantize (JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
DCTELEM temp;
|
DCTELEM temp;
|
||||||
|
@ -422,12 +427,12 @@ quantize (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace)
|
||||||
temp = -temp;
|
temp = -temp;
|
||||||
product = (UDCTELEM2)(temp + corr) * recip;
|
product = (UDCTELEM2)(temp + corr) * recip;
|
||||||
product >>= shift + sizeof(DCTELEM)*8;
|
product >>= shift + sizeof(DCTELEM)*8;
|
||||||
temp = product;
|
temp = (DCTELEM)product;
|
||||||
temp = -temp;
|
temp = -temp;
|
||||||
} else {
|
} else {
|
||||||
product = (UDCTELEM2)(temp + corr) * recip;
|
product = (UDCTELEM2)(temp + corr) * recip;
|
||||||
product >>= shift + sizeof(DCTELEM)*8;
|
product >>= shift + sizeof(DCTELEM)*8;
|
||||||
temp = product;
|
temp = (DCTELEM)product;
|
||||||
}
|
}
|
||||||
output_ptr[i] = (JCOEF) temp;
|
output_ptr[i] = (JCOEF) temp;
|
||||||
}
|
}
|
||||||
|
@ -482,7 +487,7 @@ quantize (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
forward_DCT (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
|
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
|
||||||
JDIMENSION start_row, JDIMENSION start_col,
|
JDIMENSION start_row, JDIMENSION start_col,
|
||||||
JDIMENSION num_blocks)
|
JDIMENSION num_blocks)
|
||||||
|
@ -490,8 +495,8 @@ forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
{
|
{
|
||||||
/* This routine is heavily used, so it's worth coding it tightly. */
|
/* This routine is heavily used, so it's worth coding it tightly. */
|
||||||
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
|
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
|
||||||
DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
|
DCTELEM *divisors = fdct->divisors[compptr->quant_tbl_no];
|
||||||
DCTELEM * workspace;
|
DCTELEM *workspace;
|
||||||
JDIMENSION bi;
|
JDIMENSION bi;
|
||||||
|
|
||||||
/* Make sure the compiler doesn't look up these every pass */
|
/* Make sure the compiler doesn't look up these every pass */
|
||||||
|
@ -519,7 +524,7 @@ forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
|
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col, FAST_FLOAT * workspace)
|
convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col, FAST_FLOAT *workspace)
|
||||||
{
|
{
|
||||||
register FAST_FLOAT *workspaceptr;
|
register FAST_FLOAT *workspaceptr;
|
||||||
register JSAMPROW elemptr;
|
register JSAMPROW elemptr;
|
||||||
|
@ -550,7 +555,7 @@ convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col, FAST_FLOAT * works
|
||||||
|
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
quantize_float (JCOEFPTR coef_block, FAST_FLOAT * divisors, FAST_FLOAT * workspace)
|
quantize_float (JCOEFPTR coef_block, FAST_FLOAT *divisors, FAST_FLOAT *workspace)
|
||||||
{
|
{
|
||||||
register FAST_FLOAT temp;
|
register FAST_FLOAT temp;
|
||||||
register int i;
|
register int i;
|
||||||
|
@ -572,7 +577,7 @@ quantize_float (JCOEFPTR coef_block, FAST_FLOAT * divisors, FAST_FLOAT * workspa
|
||||||
|
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
|
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
|
||||||
JDIMENSION start_row, JDIMENSION start_col,
|
JDIMENSION start_row, JDIMENSION start_col,
|
||||||
JDIMENSION num_blocks)
|
JDIMENSION num_blocks)
|
||||||
|
@ -580,8 +585,8 @@ forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
{
|
{
|
||||||
/* This routine is heavily used, so it's worth coding it tightly. */
|
/* This routine is heavily used, so it's worth coding it tightly. */
|
||||||
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
|
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
|
||||||
FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
|
FAST_FLOAT *divisors = fdct->float_divisors[compptr->quant_tbl_no];
|
||||||
FAST_FLOAT * workspace;
|
FAST_FLOAT *workspace;
|
||||||
JDIMENSION bi;
|
JDIMENSION bi;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2009-2011, 2014-2015 D. R. Commander.
|
* Copyright (C) 2009-2011, 2014-2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2015, Matthieu Darbois.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains Huffman entropy encoding routines.
|
* This file contains Huffman entropy encoding routines.
|
||||||
*
|
*
|
||||||
|
@ -19,7 +21,8 @@
|
||||||
#define JPEG_INTERNALS
|
#define JPEG_INTERNALS
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jpeglib.h"
|
||||||
#include "jchuff.h" /* Declarations shared with jcphuff.c */
|
#include "jsimd.h"
|
||||||
|
#include "jconfigint.h"
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -99,23 +102,25 @@ typedef struct {
|
||||||
int next_restart_num; /* next restart number to write (0-7) */
|
int next_restart_num; /* next restart number to write (0-7) */
|
||||||
|
|
||||||
/* Pointers to derived tables (these workspaces have image lifespan) */
|
/* Pointers to derived tables (these workspaces have image lifespan) */
|
||||||
c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
|
c_derived_tbl *dc_derived_tbls[NUM_HUFF_TBLS];
|
||||||
c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
|
c_derived_tbl *ac_derived_tbls[NUM_HUFF_TBLS];
|
||||||
|
|
||||||
#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
|
#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
|
||||||
long * dc_count_ptrs[NUM_HUFF_TBLS];
|
long *dc_count_ptrs[NUM_HUFF_TBLS];
|
||||||
long * ac_count_ptrs[NUM_HUFF_TBLS];
|
long *ac_count_ptrs[NUM_HUFF_TBLS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int simd;
|
||||||
} huff_entropy_encoder;
|
} huff_entropy_encoder;
|
||||||
|
|
||||||
typedef huff_entropy_encoder * huff_entropy_ptr;
|
typedef huff_entropy_encoder *huff_entropy_ptr;
|
||||||
|
|
||||||
/* Working state while writing an MCU.
|
/* Working state while writing an MCU.
|
||||||
* This struct contains all the fields that are needed by subroutines.
|
* This struct contains all the fields that are needed by subroutines.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
JOCTET * next_output_byte; /* => next byte to write in buffer */
|
JOCTET *next_output_byte; /* => next byte to write in buffer */
|
||||||
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
|
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
|
||||||
savable_state cur; /* Current bit buffer & DC state */
|
savable_state cur; /* Current bit buffer & DC state */
|
||||||
j_compress_ptr cinfo; /* dump_buffer needs access to this */
|
j_compress_ptr cinfo; /* dump_buffer needs access to this */
|
||||||
|
@ -143,7 +148,7 @@ start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
|
||||||
{
|
{
|
||||||
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
||||||
int ci, dctbl, actbl;
|
int ci, dctbl, actbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
if (gather_statistics) {
|
if (gather_statistics) {
|
||||||
#ifdef ENTROPY_OPT_SUPPORTED
|
#ifdef ENTROPY_OPT_SUPPORTED
|
||||||
|
@ -157,6 +162,8 @@ start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
|
||||||
entropy->pub.finish_pass = finish_pass_huff;
|
entropy->pub.finish_pass = finish_pass_huff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entropy->simd = jsimd_can_huff_encode_one_block();
|
||||||
|
|
||||||
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
||||||
compptr = cinfo->cur_comp_info[ci];
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
dctbl = compptr->dc_tbl_no;
|
dctbl = compptr->dc_tbl_no;
|
||||||
|
@ -213,7 +220,7 @@ start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
|
jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
|
||||||
c_derived_tbl ** pdtbl)
|
c_derived_tbl **pdtbl)
|
||||||
{
|
{
|
||||||
JHUFF_TBL *htbl;
|
JHUFF_TBL *htbl;
|
||||||
c_derived_tbl *dtbl;
|
c_derived_tbl *dtbl;
|
||||||
|
@ -268,7 +275,7 @@ jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
|
||||||
/* code is now 1 more than the last code used for codelength si; but
|
/* code is now 1 more than the last code used for codelength si; but
|
||||||
* it must still fit in si bits, since no code is allowed to be all ones.
|
* it must still fit in si bits, since no code is allowed to be all ones.
|
||||||
*/
|
*/
|
||||||
if (((INT32) code) >= (((INT32) 1) << si))
|
if (((JLONG) code) >= (((JLONG) 1) << si))
|
||||||
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
|
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
|
||||||
code <<= 1;
|
code <<= 1;
|
||||||
si++;
|
si++;
|
||||||
|
@ -311,10 +318,10 @@ jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
|
||||||
|
|
||||||
|
|
||||||
LOCAL(boolean)
|
LOCAL(boolean)
|
||||||
dump_buffer (working_state * state)
|
dump_buffer (working_state *state)
|
||||||
/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
|
/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
|
||||||
{
|
{
|
||||||
struct jpeg_destination_mgr * dest = state->cinfo->dest;
|
struct jpeg_destination_mgr *dest = state->cinfo->dest;
|
||||||
|
|
||||||
if (! (*dest->empty_output_buffer) (state->cinfo))
|
if (! (*dest->empty_output_buffer) (state->cinfo))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -388,7 +395,7 @@ dump_buffer (working_state * state)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EMIT_CODE(code, size) { \
|
#define EMIT_CODE(code, size) { \
|
||||||
temp2 &= (((INT32) 1)<<nbits) - 1; \
|
temp2 &= (((JLONG) 1)<<nbits) - 1; \
|
||||||
CHECKBUF31() \
|
CHECKBUF31() \
|
||||||
PUT_BITS(code, size) \
|
PUT_BITS(code, size) \
|
||||||
PUT_BITS(temp2, nbits) \
|
PUT_BITS(temp2, nbits) \
|
||||||
|
@ -402,7 +409,7 @@ dump_buffer (working_state * state)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EMIT_CODE(code, size) { \
|
#define EMIT_CODE(code, size) { \
|
||||||
temp2 &= (((INT32) 1)<<nbits) - 1; \
|
temp2 &= (((JLONG) 1)<<nbits) - 1; \
|
||||||
PUT_BITS(code, size) \
|
PUT_BITS(code, size) \
|
||||||
CHECKBUF15() \
|
CHECKBUF15() \
|
||||||
PUT_BITS(temp2, nbits) \
|
PUT_BITS(temp2, nbits) \
|
||||||
|
@ -454,7 +461,7 @@ dump_buffer (working_state * state)
|
||||||
|
|
||||||
|
|
||||||
LOCAL(boolean)
|
LOCAL(boolean)
|
||||||
flush_bits (working_state * state)
|
flush_bits (working_state *state)
|
||||||
{
|
{
|
||||||
JOCTET _buffer[BUFSIZE], *buffer;
|
JOCTET _buffer[BUFSIZE], *buffer;
|
||||||
size_t put_buffer; int put_bits;
|
size_t put_buffer; int put_bits;
|
||||||
|
@ -479,7 +486,24 @@ flush_bits (working_state * state)
|
||||||
/* Encode a single block's worth of coefficients */
|
/* Encode a single block's worth of coefficients */
|
||||||
|
|
||||||
LOCAL(boolean)
|
LOCAL(boolean)
|
||||||
encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
|
encode_one_block_simd (working_state *state, JCOEFPTR block, int last_dc_val,
|
||||||
|
c_derived_tbl *dctbl, c_derived_tbl *actbl)
|
||||||
|
{
|
||||||
|
JOCTET _buffer[BUFSIZE], *buffer;
|
||||||
|
size_t bytes, bytestocopy; int localbuf = 0;
|
||||||
|
|
||||||
|
LOAD_BUFFER()
|
||||||
|
|
||||||
|
buffer = jsimd_huff_encode_one_block(state, buffer, block, last_dc_val,
|
||||||
|
dctbl, actbl);
|
||||||
|
|
||||||
|
STORE_BUFFER()
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCAL(boolean)
|
||||||
|
encode_one_block (working_state *state, JCOEFPTR block, int last_dc_val,
|
||||||
c_derived_tbl *dctbl, c_derived_tbl *actbl)
|
c_derived_tbl *dctbl, c_derived_tbl *actbl)
|
||||||
{
|
{
|
||||||
int temp, temp2, temp3;
|
int temp, temp2, temp3;
|
||||||
|
@ -520,7 +544,7 @@ encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
|
||||||
EMIT_BITS(code, size)
|
EMIT_BITS(code, size)
|
||||||
|
|
||||||
/* Mask off any extra bits in code */
|
/* Mask off any extra bits in code */
|
||||||
temp2 &= (((INT32) 1)<<nbits) - 1;
|
temp2 &= (((JLONG) 1)<<nbits) - 1;
|
||||||
|
|
||||||
/* Emit that number of bits of the value, if positive, */
|
/* Emit that number of bits of the value, if positive, */
|
||||||
/* or the complement of its magnitude, if negative. */
|
/* or the complement of its magnitude, if negative. */
|
||||||
|
@ -592,7 +616,7 @@ encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LOCAL(boolean)
|
LOCAL(boolean)
|
||||||
emit_restart (working_state * state, int restart_num)
|
emit_restart (working_state *state, int restart_num)
|
||||||
{
|
{
|
||||||
int ci;
|
int ci;
|
||||||
|
|
||||||
|
@ -622,7 +646,7 @@ encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
||||||
working_state state;
|
working_state state;
|
||||||
int blkn, ci;
|
int blkn, ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
/* Load up working state */
|
/* Load up working state */
|
||||||
state.next_output_byte = cinfo->dest->next_output_byte;
|
state.next_output_byte = cinfo->dest->next_output_byte;
|
||||||
|
@ -638,16 +662,30 @@ encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode the MCU data blocks */
|
/* Encode the MCU data blocks */
|
||||||
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
if (entropy->simd) {
|
||||||
ci = cinfo->MCU_membership[blkn];
|
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||||
compptr = cinfo->cur_comp_info[ci];
|
ci = cinfo->MCU_membership[blkn];
|
||||||
if (! encode_one_block(&state,
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
MCU_data[blkn][0], state.cur.last_dc_val[ci],
|
if (! encode_one_block_simd(&state,
|
||||||
entropy->dc_derived_tbls[compptr->dc_tbl_no],
|
MCU_data[blkn][0], state.cur.last_dc_val[ci],
|
||||||
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
|
entropy->dc_derived_tbls[compptr->dc_tbl_no],
|
||||||
return FALSE;
|
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
|
||||||
/* Update last_dc_val */
|
return FALSE;
|
||||||
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
|
/* Update last_dc_val */
|
||||||
|
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||||
|
ci = cinfo->MCU_membership[blkn];
|
||||||
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
|
if (! encode_one_block(&state,
|
||||||
|
MCU_data[blkn][0], state.cur.last_dc_val[ci],
|
||||||
|
entropy->dc_derived_tbls[compptr->dc_tbl_no],
|
||||||
|
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
|
||||||
|
return FALSE;
|
||||||
|
/* Update last_dc_val */
|
||||||
|
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Completed MCU, so update state */
|
/* Completed MCU, so update state */
|
||||||
|
@ -790,7 +828,7 @@ encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
{
|
{
|
||||||
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
||||||
int blkn, ci;
|
int blkn, ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
/* Take care of restart intervals if needed */
|
/* Take care of restart intervals if needed */
|
||||||
if (cinfo->restart_interval) {
|
if (cinfo->restart_interval) {
|
||||||
|
@ -846,7 +884,7 @@ encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
|
jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
|
||||||
{
|
{
|
||||||
#define MAX_CLEN 32 /* assumed maximum initial code length */
|
#define MAX_CLEN 32 /* assumed maximum initial code length */
|
||||||
UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */
|
UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */
|
||||||
|
@ -991,7 +1029,7 @@ finish_pass_gather (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
||||||
int ci, dctbl, actbl;
|
int ci, dctbl, actbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
JHUFF_TBL **htblptr;
|
JHUFF_TBL **htblptr;
|
||||||
boolean did_dc[NUM_HUFF_TBLS];
|
boolean did_dc[NUM_HUFF_TBLS];
|
||||||
boolean did_ac[NUM_HUFF_TBLS];
|
boolean did_ac[NUM_HUFF_TBLS];
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||||
* to libjpeg-turbo.
|
* to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains declarations for Huffman entropy encoding routines
|
* This file contains declarations for Huffman entropy encoding routines
|
||||||
* that are shared between the sequential encoder (jchuff.c) and the
|
* that are shared between the sequential encoder (jchuff.c) and the
|
||||||
|
@ -39,4 +40,4 @@ EXTERN(void) jpeg_make_c_derived_tbl
|
||||||
|
|
||||||
/* Generate an optimal table definition given the specified counts */
|
/* Generate an optimal table definition given the specified counts */
|
||||||
EXTERN(void) jpeg_gen_optimal_table
|
EXTERN(void) jpeg_gen_optimal_table
|
||||||
(j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]);
|
(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[]);
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* This file is part of the Independent JPEG Group's software.
|
* This file is part of the Independent JPEG Group's software.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains initialization logic for the JPEG compressor.
|
* This file contains initialization logic for the JPEG compressor.
|
||||||
* This routine is in charge of selecting the modules to be executed and
|
* This routine is in charge of selecting the modules to be executed and
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||||
* to libjpeg-turbo.
|
* to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the main buffer controller for compression.
|
* This file contains the main buffer controller for compression.
|
||||||
* The main buffer lies between the pre-processor and the JPEG
|
* The main buffer lies between the pre-processor and the JPEG
|
||||||
|
@ -34,7 +35,7 @@ typedef struct {
|
||||||
JSAMPARRAY buffer[MAX_COMPONENTS];
|
JSAMPARRAY buffer[MAX_COMPONENTS];
|
||||||
} my_main_controller;
|
} my_main_controller;
|
||||||
|
|
||||||
typedef my_main_controller * my_main_ptr;
|
typedef my_main_controller *my_main_ptr;
|
||||||
|
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
* Modified 2003-2010 by Guido Vollbeding.
|
* Modified 2003-2010 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright (C) 2010, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains routines to write JPEG datastream markers.
|
* This file contains routines to write JPEG datastream markers.
|
||||||
*/
|
*/
|
||||||
|
@ -93,7 +94,7 @@ typedef struct {
|
||||||
unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
|
unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
|
||||||
} my_marker_writer;
|
} my_marker_writer;
|
||||||
|
|
||||||
typedef my_marker_writer * my_marker_ptr;
|
typedef my_marker_writer *my_marker_ptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -112,7 +113,7 @@ LOCAL(void)
|
||||||
emit_byte (j_compress_ptr cinfo, int val)
|
emit_byte (j_compress_ptr cinfo, int val)
|
||||||
/* Emit a byte */
|
/* Emit a byte */
|
||||||
{
|
{
|
||||||
struct jpeg_destination_mgr * dest = cinfo->dest;
|
struct jpeg_destination_mgr *dest = cinfo->dest;
|
||||||
|
|
||||||
*(dest->next_output_byte)++ = (JOCTET) val;
|
*(dest->next_output_byte)++ = (JOCTET) val;
|
||||||
if (--dest->free_in_buffer == 0) {
|
if (--dest->free_in_buffer == 0) {
|
||||||
|
@ -149,7 +150,7 @@ emit_dqt (j_compress_ptr cinfo, int index)
|
||||||
/* Emit a DQT marker */
|
/* Emit a DQT marker */
|
||||||
/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
|
/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
|
||||||
{
|
{
|
||||||
JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
|
JQUANT_TBL *qtbl = cinfo->quant_tbl_ptrs[index];
|
||||||
int prec;
|
int prec;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -188,7 +189,7 @@ LOCAL(void)
|
||||||
emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
|
emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
|
||||||
/* Emit a DHT marker */
|
/* Emit a DHT marker */
|
||||||
{
|
{
|
||||||
JHUFF_TBL * htbl;
|
JHUFF_TBL *htbl;
|
||||||
int length, i;
|
int length, i;
|
||||||
|
|
||||||
if (is_ac) {
|
if (is_ac) {
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* Modified 2003-2010 by Guido Vollbeding.
|
* Modified 2003-2010 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright (C) 2010, 2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains master control logic for the JPEG compressor.
|
* This file contains master control logic for the JPEG compressor.
|
||||||
* These routines are concerned with parameter validation, initial setup,
|
* These routines are concerned with parameter validation, initial setup,
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jpeglib.h"
|
||||||
#include "jpegcomp.h"
|
#include "jpegcomp.h"
|
||||||
|
#include "jconfigint.h"
|
||||||
|
|
||||||
|
|
||||||
/* Private state */
|
/* Private state */
|
||||||
|
@ -37,9 +39,19 @@ typedef struct {
|
||||||
int total_passes; /* total # of passes needed */
|
int total_passes; /* total # of passes needed */
|
||||||
|
|
||||||
int scan_number; /* current index in scan_info[] */
|
int scan_number; /* current index in scan_info[] */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is here so we can add libjpeg-turbo version/build information to the
|
||||||
|
* global string table without introducing a new global symbol. Adding this
|
||||||
|
* information to the global string table allows one to examine a binary
|
||||||
|
* object and determine which version of libjpeg-turbo it was built from or
|
||||||
|
* linked against.
|
||||||
|
*/
|
||||||
|
const char *jpeg_version;
|
||||||
|
|
||||||
} my_comp_master;
|
} my_comp_master;
|
||||||
|
|
||||||
typedef my_comp_master * my_master_ptr;
|
typedef my_comp_master *my_master_ptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -167,12 +179,12 @@ validate_script (j_compress_ptr cinfo)
|
||||||
* determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
|
* determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
const jpeg_scan_info * scanptr;
|
const jpeg_scan_info *scanptr;
|
||||||
int scanno, ncomps, ci, coefi, thisi;
|
int scanno, ncomps, ci, coefi, thisi;
|
||||||
int Ss, Se, Ah, Al;
|
int Ss, Se, Ah, Al;
|
||||||
boolean component_sent[MAX_COMPONENTS];
|
boolean component_sent[MAX_COMPONENTS];
|
||||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||||
int * last_bitpos_ptr;
|
int *last_bitpos_ptr;
|
||||||
int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
|
int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
|
||||||
/* -1 until that coefficient has been seen; then last Al for it */
|
/* -1 until that coefficient has been seen; then last Al for it */
|
||||||
#endif
|
#endif
|
||||||
|
@ -308,7 +320,7 @@ select_scan_parameters (j_compress_ptr cinfo)
|
||||||
if (cinfo->scan_info != NULL) {
|
if (cinfo->scan_info != NULL) {
|
||||||
/* Prepare for current scan --- the script is already validated */
|
/* Prepare for current scan --- the script is already validated */
|
||||||
my_master_ptr master = (my_master_ptr) cinfo->master;
|
my_master_ptr master = (my_master_ptr) cinfo->master;
|
||||||
const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;
|
const jpeg_scan_info *scanptr = cinfo->scan_info + master->scan_number;
|
||||||
|
|
||||||
cinfo->comps_in_scan = scanptr->comps_in_scan;
|
cinfo->comps_in_scan = scanptr->comps_in_scan;
|
||||||
for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
|
for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
|
||||||
|
@ -602,7 +614,7 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
|
||||||
cinfo->num_scans = 1;
|
cinfo->num_scans = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cinfo->progressive_mode && !cinfo->arith_code) /* TEMPORARY HACK ??? */
|
if (cinfo->progressive_mode && !cinfo->arith_code) /* TEMPORARY HACK ??? */
|
||||||
cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
|
cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
|
||||||
|
|
||||||
/* Initialize my private state */
|
/* Initialize my private state */
|
||||||
|
@ -622,4 +634,6 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
|
||||||
master->total_passes = cinfo->num_scans * 2;
|
master->total_passes = cinfo->num_scans * 2;
|
||||||
else
|
else
|
||||||
master->total_passes = cinfo->num_scans;
|
master->total_passes = cinfo->num_scans;
|
||||||
|
|
||||||
|
master->jpeg_version = PACKAGE_NAME " version " VERSION " (build " BUILD ")";
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
* jcomapi.c
|
* jcomapi.c
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1997, Thomas G. Lane.0
|
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||||
* to libjpeg-turbo.
|
* to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains application interface routines that are used for both
|
* This file contains application interface routines that are used for both
|
||||||
* compression and decompression.
|
* compression and decompression.
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
* Modified 2003-2008 by Guido Vollbeding.
|
* Modified 2003-2008 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2009-2011, D. R. Commander.
|
* Copyright (C) 2009-2011, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains optional default-setting code for the JPEG compressor.
|
* This file contains optional default-setting code for the JPEG compressor.
|
||||||
* Applications do not have to use this file, but those that don't use it
|
* Applications do not have to use this file, but those that don't use it
|
||||||
|
@ -33,7 +34,7 @@ jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
|
||||||
* are limited to 1..255 for JPEG baseline compatibility.
|
* are limited to 1..255 for JPEG baseline compatibility.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
JQUANT_TBL ** qtblptr;
|
JQUANT_TBL **qtblptr;
|
||||||
int i;
|
int i;
|
||||||
long temp;
|
long temp;
|
||||||
|
|
||||||
|
@ -321,7 +322,7 @@ jpeg_default_colorspace (j_compress_ptr cinfo)
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
|
jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
|
||||||
{
|
{
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
int ci;
|
int ci;
|
||||||
|
|
||||||
#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \
|
#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \
|
||||||
|
@ -403,7 +404,7 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
|
||||||
#ifdef C_PROGRESSIVE_SUPPORTED
|
#ifdef C_PROGRESSIVE_SUPPORTED
|
||||||
|
|
||||||
LOCAL(jpeg_scan_info *)
|
LOCAL(jpeg_scan_info *)
|
||||||
fill_a_scan (jpeg_scan_info * scanptr, int ci,
|
fill_a_scan (jpeg_scan_info *scanptr, int ci,
|
||||||
int Ss, int Se, int Ah, int Al)
|
int Ss, int Se, int Ah, int Al)
|
||||||
/* Support routine: generate one scan for specified component */
|
/* Support routine: generate one scan for specified component */
|
||||||
{
|
{
|
||||||
|
@ -418,7 +419,7 @@ fill_a_scan (jpeg_scan_info * scanptr, int ci,
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCAL(jpeg_scan_info *)
|
LOCAL(jpeg_scan_info *)
|
||||||
fill_scans (jpeg_scan_info * scanptr, int ncomps,
|
fill_scans (jpeg_scan_info *scanptr, int ncomps,
|
||||||
int Ss, int Se, int Ah, int Al)
|
int Ss, int Se, int Ah, int Al)
|
||||||
/* Support routine: generate one scan for each component */
|
/* Support routine: generate one scan for each component */
|
||||||
{
|
{
|
||||||
|
@ -437,7 +438,7 @@ fill_scans (jpeg_scan_info * scanptr, int ncomps,
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCAL(jpeg_scan_info *)
|
LOCAL(jpeg_scan_info *)
|
||||||
fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
|
fill_dc_scans (jpeg_scan_info *scanptr, int ncomps, int Ah, int Al)
|
||||||
/* Support routine: generate interleaved DC scan if possible, else N scans */
|
/* Support routine: generate interleaved DC scan if possible, else N scans */
|
||||||
{
|
{
|
||||||
int ci;
|
int ci;
|
||||||
|
@ -469,7 +470,7 @@ jpeg_simple_progression (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
int ncomps = cinfo->num_components;
|
int ncomps = cinfo->num_components;
|
||||||
int nscans;
|
int nscans;
|
||||||
jpeg_scan_info * scanptr;
|
jpeg_scan_info *scanptr;
|
||||||
|
|
||||||
/* Safety check to ensure start_compress not called yet. */
|
/* Safety check to ensure start_compress not called yet. */
|
||||||
if (cinfo->global_state != CSTATE_START)
|
if (cinfo->global_state != CSTATE_START)
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1995-1997, Thomas G. Lane.
|
* Copyright (C) 1995-1997, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* libjpeg-turbo Modifications:
|
||||||
* to libjpeg-turbo.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains Huffman entropy encoding routines for progressive JPEG.
|
* This file contains Huffman entropy encoding routines for progressive JPEG.
|
||||||
*
|
*
|
||||||
|
@ -32,9 +33,9 @@ typedef struct {
|
||||||
/* Bit-level coding status.
|
/* Bit-level coding status.
|
||||||
* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
|
* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
|
||||||
*/
|
*/
|
||||||
JOCTET * next_output_byte; /* => next byte to write in buffer */
|
JOCTET *next_output_byte; /* => next byte to write in buffer */
|
||||||
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
|
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
|
||||||
INT32 put_buffer; /* current bit-accumulation buffer */
|
size_t put_buffer; /* current bit-accumulation buffer */
|
||||||
int put_bits; /* # of bits now in it */
|
int put_bits; /* # of bits now in it */
|
||||||
j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
|
j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ typedef struct {
|
||||||
int ac_tbl_no; /* the table number of the single component */
|
int ac_tbl_no; /* the table number of the single component */
|
||||||
unsigned int EOBRUN; /* run length of EOBs */
|
unsigned int EOBRUN; /* run length of EOBs */
|
||||||
unsigned int BE; /* # of buffered correction bits before MCU */
|
unsigned int BE; /* # of buffered correction bits before MCU */
|
||||||
char * bit_buffer; /* buffer for correction bits (1 per char) */
|
char *bit_buffer; /* buffer for correction bits (1 per char) */
|
||||||
/* packing correction bits tightly would save some space but cost time... */
|
/* packing correction bits tightly would save some space but cost time... */
|
||||||
|
|
||||||
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
||||||
|
@ -55,13 +56,13 @@ typedef struct {
|
||||||
* Since any one scan codes only DC or only AC, we only need one set
|
* Since any one scan codes only DC or only AC, we only need one set
|
||||||
* of tables, not one for DC and one for AC.
|
* of tables, not one for DC and one for AC.
|
||||||
*/
|
*/
|
||||||
c_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
|
c_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
|
||||||
|
|
||||||
/* Statistics tables for optimization; again, one set is enough */
|
/* Statistics tables for optimization; again, one set is enough */
|
||||||
long * count_ptrs[NUM_HUFF_TBLS];
|
long *count_ptrs[NUM_HUFF_TBLS];
|
||||||
} phuff_entropy_encoder;
|
} phuff_entropy_encoder;
|
||||||
|
|
||||||
typedef phuff_entropy_encoder * phuff_entropy_ptr;
|
typedef phuff_entropy_encoder *phuff_entropy_ptr;
|
||||||
|
|
||||||
/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
|
/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
|
||||||
* buffer can hold. Larger sizes may slightly improve compression, but
|
* buffer can hold. Larger sizes may slightly improve compression, but
|
||||||
|
@ -71,8 +72,8 @@ typedef phuff_entropy_encoder * phuff_entropy_ptr;
|
||||||
|
|
||||||
#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
|
#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
|
||||||
|
|
||||||
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
|
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than JLONG.
|
||||||
* We assume that int right shift is unsigned if INT32 right shift is,
|
* We assume that int right shift is unsigned if JLONG right shift is,
|
||||||
* which should be safe.
|
* which should be safe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
|
||||||
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
|
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
|
||||||
boolean is_DC_band;
|
boolean is_DC_band;
|
||||||
int ci, tbl;
|
int ci, tbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
entropy->cinfo = cinfo;
|
entropy->cinfo = cinfo;
|
||||||
entropy->gather_statistics = gather_statistics;
|
entropy->gather_statistics = gather_statistics;
|
||||||
|
@ -207,7 +208,7 @@ LOCAL(void)
|
||||||
dump_buffer (phuff_entropy_ptr entropy)
|
dump_buffer (phuff_entropy_ptr entropy)
|
||||||
/* Empty the output buffer; we do not support suspension in this module. */
|
/* Empty the output buffer; we do not support suspension in this module. */
|
||||||
{
|
{
|
||||||
struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
|
struct jpeg_destination_mgr *dest = entropy->cinfo->dest;
|
||||||
|
|
||||||
if (! (*dest->empty_output_buffer) (entropy->cinfo))
|
if (! (*dest->empty_output_buffer) (entropy->cinfo))
|
||||||
ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
|
ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
|
||||||
|
@ -230,7 +231,7 @@ emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size)
|
||||||
/* Emit some bits, unless we are in gather mode */
|
/* Emit some bits, unless we are in gather mode */
|
||||||
{
|
{
|
||||||
/* This routine is heavily used, so it's worth coding tightly. */
|
/* This routine is heavily used, so it's worth coding tightly. */
|
||||||
register INT32 put_buffer = (INT32) code;
|
register size_t put_buffer = (size_t) code;
|
||||||
register int put_bits = entropy->put_bits;
|
register int put_bits = entropy->put_bits;
|
||||||
|
|
||||||
/* if size is 0, caller used an invalid Huffman table entry */
|
/* if size is 0, caller used an invalid Huffman table entry */
|
||||||
|
@ -240,7 +241,7 @@ emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size)
|
||||||
if (entropy->gather_statistics)
|
if (entropy->gather_statistics)
|
||||||
return; /* do nothing if we're only getting stats */
|
return; /* do nothing if we're only getting stats */
|
||||||
|
|
||||||
put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
|
put_buffer &= (((size_t) 1)<<size) - 1; /* mask off any extra bits in code */
|
||||||
|
|
||||||
put_bits += size; /* new number of bits in buffer */
|
put_bits += size; /* new number of bits in buffer */
|
||||||
|
|
||||||
|
@ -283,7 +284,7 @@ emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol)
|
||||||
if (entropy->gather_statistics)
|
if (entropy->gather_statistics)
|
||||||
entropy->count_ptrs[tbl_no][symbol]++;
|
entropy->count_ptrs[tbl_no][symbol]++;
|
||||||
else {
|
else {
|
||||||
c_derived_tbl * tbl = entropy->derived_tbls[tbl_no];
|
c_derived_tbl *tbl = entropy->derived_tbls[tbl_no];
|
||||||
emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
|
emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,7 +295,7 @@ emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart,
|
emit_buffered_bits (phuff_entropy_ptr entropy, char *bufstart,
|
||||||
unsigned int nbits)
|
unsigned int nbits)
|
||||||
{
|
{
|
||||||
if (entropy->gather_statistics)
|
if (entropy->gather_statistics)
|
||||||
|
@ -382,7 +383,7 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
int blkn, ci;
|
int blkn, ci;
|
||||||
int Al = cinfo->Al;
|
int Al = cinfo->Al;
|
||||||
JBLOCKROW block;
|
JBLOCKROW block;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
ISHIFT_TEMPS
|
ISHIFT_TEMPS
|
||||||
|
|
||||||
entropy->next_output_byte = cinfo->dest->next_output_byte;
|
entropy->next_output_byte = cinfo->dest->next_output_byte;
|
||||||
|
@ -769,7 +770,7 @@ finish_pass_gather_phuff (j_compress_ptr cinfo)
|
||||||
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
|
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
|
||||||
boolean is_DC_band;
|
boolean is_DC_band;
|
||||||
int ci, tbl;
|
int ci, tbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
JHUFF_TBL **htblptr;
|
JHUFF_TBL **htblptr;
|
||||||
boolean did[NUM_HUFF_TBLS];
|
boolean did[NUM_HUFF_TBLS];
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||||
* to libjpeg-turbo.
|
* to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the compression preprocessing controller.
|
* This file contains the compression preprocessing controller.
|
||||||
* This controller manages the color conversion, downsampling,
|
* This controller manages the color conversion, downsampling,
|
||||||
|
@ -69,7 +70,7 @@ typedef struct {
|
||||||
#endif
|
#endif
|
||||||
} my_prep_controller;
|
} my_prep_controller;
|
||||||
|
|
||||||
typedef my_prep_controller * my_prep_ptr;
|
typedef my_prep_controller *my_prep_ptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -136,7 +137,7 @@ pre_process_data (j_compress_ptr cinfo,
|
||||||
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
|
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
|
||||||
int numrows, ci;
|
int numrows, ci;
|
||||||
JDIMENSION inrows;
|
JDIMENSION inrows;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
while (*in_row_ctr < in_rows_avail &&
|
while (*in_row_ctr < in_rows_avail &&
|
||||||
*out_row_group_ctr < out_row_groups_avail) {
|
*out_row_group_ctr < out_row_groups_avail) {
|
||||||
|
@ -271,7 +272,7 @@ create_context_buffer (j_compress_ptr cinfo)
|
||||||
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
|
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
|
||||||
int rgroup_height = cinfo->max_v_samp_factor;
|
int rgroup_height = cinfo->max_v_samp_factor;
|
||||||
int ci, i;
|
int ci, i;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
JSAMPARRAY true_buffer, fake_buffer;
|
JSAMPARRAY true_buffer, fake_buffer;
|
||||||
|
|
||||||
/* Grab enough space for fake row pointers for all the components;
|
/* Grab enough space for fake row pointers for all the components;
|
||||||
|
@ -318,7 +319,7 @@ jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
|
||||||
{
|
{
|
||||||
my_prep_ptr prep;
|
my_prep_ptr prep;
|
||||||
int ci;
|
int ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
if (need_full_buffer) /* safety check */
|
if (need_full_buffer) /* safety check */
|
||||||
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
|
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
* Copyright (C) 2014, MIPS Technologies, Inc., California
|
* Copyright (C) 2014, MIPS Technologies, Inc., California.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains downsampling routines.
|
* This file contains downsampling routines.
|
||||||
*
|
*
|
||||||
|
@ -56,7 +58,7 @@
|
||||||
|
|
||||||
/* Pointer to routine to downsample a single component */
|
/* Pointer to routine to downsample a single component */
|
||||||
typedef void (*downsample1_ptr) (j_compress_ptr cinfo,
|
typedef void (*downsample1_ptr) (j_compress_ptr cinfo,
|
||||||
jpeg_component_info * compptr,
|
jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data,
|
JSAMPARRAY input_data,
|
||||||
JSAMPARRAY output_data);
|
JSAMPARRAY output_data);
|
||||||
|
|
||||||
|
@ -69,7 +71,7 @@ typedef struct {
|
||||||
downsample1_ptr methods[MAX_COMPONENTS];
|
downsample1_ptr methods[MAX_COMPONENTS];
|
||||||
} my_downsampler;
|
} my_downsampler;
|
||||||
|
|
||||||
typedef my_downsampler * my_downsample_ptr;
|
typedef my_downsampler *my_downsample_ptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -122,7 +124,7 @@ sep_downsample (j_compress_ptr cinfo,
|
||||||
{
|
{
|
||||||
my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
|
my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
|
||||||
int ci;
|
int ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
JSAMPARRAY in_ptr, out_ptr;
|
JSAMPARRAY in_ptr, out_ptr;
|
||||||
|
|
||||||
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
||||||
|
@ -142,14 +144,14 @@ sep_downsample (j_compress_ptr cinfo,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
int_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
||||||
{
|
{
|
||||||
int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
|
int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
|
||||||
JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
|
JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
|
||||||
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
|
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
|
||||||
JSAMPROW inptr, outptr;
|
JSAMPROW inptr, outptr;
|
||||||
INT32 outvalue;
|
JLONG outvalue;
|
||||||
|
|
||||||
h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
|
h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
|
||||||
v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor;
|
v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor;
|
||||||
|
@ -172,7 +174,7 @@ int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
for (v = 0; v < v_expand; v++) {
|
for (v = 0; v < v_expand; v++) {
|
||||||
inptr = input_data[inrow+v] + outcol_h;
|
inptr = input_data[inrow+v] + outcol_h;
|
||||||
for (h = 0; h < h_expand; h++) {
|
for (h = 0; h < h_expand; h++) {
|
||||||
outvalue += (INT32) GETJSAMPLE(*inptr++);
|
outvalue += (JLONG) GETJSAMPLE(*inptr++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
|
*outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
|
||||||
|
@ -189,7 +191,7 @@ int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
||||||
{
|
{
|
||||||
/* Copy the data */
|
/* Copy the data */
|
||||||
|
@ -214,7 +216,7 @@ fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
||||||
{
|
{
|
||||||
int outrow;
|
int outrow;
|
||||||
|
@ -251,7 +253,7 @@ h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
||||||
{
|
{
|
||||||
int inrow, outrow;
|
int inrow, outrow;
|
||||||
|
@ -294,14 +296,14 @@ h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
|
h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
JSAMPARRAY input_data, JSAMPARRAY output_data)
|
||||||
{
|
{
|
||||||
int inrow, outrow;
|
int inrow, outrow;
|
||||||
JDIMENSION colctr;
|
JDIMENSION colctr;
|
||||||
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
|
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
|
||||||
register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
|
register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
|
||||||
INT32 membersum, neighsum, memberscale, neighscale;
|
JLONG membersum, neighsum, memberscale, neighscale;
|
||||||
|
|
||||||
/* Expand input data enough to let all the output samples be generated
|
/* Expand input data enough to let all the output samples be generated
|
||||||
* by the standard loop. Special-casing padded output would be more
|
* by the standard loop. Special-casing padded output would be more
|
||||||
|
@ -401,7 +403,7 @@ fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JDIMENSION colctr;
|
JDIMENSION colctr;
|
||||||
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
|
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
|
||||||
register JSAMPROW inptr, above_ptr, below_ptr, outptr;
|
register JSAMPROW inptr, above_ptr, below_ptr, outptr;
|
||||||
INT32 membersum, neighsum, memberscale, neighscale;
|
JLONG membersum, neighsum, memberscale, neighscale;
|
||||||
int colsum, lastcolsum, nextcolsum;
|
int colsum, lastcolsum, nextcolsum;
|
||||||
|
|
||||||
/* Expand input data enough to let all the output samples be generated
|
/* Expand input data enough to let all the output samples be generated
|
||||||
|
@ -470,7 +472,7 @@ jinit_downsampler (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
my_downsample_ptr downsample;
|
my_downsample_ptr downsample;
|
||||||
int ci;
|
int ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
boolean smoothok = TRUE;
|
boolean smoothok = TRUE;
|
||||||
|
|
||||||
downsample = (my_downsample_ptr)
|
downsample = (my_downsample_ptr)
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
* Modified 2000-2009 by Guido Vollbeding.
|
* Modified 2000-2009 by Guido Vollbeding.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||||
* to libjpeg-turbo.
|
* to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains library routines for transcoding compression,
|
* This file contains library routines for transcoding compression,
|
||||||
* that is, writing raw DCT coefficient arrays to an output JPEG file.
|
* that is, writing raw DCT coefficient arrays to an output JPEG file.
|
||||||
|
@ -20,9 +21,9 @@
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
LOCAL(void) transencode_master_selection
|
LOCAL(void) transencode_master_selection
|
||||||
(j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays);
|
(j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays);
|
||||||
LOCAL(void) transencode_coef_controller
|
LOCAL(void) transencode_coef_controller
|
||||||
(j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays);
|
(j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -38,7 +39,7 @@ LOCAL(void) transencode_coef_controller
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
|
jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays)
|
||||||
{
|
{
|
||||||
if (cinfo->global_state != CSTATE_START)
|
if (cinfo->global_state != CSTATE_START)
|
||||||
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
|
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
|
||||||
|
@ -66,7 +67,7 @@ GLOBAL(void)
|
||||||
jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
|
jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
|
||||||
j_compress_ptr dstinfo)
|
j_compress_ptr dstinfo)
|
||||||
{
|
{
|
||||||
JQUANT_TBL ** qtblptr;
|
JQUANT_TBL **qtblptr;
|
||||||
jpeg_component_info *incomp, *outcomp;
|
jpeg_component_info *incomp, *outcomp;
|
||||||
JQUANT_TBL *c_quant, *slot_quant;
|
JQUANT_TBL *c_quant, *slot_quant;
|
||||||
int tblno, ci, coefi;
|
int tblno, ci, coefi;
|
||||||
|
@ -165,7 +166,7 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
transencode_master_selection (j_compress_ptr cinfo,
|
transencode_master_selection (j_compress_ptr cinfo,
|
||||||
jvirt_barray_ptr * coef_arrays)
|
jvirt_barray_ptr *coef_arrays)
|
||||||
{
|
{
|
||||||
/* Although we don't actually use input_components for transcoding,
|
/* Although we don't actually use input_components for transcoding,
|
||||||
* jcmaster.c's initial_setup will complain if input_components is 0.
|
* jcmaster.c's initial_setup will complain if input_components is 0.
|
||||||
|
@ -227,13 +228,13 @@ typedef struct {
|
||||||
int MCU_rows_per_iMCU_row; /* number of such rows needed */
|
int MCU_rows_per_iMCU_row; /* number of such rows needed */
|
||||||
|
|
||||||
/* Virtual block array for each component. */
|
/* Virtual block array for each component. */
|
||||||
jvirt_barray_ptr * whole_image;
|
jvirt_barray_ptr *whole_image;
|
||||||
|
|
||||||
/* Workspace for constructing dummy blocks at right/bottom edges. */
|
/* Workspace for constructing dummy blocks at right/bottom edges. */
|
||||||
JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
|
JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
|
||||||
} my_coef_controller;
|
} my_coef_controller;
|
||||||
|
|
||||||
typedef my_coef_controller * my_coef_ptr;
|
typedef my_coef_controller *my_coef_ptr;
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
|
@ -374,7 +375,7 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
transencode_coef_controller (j_compress_ptr cinfo,
|
transencode_coef_controller (j_compress_ptr cinfo,
|
||||||
jvirt_barray_ptr * coef_arrays)
|
jvirt_barray_ptr *coef_arrays)
|
||||||
{
|
{
|
||||||
my_coef_ptr coef;
|
my_coef_ptr coef;
|
||||||
JBLOCKROW buffer;
|
JBLOCKROW buffer;
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1998, Thomas G. Lane.
|
* Copyright (C) 1994-1998, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* libjpeg-turbo Modifications:
|
||||||
* to libjpeg-turbo.
|
* Copyright (C) 2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains application interface code for the decompression half
|
* This file contains application interface code for the decompression half
|
||||||
* of the JPEG library. These are the "minimum" API routines that may be
|
* of the JPEG library. These are the "minimum" API routines that may be
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
#define JPEG_INTERNALS
|
#define JPEG_INTERNALS
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jpeglib.h"
|
||||||
|
#include "jdmaster.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,6 +84,14 @@ jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
|
||||||
|
|
||||||
/* OK, I'm ready */
|
/* OK, I'm ready */
|
||||||
cinfo->global_state = DSTATE_START;
|
cinfo->global_state = DSTATE_START;
|
||||||
|
|
||||||
|
/* The master struct is used to store extension parameters, so we allocate it
|
||||||
|
* here.
|
||||||
|
*/
|
||||||
|
cinfo->master = (struct jpeg_decomp_master *)
|
||||||
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||||
|
sizeof(my_decomp_master));
|
||||||
|
MEMZERO(cinfo->master, sizeof(my_decomp_master));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright (C) 2010, 2015-2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2015, Google, Inc.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains application interface code for the decompression half
|
* This file contains application interface code for the decompression half
|
||||||
* of the JPEG library. These are the "standard" API routines that are
|
* of the JPEG library. These are the "standard" API routines that are
|
||||||
|
@ -16,11 +18,11 @@
|
||||||
* whole decompression library into a transcoder.
|
* whole decompression library into a transcoder.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define JPEG_INTERNALS
|
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jdmainct.h"
|
||||||
#include "jpegcomp.h"
|
#include "jdcoefct.h"
|
||||||
|
#include "jdsample.h"
|
||||||
|
#include "jmemsys.h"
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
LOCAL(boolean) output_pass_setup (j_decompress_ptr cinfo);
|
LOCAL(boolean) output_pass_setup (j_decompress_ptr cinfo);
|
||||||
|
@ -138,6 +140,110 @@ output_pass_setup (j_decompress_ptr cinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable partial scanline decompression
|
||||||
|
*
|
||||||
|
* Must be called after jpeg_start_decompress() and before any calls to
|
||||||
|
* jpeg_read_scanlines() or jpeg_skip_scanlines().
|
||||||
|
*
|
||||||
|
* Refer to libjpeg.txt for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
GLOBAL(void)
|
||||||
|
jpeg_crop_scanline (j_decompress_ptr cinfo, JDIMENSION *xoffset,
|
||||||
|
JDIMENSION *width)
|
||||||
|
{
|
||||||
|
int ci, align, orig_downsampled_width;
|
||||||
|
JDIMENSION input_xoffset;
|
||||||
|
boolean reinit_upsampler = FALSE;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
|
if (cinfo->global_state != DSTATE_SCANNING || cinfo->output_scanline != 0)
|
||||||
|
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
|
||||||
|
|
||||||
|
if (!xoffset || !width)
|
||||||
|
ERREXIT(cinfo, JERR_BAD_CROP_SPEC);
|
||||||
|
|
||||||
|
/* xoffset and width must fall within the output image dimensions. */
|
||||||
|
if (*width == 0 || *xoffset + *width > cinfo->output_width)
|
||||||
|
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
|
||||||
|
|
||||||
|
/* No need to do anything if the caller wants the entire width. */
|
||||||
|
if (*width == cinfo->output_width)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Ensuring the proper alignment of xoffset is tricky. At minimum, it
|
||||||
|
* must align with an MCU boundary, because:
|
||||||
|
*
|
||||||
|
* (1) The IDCT is performed in blocks, and it is not feasible to modify
|
||||||
|
* the algorithm so that it can transform partial blocks.
|
||||||
|
* (2) Because of the SIMD extensions, any input buffer passed to the
|
||||||
|
* upsampling and color conversion routines must be aligned to the
|
||||||
|
* SIMD word size (for instance, 128-bit in the case of SSE2.) The
|
||||||
|
* easiest way to accomplish this without copying data is to ensure
|
||||||
|
* that upsampling and color conversion begin at the start of the
|
||||||
|
* first MCU column that will be inverse transformed.
|
||||||
|
*
|
||||||
|
* In practice, we actually impose a stricter alignment requirement. We
|
||||||
|
* require that xoffset be a multiple of the maximum MCU column width of all
|
||||||
|
* of the components (the "iMCU column width.") This is to simplify the
|
||||||
|
* single-pass decompression case, allowing us to use the same MCU column
|
||||||
|
* width for all of the components.
|
||||||
|
*/
|
||||||
|
align = cinfo->_min_DCT_scaled_size * cinfo->max_h_samp_factor;
|
||||||
|
|
||||||
|
/* Adjust xoffset to the nearest iMCU boundary <= the requested value */
|
||||||
|
input_xoffset = *xoffset;
|
||||||
|
*xoffset = (input_xoffset / align) * align;
|
||||||
|
|
||||||
|
/* Adjust the width so that the right edge of the output image is as
|
||||||
|
* requested (only the left edge is altered.) It is important that calling
|
||||||
|
* programs check this value after this function returns, so that they can
|
||||||
|
* allocate an output buffer with the appropriate size.
|
||||||
|
*/
|
||||||
|
*width = *width + input_xoffset - *xoffset;
|
||||||
|
cinfo->output_width = *width;
|
||||||
|
|
||||||
|
/* Set the first and last iMCU columns that we must decompress. These values
|
||||||
|
* will be used in single-scan decompressions.
|
||||||
|
*/
|
||||||
|
cinfo->master->first_iMCU_col =
|
||||||
|
(JDIMENSION) (long) (*xoffset) / (long) align;
|
||||||
|
cinfo->master->last_iMCU_col =
|
||||||
|
(JDIMENSION) jdiv_round_up((long) (*xoffset + cinfo->output_width),
|
||||||
|
(long) align) - 1;
|
||||||
|
|
||||||
|
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
||||||
|
ci++, compptr++) {
|
||||||
|
/* Set downsampled_width to the new output width. */
|
||||||
|
orig_downsampled_width = compptr->downsampled_width;
|
||||||
|
compptr->downsampled_width =
|
||||||
|
(JDIMENSION) jdiv_round_up((long) (cinfo->output_width *
|
||||||
|
compptr->h_samp_factor),
|
||||||
|
(long) cinfo->max_h_samp_factor);
|
||||||
|
if (compptr->downsampled_width < 2 && orig_downsampled_width >= 2)
|
||||||
|
reinit_upsampler = TRUE;
|
||||||
|
|
||||||
|
/* Set the first and last iMCU columns that we must decompress. These
|
||||||
|
* values will be used in multi-scan decompressions.
|
||||||
|
*/
|
||||||
|
cinfo->master->first_MCU_col[ci] =
|
||||||
|
(JDIMENSION) (long) (*xoffset * compptr->h_samp_factor) /
|
||||||
|
(long) align;
|
||||||
|
cinfo->master->last_MCU_col[ci] =
|
||||||
|
(JDIMENSION) jdiv_round_up((long) ((*xoffset + cinfo->output_width) *
|
||||||
|
compptr->h_samp_factor),
|
||||||
|
(long) align) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reinit_upsampler) {
|
||||||
|
cinfo->master->jinit_upsampler_no_alloc = TRUE;
|
||||||
|
jinit_upsampler(cinfo);
|
||||||
|
cinfo->master->jinit_upsampler_no_alloc = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read some scanlines of data from the JPEG decompressor.
|
* Read some scanlines of data from the JPEG decompressor.
|
||||||
*
|
*
|
||||||
|
@ -179,6 +285,236 @@ jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Dummy color convert function used by jpeg_skip_scanlines() */
|
||||||
|
LOCAL(void)
|
||||||
|
noop_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||||
|
JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In some cases, it is best to call jpeg_read_scanlines() and discard the
|
||||||
|
* output, rather than skipping the scanlines, because this allows us to
|
||||||
|
* maintain the internal state of the context-based upsampler. In these cases,
|
||||||
|
* we set up and tear down a dummy color converter in order to avoid valgrind
|
||||||
|
* errors and to achieve the best possible performance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
read_and_discard_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines)
|
||||||
|
{
|
||||||
|
JDIMENSION n;
|
||||||
|
void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||||
|
JDIMENSION input_row, JSAMPARRAY output_buf,
|
||||||
|
int num_rows);
|
||||||
|
|
||||||
|
color_convert = cinfo->cconvert->color_convert;
|
||||||
|
cinfo->cconvert->color_convert = noop_convert;
|
||||||
|
|
||||||
|
for (n = 0; n < num_lines; n++)
|
||||||
|
jpeg_read_scanlines(cinfo, NULL, 1);
|
||||||
|
|
||||||
|
cinfo->cconvert->color_convert = color_convert;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by jpeg_skip_scanlines(). This partially skips a decompress block by
|
||||||
|
* incrementing the rowgroup counter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
increment_simple_rowgroup_ctr (j_decompress_ptr cinfo, JDIMENSION rows)
|
||||||
|
{
|
||||||
|
JDIMENSION rows_left;
|
||||||
|
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
|
||||||
|
|
||||||
|
/* Increment the counter to the next row group after the skipped rows. */
|
||||||
|
main_ptr->rowgroup_ctr += rows / cinfo->max_v_samp_factor;
|
||||||
|
|
||||||
|
/* Partially skipping a row group would involve modifying the internal state
|
||||||
|
* of the upsampler, so read the remaining rows into a dummy buffer instead.
|
||||||
|
*/
|
||||||
|
rows_left = rows % cinfo->max_v_samp_factor;
|
||||||
|
cinfo->output_scanline += rows - rows_left;
|
||||||
|
|
||||||
|
read_and_discard_scanlines(cinfo, rows_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skips some scanlines of data from the JPEG decompressor.
|
||||||
|
*
|
||||||
|
* The return value will be the number of lines actually skipped. If skipping
|
||||||
|
* num_lines would move beyond the end of the image, then the actual number of
|
||||||
|
* lines remaining in the image is returned. Otherwise, the return value will
|
||||||
|
* be equal to num_lines.
|
||||||
|
*
|
||||||
|
* Refer to libjpeg.txt for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
GLOBAL(JDIMENSION)
|
||||||
|
jpeg_skip_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines)
|
||||||
|
{
|
||||||
|
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
|
||||||
|
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
|
||||||
|
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
|
||||||
|
JDIMENSION i, x;
|
||||||
|
int y;
|
||||||
|
JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row;
|
||||||
|
JDIMENSION lines_to_skip, lines_to_read;
|
||||||
|
|
||||||
|
if (cinfo->global_state != DSTATE_SCANNING)
|
||||||
|
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
|
||||||
|
|
||||||
|
/* Do not skip past the bottom of the image. */
|
||||||
|
if (cinfo->output_scanline + num_lines >= cinfo->output_height) {
|
||||||
|
cinfo->output_scanline = cinfo->output_height;
|
||||||
|
return cinfo->output_height - cinfo->output_scanline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_lines == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
lines_per_iMCU_row = cinfo->_min_DCT_scaled_size * cinfo->max_v_samp_factor;
|
||||||
|
lines_left_in_iMCU_row =
|
||||||
|
(lines_per_iMCU_row - (cinfo->output_scanline % lines_per_iMCU_row)) %
|
||||||
|
lines_per_iMCU_row;
|
||||||
|
lines_after_iMCU_row = num_lines - lines_left_in_iMCU_row;
|
||||||
|
|
||||||
|
/* Skip the lines remaining in the current iMCU row. When upsampling
|
||||||
|
* requires context rows, we need the previous and next rows in order to read
|
||||||
|
* the current row. This adds some complexity.
|
||||||
|
*/
|
||||||
|
if (cinfo->upsample->need_context_rows) {
|
||||||
|
/* If the skipped lines would not move us past the current iMCU row, we
|
||||||
|
* read the lines and ignore them. There might be a faster way of doing
|
||||||
|
* this, but we are facing increasing complexity for diminishing returns.
|
||||||
|
* The increasing complexity would be a by-product of meddling with the
|
||||||
|
* state machine used to skip context rows. Near the end of an iMCU row,
|
||||||
|
* the next iMCU row may have already been entropy-decoded. In this unique
|
||||||
|
* case, we will read the next iMCU row if we cannot skip past it as well.
|
||||||
|
*/
|
||||||
|
if ((num_lines < lines_left_in_iMCU_row + 1) ||
|
||||||
|
(lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full &&
|
||||||
|
lines_after_iMCU_row < lines_per_iMCU_row + 1)) {
|
||||||
|
read_and_discard_scanlines(cinfo, num_lines);
|
||||||
|
return num_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the next iMCU row has already been entropy-decoded, make sure that
|
||||||
|
* we do not skip too far.
|
||||||
|
*/
|
||||||
|
if (lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full) {
|
||||||
|
cinfo->output_scanline += lines_left_in_iMCU_row + lines_per_iMCU_row;
|
||||||
|
lines_after_iMCU_row -= lines_per_iMCU_row;
|
||||||
|
} else {
|
||||||
|
cinfo->output_scanline += lines_left_in_iMCU_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have just completed the first block, adjust the buffer pointers */
|
||||||
|
if (main_ptr->iMCU_row_ctr == 0 ||
|
||||||
|
(main_ptr->iMCU_row_ctr == 1 && lines_left_in_iMCU_row > 2))
|
||||||
|
set_wraparound_pointers(cinfo);
|
||||||
|
main_ptr->buffer_full = FALSE;
|
||||||
|
main_ptr->rowgroup_ctr = 0;
|
||||||
|
main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
|
||||||
|
upsample->next_row_out = cinfo->max_v_samp_factor;
|
||||||
|
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skipping is much simpler when context rows are not required. */
|
||||||
|
else {
|
||||||
|
if (num_lines < lines_left_in_iMCU_row) {
|
||||||
|
increment_simple_rowgroup_ctr(cinfo, num_lines);
|
||||||
|
return num_lines;
|
||||||
|
} else {
|
||||||
|
cinfo->output_scanline += lines_left_in_iMCU_row;
|
||||||
|
main_ptr->buffer_full = FALSE;
|
||||||
|
main_ptr->rowgroup_ctr = 0;
|
||||||
|
upsample->next_row_out = cinfo->max_v_samp_factor;
|
||||||
|
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate how many full iMCU rows we can skip. */
|
||||||
|
if (cinfo->upsample->need_context_rows)
|
||||||
|
lines_to_skip = ((lines_after_iMCU_row - 1) / lines_per_iMCU_row) *
|
||||||
|
lines_per_iMCU_row;
|
||||||
|
else
|
||||||
|
lines_to_skip = (lines_after_iMCU_row / lines_per_iMCU_row) *
|
||||||
|
lines_per_iMCU_row;
|
||||||
|
/* Calculate the number of lines that remain to be skipped after skipping all
|
||||||
|
* of the full iMCU rows that we can. We will not read these lines unless we
|
||||||
|
* have to.
|
||||||
|
*/
|
||||||
|
lines_to_read = lines_after_iMCU_row - lines_to_skip;
|
||||||
|
|
||||||
|
/* For images requiring multiple scans (progressive, non-interleaved, etc.),
|
||||||
|
* all of the entropy decoding occurs in jpeg_start_decompress(), assuming
|
||||||
|
* that the input data source is non-suspending. This makes skipping easy.
|
||||||
|
*/
|
||||||
|
if (cinfo->inputctl->has_multiple_scans) {
|
||||||
|
if (cinfo->upsample->need_context_rows) {
|
||||||
|
cinfo->output_scanline += lines_to_skip;
|
||||||
|
cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row;
|
||||||
|
main_ptr->iMCU_row_ctr += lines_after_iMCU_row / lines_per_iMCU_row;
|
||||||
|
/* It is complex to properly move to the middle of a context block, so
|
||||||
|
* read the remaining lines instead of skipping them.
|
||||||
|
*/
|
||||||
|
read_and_discard_scanlines(cinfo, lines_to_read);
|
||||||
|
} else {
|
||||||
|
cinfo->output_scanline += lines_to_skip;
|
||||||
|
cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row;
|
||||||
|
increment_simple_rowgroup_ctr(cinfo, lines_to_read);
|
||||||
|
}
|
||||||
|
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
|
||||||
|
return num_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip the iMCU rows that we can safely skip. */
|
||||||
|
for (i = 0; i < lines_to_skip; i += lines_per_iMCU_row) {
|
||||||
|
for (y = 0; y < coef->MCU_rows_per_iMCU_row; y++) {
|
||||||
|
for (x = 0; x < cinfo->MCUs_per_row; x++) {
|
||||||
|
/* Calling decode_mcu() with a NULL pointer causes it to discard the
|
||||||
|
* decoded coefficients. This is ~5% faster for large subsets, but
|
||||||
|
* it's tough to tell a difference for smaller images.
|
||||||
|
*/
|
||||||
|
(*cinfo->entropy->decode_mcu) (cinfo, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cinfo->input_iMCU_row++;
|
||||||
|
cinfo->output_iMCU_row++;
|
||||||
|
if (cinfo->input_iMCU_row < cinfo->total_iMCU_rows)
|
||||||
|
start_iMCU_row(cinfo);
|
||||||
|
else
|
||||||
|
(*cinfo->inputctl->finish_input_pass) (cinfo);
|
||||||
|
}
|
||||||
|
cinfo->output_scanline += lines_to_skip;
|
||||||
|
|
||||||
|
if (cinfo->upsample->need_context_rows) {
|
||||||
|
/* Context-based upsampling keeps track of iMCU rows. */
|
||||||
|
main_ptr->iMCU_row_ctr += lines_to_skip / lines_per_iMCU_row;
|
||||||
|
|
||||||
|
/* It is complex to properly move to the middle of a context block, so
|
||||||
|
* read the remaining lines instead of skipping them.
|
||||||
|
*/
|
||||||
|
read_and_discard_scanlines(cinfo, lines_to_read);
|
||||||
|
} else {
|
||||||
|
increment_simple_rowgroup_ctr(cinfo, lines_to_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Since skipping lines involves skipping the upsampling step, the value of
|
||||||
|
* "rows_to_go" will become invalid unless we set it here. NOTE: This is a
|
||||||
|
* bit odd, since "rows_to_go" seems to be redundantly keeping track of
|
||||||
|
* output_scanline.
|
||||||
|
*/
|
||||||
|
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
|
||||||
|
|
||||||
|
/* Always skip the requested number of lines. */
|
||||||
|
return num_lines;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Alternate entry point to read raw data.
|
* Alternate entry point to read raw data.
|
||||||
* Processes exactly one iMCU row per call, unless suspended.
|
* Processes exactly one iMCU row per call, unless suspended.
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
* jdarith.c
|
* jdarith.c
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Developed 1997-2009 by Guido Vollbeding.
|
* Developed 1997-2015 by Guido Vollbeding.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* libjpeg-turbo Modifications:
|
||||||
* to libjpeg-turbo.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains portable arithmetic entropy decoding routines for JPEG
|
* This file contains portable arithmetic entropy decoding routines for JPEG
|
||||||
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
|
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
|
||||||
|
@ -25,8 +26,8 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct jpeg_entropy_decoder pub; /* public fields */
|
struct jpeg_entropy_decoder pub; /* public fields */
|
||||||
|
|
||||||
INT32 c; /* C register, base of coding interval + input bit buffer */
|
JLONG c; /* C register, base of coding interval + input bit buffer */
|
||||||
INT32 a; /* A register, normalized size of coding interval */
|
JLONG a; /* A register, normalized size of coding interval */
|
||||||
int ct; /* bit shift counter, # of bits left in bit buffer part of C */
|
int ct; /* bit shift counter, # of bits left in bit buffer part of C */
|
||||||
/* init: ct = -16 */
|
/* init: ct = -16 */
|
||||||
/* run: ct = 0..7 */
|
/* run: ct = 0..7 */
|
||||||
|
@ -37,14 +38,14 @@ typedef struct {
|
||||||
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
||||||
|
|
||||||
/* Pointers to statistics areas (these workspaces have image lifespan) */
|
/* Pointers to statistics areas (these workspaces have image lifespan) */
|
||||||
unsigned char * dc_stats[NUM_ARITH_TBLS];
|
unsigned char *dc_stats[NUM_ARITH_TBLS];
|
||||||
unsigned char * ac_stats[NUM_ARITH_TBLS];
|
unsigned char *ac_stats[NUM_ARITH_TBLS];
|
||||||
|
|
||||||
/* Statistics bin for coding with fixed probability 0.5 */
|
/* Statistics bin for coding with fixed probability 0.5 */
|
||||||
unsigned char fixed_bin[4];
|
unsigned char fixed_bin[4];
|
||||||
} arith_entropy_decoder;
|
} arith_entropy_decoder;
|
||||||
|
|
||||||
typedef arith_entropy_decoder * arith_entropy_ptr;
|
typedef arith_entropy_decoder *arith_entropy_ptr;
|
||||||
|
|
||||||
/* The following two definitions specify the allocation chunk size
|
/* The following two definitions specify the allocation chunk size
|
||||||
* for the statistics area.
|
* for the statistics area.
|
||||||
|
@ -67,7 +68,7 @@ LOCAL(int)
|
||||||
get_byte (j_decompress_ptr cinfo)
|
get_byte (j_decompress_ptr cinfo)
|
||||||
/* Read next input byte; we do not support suspension in this module. */
|
/* Read next input byte; we do not support suspension in this module. */
|
||||||
{
|
{
|
||||||
struct jpeg_source_mgr * src = cinfo->src;
|
struct jpeg_source_mgr *src = cinfo->src;
|
||||||
|
|
||||||
if (src->bytes_in_buffer == 0)
|
if (src->bytes_in_buffer == 0)
|
||||||
if (! (*src->fill_input_buffer) (cinfo))
|
if (! (*src->fill_input_buffer) (cinfo))
|
||||||
|
@ -96,7 +97,7 @@ get_byte (j_decompress_ptr cinfo)
|
||||||
* (instead of fixed) with the bit shift counter CT.
|
* (instead of fixed) with the bit shift counter CT.
|
||||||
* Thus, we also need only one (variable instead of
|
* Thus, we also need only one (variable instead of
|
||||||
* fixed size) shift for the LPS/MPS decision, and
|
* fixed size) shift for the LPS/MPS decision, and
|
||||||
* we can get away with any renormalization update
|
* we can do away with any renormalization update
|
||||||
* of C (except for new data insertion, of course).
|
* of C (except for new data insertion, of course).
|
||||||
*
|
*
|
||||||
* I've also introduced a new scheme for accessing
|
* I've also introduced a new scheme for accessing
|
||||||
|
@ -109,7 +110,7 @@ arith_decode (j_decompress_ptr cinfo, unsigned char *st)
|
||||||
{
|
{
|
||||||
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
|
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
|
||||||
register unsigned char nl, nm;
|
register unsigned char nl, nm;
|
||||||
register INT32 qe, temp;
|
register JLONG qe, temp;
|
||||||
register int sv, data;
|
register int sv, data;
|
||||||
|
|
||||||
/* Renormalization & data input per section D.2.6 */
|
/* Renormalization & data input per section D.2.6 */
|
||||||
|
@ -193,7 +194,7 @@ process_restart (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
||||||
int ci;
|
int ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
/* Advance past the RSTn marker */
|
/* Advance past the RSTn marker */
|
||||||
if (! (*cinfo->marker->read_restart_marker) (cinfo))
|
if (! (*cinfo->marker->read_restart_marker) (cinfo))
|
||||||
|
@ -202,13 +203,13 @@ process_restart (j_decompress_ptr cinfo)
|
||||||
/* Re-initialize statistics areas */
|
/* Re-initialize statistics areas */
|
||||||
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
||||||
compptr = cinfo->cur_comp_info[ci];
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
|
if (!cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
|
||||||
MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
|
MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
|
||||||
/* Reset DC predictions to 0 */
|
/* Reset DC predictions to 0 */
|
||||||
entropy->last_dc_val[ci] = 0;
|
entropy->last_dc_val[ci] = 0;
|
||||||
entropy->dc_context[ci] = 0;
|
entropy->dc_context[ci] = 0;
|
||||||
}
|
}
|
||||||
if (! cinfo->progressive_mode || cinfo->Ss) {
|
if (!cinfo->progressive_mode || cinfo->Ss) {
|
||||||
MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
|
MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,7 +499,7 @@ METHODDEF(boolean)
|
||||||
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
{
|
{
|
||||||
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
JBLOCKROW block;
|
JBLOCKROW block;
|
||||||
unsigned char *st;
|
unsigned char *st;
|
||||||
int blkn, ci, tbl, sign, k;
|
int blkn, ci, tbl, sign, k;
|
||||||
|
@ -516,7 +517,7 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
/* Outer loop handles each block in the MCU */
|
/* Outer loop handles each block in the MCU */
|
||||||
|
|
||||||
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||||
block = MCU_data[blkn];
|
block = MCU_data ? MCU_data[blkn] : NULL;
|
||||||
ci = cinfo->MCU_membership[blkn];
|
ci = cinfo->MCU_membership[blkn];
|
||||||
compptr = cinfo->cur_comp_info[ci];
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
|
|
||||||
|
@ -563,7 +564,8 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
entropy->last_dc_val[ci] += v;
|
entropy->last_dc_val[ci] += v;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*block)[0] = (JCOEF) entropy->last_dc_val[ci];
|
if (block)
|
||||||
|
(*block)[0] = (JCOEF) entropy->last_dc_val[ci];
|
||||||
|
|
||||||
/* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
|
/* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
|
||||||
|
|
||||||
|
@ -607,7 +609,8 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
while (m >>= 1)
|
while (m >>= 1)
|
||||||
if (arith_decode(cinfo, st)) v |= m;
|
if (arith_decode(cinfo, st)) v |= m;
|
||||||
v += 1; if (sign) v = -v;
|
v += 1; if (sign) v = -v;
|
||||||
(*block)[jpeg_natural_order[k]] = (JCOEF) v;
|
if (block)
|
||||||
|
(*block)[jpeg_natural_order[k]] = (JCOEF) v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,7 +627,7 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
|
||||||
int ci, tbl;
|
int ci, tbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
if (cinfo->progressive_mode) {
|
if (cinfo->progressive_mode) {
|
||||||
/* Validate progressive scan parameters */
|
/* Validate progressive scan parameters */
|
||||||
|
@ -691,7 +694,7 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
/* Allocate & initialize requested statistics areas */
|
/* Allocate & initialize requested statistics areas */
|
||||||
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
||||||
compptr = cinfo->cur_comp_info[ci];
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
|
if (!cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
|
||||||
tbl = compptr->dc_tbl_no;
|
tbl = compptr->dc_tbl_no;
|
||||||
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
|
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
|
||||||
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
|
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
|
||||||
|
@ -703,7 +706,7 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
entropy->last_dc_val[ci] = 0;
|
entropy->last_dc_val[ci] = 0;
|
||||||
entropy->dc_context[ci] = 0;
|
entropy->dc_context[ci] = 0;
|
||||||
}
|
}
|
||||||
if (! cinfo->progressive_mode || cinfo->Ss) {
|
if (!cinfo->progressive_mode || cinfo->Ss) {
|
||||||
tbl = compptr->ac_tbl_no;
|
tbl = compptr->ac_tbl_no;
|
||||||
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
|
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
|
||||||
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
|
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* Modified 2009-2012 by Guido Vollbeding.
|
* Modified 2009-2012 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2013, D. R. Commander.
|
* Copyright (C) 2013, 2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains compression data destination routines for the case of
|
* This file contains compression data destination routines for the case of
|
||||||
* emitting JPEG data to memory or to a file (or any stdio stream).
|
* emitting JPEG data to memory or to a file (or any stdio stream).
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
#include "jerror.h"
|
#include "jerror.h"
|
||||||
|
|
||||||
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
|
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
|
||||||
extern void * malloc (size_t size);
|
extern void *malloc (size_t size);
|
||||||
extern void free (void *ptr);
|
extern void free (void *ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -33,11 +34,11 @@ extern void free (void *ptr);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct jpeg_destination_mgr pub; /* public fields */
|
struct jpeg_destination_mgr pub; /* public fields */
|
||||||
|
|
||||||
FILE * outfile; /* target stream */
|
FILE *outfile; /* target stream */
|
||||||
JOCTET * buffer; /* start of buffer */
|
JOCTET *buffer; /* start of buffer */
|
||||||
} my_destination_mgr;
|
} my_destination_mgr;
|
||||||
|
|
||||||
typedef my_destination_mgr * my_dest_ptr;
|
typedef my_destination_mgr *my_dest_ptr;
|
||||||
|
|
||||||
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
|
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
|
||||||
|
|
||||||
|
@ -48,14 +49,14 @@ typedef my_destination_mgr * my_dest_ptr;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct jpeg_destination_mgr pub; /* public fields */
|
struct jpeg_destination_mgr pub; /* public fields */
|
||||||
|
|
||||||
unsigned char ** outbuffer; /* target buffer */
|
unsigned char **outbuffer; /* target buffer */
|
||||||
unsigned long * outsize;
|
unsigned long *outsize;
|
||||||
unsigned char * newbuffer; /* newly allocated buffer */
|
unsigned char *newbuffer; /* newly allocated buffer */
|
||||||
JOCTET * buffer; /* start of buffer */
|
JOCTET *buffer; /* start of buffer */
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
} my_mem_destination_mgr;
|
} my_mem_destination_mgr;
|
||||||
|
|
||||||
typedef my_mem_destination_mgr * my_mem_dest_ptr;
|
typedef my_mem_destination_mgr *my_mem_dest_ptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ METHODDEF(boolean)
|
||||||
empty_mem_output_buffer (j_compress_ptr cinfo)
|
empty_mem_output_buffer (j_compress_ptr cinfo)
|
||||||
{
|
{
|
||||||
size_t nextsize;
|
size_t nextsize;
|
||||||
JOCTET * nextbuffer;
|
JOCTET *nextbuffer;
|
||||||
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
|
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
|
||||||
|
|
||||||
/* Try to allocate new buffer with double size */
|
/* Try to allocate new buffer with double size */
|
||||||
|
@ -203,20 +204,25 @@ term_mem_destination (j_compress_ptr cinfo)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
|
jpeg_stdio_dest (j_compress_ptr cinfo, FILE *outfile)
|
||||||
{
|
{
|
||||||
my_dest_ptr dest;
|
my_dest_ptr dest;
|
||||||
|
|
||||||
/* The destination object is made permanent so that multiple JPEG images
|
/* The destination object is made permanent so that multiple JPEG images
|
||||||
* can be written to the same file without re-executing jpeg_stdio_dest.
|
* can be written to the same file without re-executing jpeg_stdio_dest.
|
||||||
* This makes it dangerous to use this manager and a different destination
|
|
||||||
* manager serially with the same JPEG object, because their private object
|
|
||||||
* sizes may be different. Caveat programmer.
|
|
||||||
*/
|
*/
|
||||||
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
|
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
|
||||||
cinfo->dest = (struct jpeg_destination_mgr *)
|
cinfo->dest = (struct jpeg_destination_mgr *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||||
sizeof(my_destination_mgr));
|
sizeof(my_destination_mgr));
|
||||||
|
} else if (cinfo->dest->init_destination != init_destination) {
|
||||||
|
/* It is unsafe to reuse the existing destination manager unless it was
|
||||||
|
* created by this function. Otherwise, there is no guarantee that the
|
||||||
|
* opaque structure is the right size. Note that we could just create a
|
||||||
|
* new structure, but the old structure would not be freed until
|
||||||
|
* jpeg_destroy_compress() was called.
|
||||||
|
*/
|
||||||
|
ERREXIT(cinfo, JERR_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = (my_dest_ptr) cinfo->dest;
|
dest = (my_dest_ptr) cinfo->dest;
|
||||||
|
@ -237,11 +243,14 @@ jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
|
||||||
* larger memory, so the buffer is available to the application after
|
* larger memory, so the buffer is available to the application after
|
||||||
* finishing compression, and then the application is responsible for
|
* finishing compression, and then the application is responsible for
|
||||||
* freeing the requested memory.
|
* freeing the requested memory.
|
||||||
|
* Note: An initial buffer supplied by the caller is expected to be
|
||||||
|
* managed by the application. The library does not free such buffer
|
||||||
|
* when allocating a larger buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_mem_dest (j_compress_ptr cinfo,
|
jpeg_mem_dest (j_compress_ptr cinfo,
|
||||||
unsigned char ** outbuffer, unsigned long * outsize)
|
unsigned char **outbuffer, unsigned long *outsize)
|
||||||
{
|
{
|
||||||
my_mem_dest_ptr dest;
|
my_mem_dest_ptr dest;
|
||||||
|
|
||||||
|
@ -255,6 +264,11 @@ jpeg_mem_dest (j_compress_ptr cinfo,
|
||||||
cinfo->dest = (struct jpeg_destination_mgr *)
|
cinfo->dest = (struct jpeg_destination_mgr *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||||
sizeof(my_mem_destination_mgr));
|
sizeof(my_mem_destination_mgr));
|
||||||
|
} else if (cinfo->dest->init_destination != init_mem_destination) {
|
||||||
|
/* It is unsafe to reuse the existing destination manager unless it was
|
||||||
|
* created by this function.
|
||||||
|
*/
|
||||||
|
ERREXIT(cinfo, JERR_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = (my_mem_dest_ptr) cinfo->dest;
|
dest = (my_mem_dest_ptr) cinfo->dest;
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* Modified 2009-2011 by Guido Vollbeding.
|
* Modified 2009-2011 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2013, D. R. Commander.
|
* Copyright (C) 2013, 2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains decompression data source routines for the case of
|
* This file contains decompression data source routines for the case of
|
||||||
* reading JPEG data from memory or from a file (or any stdio stream).
|
* reading JPEG data from memory or from a file (or any stdio stream).
|
||||||
|
@ -28,12 +29,12 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct jpeg_source_mgr pub; /* public fields */
|
struct jpeg_source_mgr pub; /* public fields */
|
||||||
|
|
||||||
FILE * infile; /* source stream */
|
FILE *infile; /* source stream */
|
||||||
JOCTET * buffer; /* start of buffer */
|
JOCTET *buffer; /* start of buffer */
|
||||||
boolean start_of_file; /* have we gotten any data yet? */
|
boolean start_of_file; /* have we gotten any data yet? */
|
||||||
} my_source_mgr;
|
} my_source_mgr;
|
||||||
|
|
||||||
typedef my_source_mgr * my_src_ptr;
|
typedef my_source_mgr *my_src_ptr;
|
||||||
|
|
||||||
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
|
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
|
||||||
|
|
||||||
|
@ -161,7 +162,7 @@ fill_mem_input_buffer (j_decompress_ptr cinfo)
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
|
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
|
||||||
{
|
{
|
||||||
struct jpeg_source_mgr * src = cinfo->src;
|
struct jpeg_source_mgr *src = cinfo->src;
|
||||||
|
|
||||||
/* Just a dumb implementation for now. Could use fseek() except
|
/* Just a dumb implementation for now. Could use fseek() except
|
||||||
* it doesn't work on pipes. Not clear that being smart is worth
|
* it doesn't work on pipes. Not clear that being smart is worth
|
||||||
|
@ -213,7 +214,7 @@ term_source (j_decompress_ptr cinfo)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
|
jpeg_stdio_src (j_decompress_ptr cinfo, FILE *infile)
|
||||||
{
|
{
|
||||||
my_src_ptr src;
|
my_src_ptr src;
|
||||||
|
|
||||||
|
@ -221,8 +222,6 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
|
||||||
* of JPEG images can be read from the same file by calling jpeg_stdio_src
|
* of JPEG images can be read from the same file by calling jpeg_stdio_src
|
||||||
* only before the first one. (If we discarded the buffer at the end of
|
* only before the first one. (If we discarded the buffer at the end of
|
||||||
* one image, we'd likely lose the start of the next one.)
|
* one image, we'd likely lose the start of the next one.)
|
||||||
* This makes it unsafe to use this manager and a different source
|
|
||||||
* manager serially with the same JPEG object. Caveat programmer.
|
|
||||||
*/
|
*/
|
||||||
if (cinfo->src == NULL) { /* first time for this JPEG object? */
|
if (cinfo->src == NULL) { /* first time for this JPEG object? */
|
||||||
cinfo->src = (struct jpeg_source_mgr *)
|
cinfo->src = (struct jpeg_source_mgr *)
|
||||||
|
@ -232,6 +231,14 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
|
||||||
src->buffer = (JOCTET *)
|
src->buffer = (JOCTET *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||||
INPUT_BUF_SIZE * sizeof(JOCTET));
|
INPUT_BUF_SIZE * sizeof(JOCTET));
|
||||||
|
} else if (cinfo->src->init_source != init_source) {
|
||||||
|
/* It is unsafe to reuse the existing source manager unless it was created
|
||||||
|
* by this function. Otherwise, there is no guarantee that the opaque
|
||||||
|
* structure is the right size. Note that we could just create a new
|
||||||
|
* structure, but the old structure would not be freed until
|
||||||
|
* jpeg_destroy_decompress() was called.
|
||||||
|
*/
|
||||||
|
ERREXIT(cinfo, JERR_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
src = (my_src_ptr) cinfo->src;
|
src = (my_src_ptr) cinfo->src;
|
||||||
|
@ -254,9 +261,9 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_mem_src (j_decompress_ptr cinfo,
|
jpeg_mem_src (j_decompress_ptr cinfo,
|
||||||
unsigned char * inbuffer, unsigned long insize)
|
const unsigned char *inbuffer, unsigned long insize)
|
||||||
{
|
{
|
||||||
struct jpeg_source_mgr * src;
|
struct jpeg_source_mgr *src;
|
||||||
|
|
||||||
if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */
|
if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */
|
||||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||||
|
@ -269,6 +276,11 @@ jpeg_mem_src (j_decompress_ptr cinfo,
|
||||||
cinfo->src = (struct jpeg_source_mgr *)
|
cinfo->src = (struct jpeg_source_mgr *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||||
sizeof(struct jpeg_source_mgr));
|
sizeof(struct jpeg_source_mgr));
|
||||||
|
} else if (cinfo->src->init_source != init_mem_source) {
|
||||||
|
/* It is unsafe to reuse the existing source manager unless it was created
|
||||||
|
* by this function.
|
||||||
|
*/
|
||||||
|
ERREXIT(cinfo, JERR_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
src = cinfo->src;
|
src = cinfo->src;
|
||||||
|
@ -278,6 +290,6 @@ jpeg_mem_src (j_decompress_ptr cinfo,
|
||||||
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
|
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
|
||||||
src->term_source = term_source;
|
src->term_source = term_source;
|
||||||
src->bytes_in_buffer = (size_t) insize;
|
src->bytes_in_buffer = (size_t) insize;
|
||||||
src->next_input_byte = (JOCTET *) inbuffer;
|
src->next_input_byte = (const JOCTET *) inbuffer;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2010, 2015-2016, D. R. Commander.
|
||||||
|
* Copyright (C) 2015, Google, Inc.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the coefficient buffer controller for decompression.
|
* This file contains the coefficient buffer controller for decompression.
|
||||||
* This controller is the top level of the JPEG decompressor proper.
|
* This controller is the top level of the JPEG decompressor proper.
|
||||||
|
@ -16,53 +19,10 @@
|
||||||
* Also, the input side (only) is used when reading a file for transcoding.
|
* Also, the input side (only) is used when reading a file for transcoding.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define JPEG_INTERNALS
|
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jdcoefct.h"
|
||||||
#include "jpegcomp.h"
|
#include "jpegcomp.h"
|
||||||
|
|
||||||
/* Block smoothing is only applicable for progressive JPEG, so: */
|
|
||||||
#ifndef D_PROGRESSIVE_SUPPORTED
|
|
||||||
#undef BLOCK_SMOOTHING_SUPPORTED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Private buffer controller object */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct jpeg_d_coef_controller pub; /* public fields */
|
|
||||||
|
|
||||||
/* These variables keep track of the current location of the input side. */
|
|
||||||
/* cinfo->input_iMCU_row is also used for this. */
|
|
||||||
JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
|
|
||||||
int MCU_vert_offset; /* counts MCU rows within iMCU row */
|
|
||||||
int MCU_rows_per_iMCU_row; /* number of such rows needed */
|
|
||||||
|
|
||||||
/* The output side's location is represented by cinfo->output_iMCU_row. */
|
|
||||||
|
|
||||||
/* In single-pass modes, it's sufficient to buffer just one MCU.
|
|
||||||
* We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
|
|
||||||
* and let the entropy decoder write into that workspace each time.
|
|
||||||
* In multi-pass modes, this array points to the current MCU's blocks
|
|
||||||
* within the virtual arrays; it is used only by the input side.
|
|
||||||
*/
|
|
||||||
JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
|
|
||||||
|
|
||||||
/* Temporary workspace for one MCU */
|
|
||||||
JCOEF * workspace;
|
|
||||||
|
|
||||||
#ifdef D_MULTISCAN_FILES_SUPPORTED
|
|
||||||
/* In multi-pass modes, we need a virtual block array for each component. */
|
|
||||||
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BLOCK_SMOOTHING_SUPPORTED
|
|
||||||
/* When doing block smoothing, we latch coefficient Al values here */
|
|
||||||
int * coef_bits_latch;
|
|
||||||
#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
|
|
||||||
#endif
|
|
||||||
} my_coef_controller;
|
|
||||||
|
|
||||||
typedef my_coef_controller * my_coef_ptr;
|
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
METHODDEF(int) decompress_onepass
|
METHODDEF(int) decompress_onepass
|
||||||
|
@ -78,30 +38,6 @@ METHODDEF(int) decompress_smooth_data
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
|
||||||
start_iMCU_row (j_decompress_ptr cinfo)
|
|
||||||
/* Reset within-iMCU-row counters for a new row (input side) */
|
|
||||||
{
|
|
||||||
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
|
|
||||||
|
|
||||||
/* In an interleaved scan, an MCU row is the same as an iMCU row.
|
|
||||||
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
|
|
||||||
* But at the bottom of the image, process only what's left.
|
|
||||||
*/
|
|
||||||
if (cinfo->comps_in_scan > 1) {
|
|
||||||
coef->MCU_rows_per_iMCU_row = 1;
|
|
||||||
} else {
|
|
||||||
if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
|
|
||||||
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
|
|
||||||
else
|
|
||||||
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
coef->MCU_ctr = 0;
|
|
||||||
coef->MCU_vert_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize for an input processing pass.
|
* Initialize for an input processing pass.
|
||||||
*/
|
*/
|
||||||
|
@ -173,38 +109,46 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||||
coef->MCU_ctr = MCU_col_num;
|
coef->MCU_ctr = MCU_col_num;
|
||||||
return JPEG_SUSPENDED;
|
return JPEG_SUSPENDED;
|
||||||
}
|
}
|
||||||
/* Determine where data should go in output_buf and do the IDCT thing.
|
|
||||||
* We skip dummy blocks at the right and bottom edges (but blkn gets
|
/* Only perform the IDCT on blocks that are contained within the desired
|
||||||
* incremented past them!). Note the inner loop relies on having
|
* cropping region.
|
||||||
* allocated the MCU_buffer[] blocks sequentially.
|
|
||||||
*/
|
*/
|
||||||
blkn = 0; /* index of current DCT block within MCU */
|
if (MCU_col_num >= cinfo->master->first_iMCU_col &&
|
||||||
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
MCU_col_num <= cinfo->master->last_iMCU_col) {
|
||||||
compptr = cinfo->cur_comp_info[ci];
|
/* Determine where data should go in output_buf and do the IDCT thing.
|
||||||
/* Don't bother to IDCT an uninteresting component. */
|
* We skip dummy blocks at the right and bottom edges (but blkn gets
|
||||||
if (! compptr->component_needed) {
|
* incremented past them!). Note the inner loop relies on having
|
||||||
blkn += compptr->MCU_blocks;
|
* allocated the MCU_buffer[] blocks sequentially.
|
||||||
continue;
|
*/
|
||||||
}
|
blkn = 0; /* index of current DCT block within MCU */
|
||||||
inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
|
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
||||||
useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
: compptr->last_col_width;
|
/* Don't bother to IDCT an uninteresting component. */
|
||||||
output_ptr = output_buf[compptr->component_index] +
|
if (! compptr->component_needed) {
|
||||||
yoffset * compptr->_DCT_scaled_size;
|
blkn += compptr->MCU_blocks;
|
||||||
start_col = MCU_col_num * compptr->MCU_sample_width;
|
continue;
|
||||||
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
|
}
|
||||||
if (cinfo->input_iMCU_row < last_iMCU_row ||
|
inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
|
||||||
yoffset+yindex < compptr->last_row_height) {
|
useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
|
||||||
output_col = start_col;
|
: compptr->last_col_width;
|
||||||
for (xindex = 0; xindex < useful_width; xindex++) {
|
output_ptr = output_buf[compptr->component_index] +
|
||||||
(*inverse_DCT) (cinfo, compptr,
|
yoffset * compptr->_DCT_scaled_size;
|
||||||
(JCOEFPTR) coef->MCU_buffer[blkn+xindex],
|
start_col = (MCU_col_num - cinfo->master->first_iMCU_col) *
|
||||||
output_ptr, output_col);
|
compptr->MCU_sample_width;
|
||||||
output_col += compptr->_DCT_scaled_size;
|
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
|
||||||
}
|
if (cinfo->input_iMCU_row < last_iMCU_row ||
|
||||||
|
yoffset+yindex < compptr->last_row_height) {
|
||||||
|
output_col = start_col;
|
||||||
|
for (xindex = 0; xindex < useful_width; xindex++) {
|
||||||
|
(*inverse_DCT) (cinfo, compptr,
|
||||||
|
(JCOEFPTR) coef->MCU_buffer[blkn+xindex],
|
||||||
|
output_ptr, output_col);
|
||||||
|
output_col += compptr->_DCT_scaled_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blkn += compptr->MCU_width;
|
||||||
|
output_ptr += compptr->_DCT_scaled_size;
|
||||||
}
|
}
|
||||||
blkn += compptr->MCU_width;
|
|
||||||
output_ptr += compptr->_DCT_scaled_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,9 +303,10 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||||
output_ptr = output_buf[ci];
|
output_ptr = output_buf[ci];
|
||||||
/* Loop over all DCT blocks to be processed. */
|
/* Loop over all DCT blocks to be processed. */
|
||||||
for (block_row = 0; block_row < block_rows; block_row++) {
|
for (block_row = 0; block_row < block_rows; block_row++) {
|
||||||
buffer_ptr = buffer[block_row];
|
buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci];
|
||||||
output_col = 0;
|
output_col = 0;
|
||||||
for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
|
for (block_num = cinfo->master->first_MCU_col[ci];
|
||||||
|
block_num <= cinfo->master->last_MCU_col[ci]; block_num++) {
|
||||||
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
|
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
|
||||||
output_ptr, output_col);
|
output_ptr, output_col);
|
||||||
buffer_ptr++;
|
buffer_ptr++;
|
||||||
|
@ -411,9 +356,9 @@ smoothing_ok (j_decompress_ptr cinfo)
|
||||||
boolean smoothing_useful = FALSE;
|
boolean smoothing_useful = FALSE;
|
||||||
int ci, coefi;
|
int ci, coefi;
|
||||||
jpeg_component_info *compptr;
|
jpeg_component_info *compptr;
|
||||||
JQUANT_TBL * qtable;
|
JQUANT_TBL *qtable;
|
||||||
int * coef_bits;
|
int *coef_bits;
|
||||||
int * coef_bits_latch;
|
int *coef_bits_latch;
|
||||||
|
|
||||||
if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
|
if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -474,10 +419,10 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||||
jpeg_component_info *compptr;
|
jpeg_component_info *compptr;
|
||||||
inverse_DCT_method_ptr inverse_DCT;
|
inverse_DCT_method_ptr inverse_DCT;
|
||||||
boolean first_row, last_row;
|
boolean first_row, last_row;
|
||||||
JCOEF * workspace;
|
JCOEF *workspace;
|
||||||
int *coef_bits;
|
int *coef_bits;
|
||||||
JQUANT_TBL *quanttbl;
|
JQUANT_TBL *quanttbl;
|
||||||
INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
|
JLONG Q00,Q01,Q02,Q10,Q11,Q20, num;
|
||||||
int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
|
int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
|
||||||
int Al, pred;
|
int Al, pred;
|
||||||
|
|
||||||
|
@ -547,7 +492,7 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||||
output_ptr = output_buf[ci];
|
output_ptr = output_buf[ci];
|
||||||
/* Loop over all DCT blocks to be processed. */
|
/* Loop over all DCT blocks to be processed. */
|
||||||
for (block_row = 0; block_row < block_rows; block_row++) {
|
for (block_row = 0; block_row < block_rows; block_row++) {
|
||||||
buffer_ptr = buffer[block_row];
|
buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci];
|
||||||
if (first_row && block_row == 0)
|
if (first_row && block_row == 0)
|
||||||
prev_block_row = buffer_ptr;
|
prev_block_row = buffer_ptr;
|
||||||
else
|
else
|
||||||
|
@ -564,7 +509,8 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||||
DC7 = DC8 = DC9 = (int) next_block_row[0][0];
|
DC7 = DC8 = DC9 = (int) next_block_row[0][0];
|
||||||
output_col = 0;
|
output_col = 0;
|
||||||
last_block_column = compptr->width_in_blocks - 1;
|
last_block_column = compptr->width_in_blocks - 1;
|
||||||
for (block_num = 0; block_num <= last_block_column; block_num++) {
|
for (block_num = cinfo->master->first_MCU_col[ci];
|
||||||
|
block_num <= cinfo->master->last_MCU_col[ci]; block_num++) {
|
||||||
/* Fetch current DCT block into workspace so we can modify it. */
|
/* Fetch current DCT block into workspace so we can modify it. */
|
||||||
jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
|
jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
|
||||||
/* Update DC values */
|
/* Update DC values */
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* jdcoefct.h
|
||||||
|
*
|
||||||
|
* This file was part of the Independent JPEG Group's software:
|
||||||
|
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||||
|
* libjpeg-turbo Modifications:
|
||||||
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define JPEG_INTERNALS
|
||||||
|
#include "jpeglib.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Block smoothing is only applicable for progressive JPEG, so: */
|
||||||
|
#ifndef D_PROGRESSIVE_SUPPORTED
|
||||||
|
#undef BLOCK_SMOOTHING_SUPPORTED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Private buffer controller object */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct jpeg_d_coef_controller pub; /* public fields */
|
||||||
|
|
||||||
|
/* These variables keep track of the current location of the input side. */
|
||||||
|
/* cinfo->input_iMCU_row is also used for this. */
|
||||||
|
JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
|
||||||
|
int MCU_vert_offset; /* counts MCU rows within iMCU row */
|
||||||
|
int MCU_rows_per_iMCU_row; /* number of such rows needed */
|
||||||
|
|
||||||
|
/* The output side's location is represented by cinfo->output_iMCU_row. */
|
||||||
|
|
||||||
|
/* In single-pass modes, it's sufficient to buffer just one MCU.
|
||||||
|
* We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
|
||||||
|
* and let the entropy decoder write into that workspace each time.
|
||||||
|
* In multi-pass modes, this array points to the current MCU's blocks
|
||||||
|
* within the virtual arrays; it is used only by the input side.
|
||||||
|
*/
|
||||||
|
JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
|
||||||
|
|
||||||
|
/* Temporary workspace for one MCU */
|
||||||
|
JCOEF *workspace;
|
||||||
|
|
||||||
|
#ifdef D_MULTISCAN_FILES_SUPPORTED
|
||||||
|
/* In multi-pass modes, we need a virtual block array for each component. */
|
||||||
|
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BLOCK_SMOOTHING_SUPPORTED
|
||||||
|
/* When doing block smoothing, we latch coefficient Al values here */
|
||||||
|
int *coef_bits_latch;
|
||||||
|
#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
|
||||||
|
#endif
|
||||||
|
} my_coef_controller;
|
||||||
|
|
||||||
|
typedef my_coef_controller *my_coef_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
start_iMCU_row (j_decompress_ptr cinfo)
|
||||||
|
/* Reset within-iMCU-row counters for a new row (input side) */
|
||||||
|
{
|
||||||
|
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
|
||||||
|
|
||||||
|
/* In an interleaved scan, an MCU row is the same as an iMCU row.
|
||||||
|
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
|
||||||
|
* But at the bottom of the image, process only what's left.
|
||||||
|
*/
|
||||||
|
if (cinfo->comps_in_scan > 1) {
|
||||||
|
coef->MCU_rows_per_iMCU_row = 1;
|
||||||
|
} else {
|
||||||
|
if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
|
||||||
|
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
|
||||||
|
else
|
||||||
|
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
coef->MCU_ctr = 0;
|
||||||
|
coef->MCU_vert_offset = 0;
|
||||||
|
}
|
|
@ -5,8 +5,9 @@
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* Modifications:
|
* Modifications:
|
||||||
* Copyright (C) 2013, Linaro Limited.
|
* Copyright (C) 2013, Linaro Limited.
|
||||||
* Copyright (C) 2014, D. R. Commander.
|
* Copyright (C) 2014-2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains output colorspace conversion routines.
|
* This file contains output colorspace conversion routines.
|
||||||
*/
|
*/
|
||||||
|
@ -30,12 +31,12 @@ ycc_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
register int * Crrtab = cconvert->Cr_r_tab;
|
register int * Crrtab = cconvert->Cr_r_tab;
|
||||||
register int * Cbbtab = cconvert->Cb_b_tab;
|
register int * Cbbtab = cconvert->Cb_b_tab;
|
||||||
register INT32 * Crgtab = cconvert->Cr_g_tab;
|
register JLONG * Crgtab = cconvert->Cr_g_tab;
|
||||||
register INT32 * Cbgtab = cconvert->Cb_g_tab;
|
register JLONG * Cbgtab = cconvert->Cb_g_tab;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
inptr0 = input_buf[0][input_row];
|
inptr0 = input_buf[0][input_row];
|
||||||
inptr1 = input_buf[1][input_row];
|
inptr1 = input_buf[1][input_row];
|
||||||
|
@ -52,7 +53,7 @@ ycc_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
SCALEBITS))];
|
SCALEBITS))];
|
||||||
b = range_limit[y + Cbbtab[cb]];
|
b = range_limit[y + Cbbtab[cb]];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
outptr += 2;
|
outptr += 2;
|
||||||
num_cols--;
|
num_cols--;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +88,7 @@ ycc_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
SCALEBITS))];
|
SCALEBITS))];
|
||||||
b = range_limit[y + Cbbtab[cb]];
|
b = range_limit[y + Cbbtab[cb]];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,13 +110,13 @@ ycc_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
register int * Crrtab = cconvert->Cr_r_tab;
|
register int * Crrtab = cconvert->Cr_r_tab;
|
||||||
register int * Cbbtab = cconvert->Cb_b_tab;
|
register int * Cbbtab = cconvert->Cb_b_tab;
|
||||||
register INT32 * Crgtab = cconvert->Cr_g_tab;
|
register JLONG * Crgtab = cconvert->Cr_g_tab;
|
||||||
register INT32 * Cbgtab = cconvert->Cb_g_tab;
|
register JLONG * Cbgtab = cconvert->Cb_g_tab;
|
||||||
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
|
|
||||||
inptr0 = input_buf[0][input_row];
|
inptr0 = input_buf[0][input_row];
|
||||||
|
@ -133,7 +134,7 @@ ycc_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
SCALEBITS)), d0)];
|
SCALEBITS)), d0)];
|
||||||
b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
|
b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
outptr += 2;
|
outptr += 2;
|
||||||
num_cols--;
|
num_cols--;
|
||||||
}
|
}
|
||||||
|
@ -173,7 +174,7 @@ ycc_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
SCALEBITS)), d0)];
|
SCALEBITS)), d0)];
|
||||||
b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
|
b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +193,7 @@ rgb_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
|
|
||||||
inptr0 = input_buf[0][input_row];
|
inptr0 = input_buf[0][input_row];
|
||||||
|
@ -205,7 +206,7 @@ rgb_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
g = GETJSAMPLE(*inptr1++);
|
g = GETJSAMPLE(*inptr1++);
|
||||||
b = GETJSAMPLE(*inptr2++);
|
b = GETJSAMPLE(*inptr2++);
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
outptr += 2;
|
outptr += 2;
|
||||||
num_cols--;
|
num_cols--;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +229,7 @@ rgb_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
g = GETJSAMPLE(*inptr1);
|
g = GETJSAMPLE(*inptr1);
|
||||||
b = GETJSAMPLE(*inptr2);
|
b = GETJSAMPLE(*inptr2);
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,11 +246,11 @@ rgb_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
JDIMENSION num_cols = cinfo->output_width;
|
JDIMENSION num_cols = cinfo->output_width;
|
||||||
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
|
|
||||||
inptr0 = input_buf[0][input_row];
|
inptr0 = input_buf[0][input_row];
|
||||||
|
@ -262,7 +263,7 @@ rgb_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
|
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
|
||||||
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
|
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
outptr += 2;
|
outptr += 2;
|
||||||
num_cols--;
|
num_cols--;
|
||||||
}
|
}
|
||||||
|
@ -287,7 +288,7 @@ rgb_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1), d0)];
|
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1), d0)];
|
||||||
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2), d0)];
|
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2), d0)];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,7 +305,7 @@ gray_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
JDIMENSION num_cols = cinfo->output_width;
|
JDIMENSION num_cols = cinfo->output_width;
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
unsigned int g;
|
unsigned int g;
|
||||||
|
|
||||||
inptr = input_buf[0][input_row++];
|
inptr = input_buf[0][input_row++];
|
||||||
|
@ -312,7 +313,7 @@ gray_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
if (PACK_NEED_ALIGNMENT(outptr)) {
|
if (PACK_NEED_ALIGNMENT(outptr)) {
|
||||||
g = *inptr++;
|
g = *inptr++;
|
||||||
rgb = PACK_SHORT_565(g, g, g);
|
rgb = PACK_SHORT_565(g, g, g);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
outptr += 2;
|
outptr += 2;
|
||||||
num_cols--;
|
num_cols--;
|
||||||
}
|
}
|
||||||
|
@ -327,7 +328,7 @@ gray_rgb565_convert_internal (j_decompress_ptr cinfo,
|
||||||
if (num_cols & 1) {
|
if (num_cols & 1) {
|
||||||
g = *inptr;
|
g = *inptr;
|
||||||
rgb = PACK_SHORT_565(g, g, g);
|
rgb = PACK_SHORT_565(g, g, g);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,10 +344,10 @@ gray_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
JDIMENSION num_cols = cinfo->output_width;
|
JDIMENSION num_cols = cinfo->output_width;
|
||||||
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
unsigned int g;
|
unsigned int g;
|
||||||
|
|
||||||
inptr = input_buf[0][input_row++];
|
inptr = input_buf[0][input_row++];
|
||||||
|
@ -355,7 +356,7 @@ gray_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
g = *inptr++;
|
g = *inptr++;
|
||||||
g = range_limit[DITHER_565_R(g, d0)];
|
g = range_limit[DITHER_565_R(g, d0)];
|
||||||
rgb = PACK_SHORT_565(g, g, g);
|
rgb = PACK_SHORT_565(g, g, g);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
outptr += 2;
|
outptr += 2;
|
||||||
num_cols--;
|
num_cols--;
|
||||||
}
|
}
|
||||||
|
@ -377,7 +378,7 @@ gray_rgb565D_convert_internal (j_decompress_ptr cinfo,
|
||||||
g = *inptr;
|
g = *inptr;
|
||||||
g = range_limit[DITHER_565_R(g, d0)];
|
g = range_limit[DITHER_565_R(g, d0)];
|
||||||
rgb = PACK_SHORT_565(g, g, g);
|
rgb = PACK_SHORT_565(g, g, g);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2009, 2011, D. R. Commander.
|
* Copyright (C) 2009, 2011, 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains output colorspace conversion routines.
|
* This file contains output colorspace conversion routines.
|
||||||
*/
|
*/
|
||||||
|
@ -41,8 +42,8 @@ ycc_rgb_convert_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
register int * Crrtab = cconvert->Cr_r_tab;
|
register int * Crrtab = cconvert->Cr_r_tab;
|
||||||
register int * Cbbtab = cconvert->Cb_b_tab;
|
register int * Cbbtab = cconvert->Cb_b_tab;
|
||||||
register INT32 * Crgtab = cconvert->Cr_g_tab;
|
register JLONG * Crgtab = cconvert->Cr_g_tab;
|
||||||
register INT32 * Cbgtab = cconvert->Cb_g_tab;
|
register JLONG * Cbgtab = cconvert->Cb_g_tab;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
* Copyright (C) 2009, 2011-2012, 2014-2015, D. R. Commander.
|
* Copyright (C) 2009, 2011-2012, 2014-2015, D. R. Commander.
|
||||||
* Copyright (C) 2013, Linaro Limited.
|
* Copyright (C) 2013, Linaro Limited.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains output colorspace conversion routines.
|
* This file contains output colorspace conversion routines.
|
||||||
*/
|
*/
|
||||||
|
@ -26,16 +27,16 @@ typedef struct {
|
||||||
struct jpeg_color_deconverter pub; /* public fields */
|
struct jpeg_color_deconverter pub; /* public fields */
|
||||||
|
|
||||||
/* Private state for YCC->RGB conversion */
|
/* Private state for YCC->RGB conversion */
|
||||||
int * Cr_r_tab; /* => table for Cr to R conversion */
|
int *Cr_r_tab; /* => table for Cr to R conversion */
|
||||||
int * Cb_b_tab; /* => table for Cb to B conversion */
|
int *Cb_b_tab; /* => table for Cb to B conversion */
|
||||||
INT32 * Cr_g_tab; /* => table for Cr to G conversion */
|
JLONG *Cr_g_tab; /* => table for Cr to G conversion */
|
||||||
INT32 * Cb_g_tab; /* => table for Cb to G conversion */
|
JLONG *Cb_g_tab; /* => table for Cb to G conversion */
|
||||||
|
|
||||||
/* Private state for RGB->Y conversion */
|
/* Private state for RGB->Y conversion */
|
||||||
INT32 * rgb_y_tab; /* => table for RGB to Y conversion */
|
JLONG *rgb_y_tab; /* => table for RGB to Y conversion */
|
||||||
} my_color_deconverter;
|
} my_color_deconverter;
|
||||||
|
|
||||||
typedef my_color_deconverter * my_cconvert_ptr;
|
typedef my_color_deconverter *my_cconvert_ptr;
|
||||||
|
|
||||||
|
|
||||||
/**************** YCbCr -> RGB conversion: most common case **************/
|
/**************** YCbCr -> RGB conversion: most common case **************/
|
||||||
|
@ -73,8 +74,8 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SCALEBITS 16 /* speediest right-shift on some machines */
|
#define SCALEBITS 16 /* speediest right-shift on some machines */
|
||||||
#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
|
#define ONE_HALF ((JLONG) 1 << (SCALEBITS-1))
|
||||||
#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
|
#define FIX(x) ((JLONG) ((x) * (1L<<SCALEBITS) + 0.5))
|
||||||
|
|
||||||
/* We allocate one big table for RGB->Y conversion and divide it up into
|
/* We allocate one big table for RGB->Y conversion and divide it up into
|
||||||
* three parts, instead of doing three alloc_small requests. This lets us
|
* three parts, instead of doing three alloc_small requests. This lets us
|
||||||
|
@ -211,7 +212,7 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
||||||
int i;
|
int i;
|
||||||
INT32 x;
|
JLONG x;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
cconvert->Cr_r_tab = (int *)
|
cconvert->Cr_r_tab = (int *)
|
||||||
|
@ -220,12 +221,12 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
|
||||||
cconvert->Cb_b_tab = (int *)
|
cconvert->Cb_b_tab = (int *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(MAXJSAMPLE+1) * sizeof(int));
|
(MAXJSAMPLE+1) * sizeof(int));
|
||||||
cconvert->Cr_g_tab = (INT32 *)
|
cconvert->Cr_g_tab = (JLONG *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(MAXJSAMPLE+1) * sizeof(INT32));
|
(MAXJSAMPLE+1) * sizeof(JLONG));
|
||||||
cconvert->Cb_g_tab = (INT32 *)
|
cconvert->Cb_g_tab = (JLONG *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(MAXJSAMPLE+1) * sizeof(INT32));
|
(MAXJSAMPLE+1) * sizeof(JLONG));
|
||||||
|
|
||||||
for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
|
for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
|
||||||
/* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
|
/* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
|
||||||
|
@ -302,13 +303,13 @@ LOCAL(void)
|
||||||
build_rgb_y_table (j_decompress_ptr cinfo)
|
build_rgb_y_table (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
||||||
INT32 * rgb_y_tab;
|
JLONG *rgb_y_tab;
|
||||||
INT32 i;
|
JLONG i;
|
||||||
|
|
||||||
/* Allocate and fill in the conversion tables. */
|
/* Allocate and fill in the conversion tables. */
|
||||||
cconvert->rgb_y_tab = rgb_y_tab = (INT32 *)
|
cconvert->rgb_y_tab = rgb_y_tab = (JLONG *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(TABLE_SIZE * sizeof(INT32)));
|
(TABLE_SIZE * sizeof(JLONG)));
|
||||||
|
|
||||||
for (i = 0; i <= MAXJSAMPLE; i++) {
|
for (i = 0; i <= MAXJSAMPLE; i++) {
|
||||||
rgb_y_tab[i+R_Y_OFF] = FIX(0.29900) * i;
|
rgb_y_tab[i+R_Y_OFF] = FIX(0.29900) * i;
|
||||||
|
@ -329,7 +330,7 @@ rgb_gray_convert (j_decompress_ptr cinfo,
|
||||||
{
|
{
|
||||||
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
|
||||||
register int r, g, b;
|
register int r, g, b;
|
||||||
register INT32 * ctab = cconvert->rgb_y_tab;
|
register JLONG *ctab = cconvert->rgb_y_tab;
|
||||||
register JSAMPROW outptr;
|
register JSAMPROW outptr;
|
||||||
register JSAMPROW inptr0, inptr1, inptr2;
|
register JSAMPROW inptr0, inptr1, inptr2;
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
|
@ -542,11 +543,11 @@ ycck_cmyk_convert (j_decompress_ptr cinfo,
|
||||||
register JDIMENSION col;
|
register JDIMENSION col;
|
||||||
JDIMENSION num_cols = cinfo->output_width;
|
JDIMENSION num_cols = cinfo->output_width;
|
||||||
/* copy these pointers into registers if possible */
|
/* copy these pointers into registers if possible */
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE *range_limit = cinfo->sample_range_limit;
|
||||||
register int * Crrtab = cconvert->Cr_r_tab;
|
register int *Crrtab = cconvert->Cr_r_tab;
|
||||||
register int * Cbbtab = cconvert->Cb_b_tab;
|
register int *Cbbtab = cconvert->Cb_b_tab;
|
||||||
register INT32 * Crgtab = cconvert->Cr_g_tab;
|
register JLONG *Crgtab = cconvert->Cr_g_tab;
|
||||||
register INT32 * Cbgtab = cconvert->Cb_g_tab;
|
register JLONG *Cbgtab = cconvert->Cb_g_tab;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
while (--num_rows >= 0) {
|
while (--num_rows >= 0) {
|
||||||
|
@ -603,8 +604,8 @@ ycck_cmyk_convert (j_decompress_ptr cinfo,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DITHER_MASK 0x3
|
#define DITHER_MASK 0x3
|
||||||
#define DITHER_ROTATE(x) (((x) << 24) | (((x) >> 8) & 0x00FFFFFF))
|
#define DITHER_ROTATE(x) ((((x) & 0xFF) << 24) | (((x) >> 8) & 0x00FFFFFF))
|
||||||
static const INT32 dither_matrix[4] = {
|
static const JLONG dither_matrix[4] = {
|
||||||
0x0008020A,
|
0x0008020A,
|
||||||
0x0C040E06,
|
0x0C040E06,
|
||||||
0x030B0109,
|
0x030B0109,
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* libjpeg-turbo Modifications:
|
||||||
* to libjpeg-turbo.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This include file contains common declarations for the forward and
|
* This include file contains common declarations for the forward and
|
||||||
* inverse DCT modules. These declarations are private to the DCT managers
|
* inverse DCT modules. These declarations are private to the DCT managers
|
||||||
|
@ -18,7 +19,7 @@
|
||||||
/*
|
/*
|
||||||
* A forward DCT routine is given a pointer to a work area of type DCTELEM[];
|
* A forward DCT routine is given a pointer to a work area of type DCTELEM[];
|
||||||
* the DCT is to be performed in-place in that buffer. Type DCTELEM is int
|
* the DCT is to be performed in-place in that buffer. Type DCTELEM is int
|
||||||
* for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT
|
* for 8-bit samples, JLONG for 12-bit samples. (NOTE: Floating-point DCT
|
||||||
* implementations use an array of type FAST_FLOAT, instead.)
|
* implementations use an array of type FAST_FLOAT, instead.)
|
||||||
* The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
|
* The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
|
||||||
* The DCT outputs are returned scaled up by a factor of 8; they therefore
|
* The DCT outputs are returned scaled up by a factor of 8; they therefore
|
||||||
|
@ -40,7 +41,7 @@ typedef unsigned short UDCTELEM;
|
||||||
typedef unsigned int UDCTELEM2;
|
typedef unsigned int UDCTELEM2;
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
typedef INT32 DCTELEM; /* must have 32 bits */
|
typedef JLONG DCTELEM; /* must have 32 bits */
|
||||||
typedef unsigned long long UDCTELEM2;
|
typedef unsigned long long UDCTELEM2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
|
||||||
typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
|
typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
|
||||||
#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
|
#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
|
||||||
#else
|
#else
|
||||||
typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
|
typedef JLONG IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
|
||||||
#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
|
#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
|
||||||
#endif
|
#endif
|
||||||
typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
|
typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
|
||||||
|
@ -89,63 +90,63 @@ typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
|
||||||
|
|
||||||
/* Extern declarations for the forward and inverse DCT routines. */
|
/* Extern declarations for the forward and inverse DCT routines. */
|
||||||
|
|
||||||
EXTERN(void) jpeg_fdct_islow (DCTELEM * data);
|
EXTERN(void) jpeg_fdct_islow (DCTELEM *data);
|
||||||
EXTERN(void) jpeg_fdct_ifast (DCTELEM * data);
|
EXTERN(void) jpeg_fdct_ifast (DCTELEM *data);
|
||||||
EXTERN(void) jpeg_fdct_float (FAST_FLOAT * data);
|
EXTERN(void) jpeg_fdct_float (FAST_FLOAT *data);
|
||||||
|
|
||||||
EXTERN(void) jpeg_idct_islow
|
EXTERN(void) jpeg_idct_islow
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_ifast
|
EXTERN(void) jpeg_idct_ifast
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_float
|
EXTERN(void) jpeg_idct_float
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_7x7
|
EXTERN(void) jpeg_idct_7x7
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_6x6
|
EXTERN(void) jpeg_idct_6x6
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_5x5
|
EXTERN(void) jpeg_idct_5x5
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_4x4
|
EXTERN(void) jpeg_idct_4x4
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_3x3
|
EXTERN(void) jpeg_idct_3x3
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_2x2
|
EXTERN(void) jpeg_idct_2x2
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_1x1
|
EXTERN(void) jpeg_idct_1x1
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_9x9
|
EXTERN(void) jpeg_idct_9x9
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_10x10
|
EXTERN(void) jpeg_idct_10x10
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_11x11
|
EXTERN(void) jpeg_idct_11x11
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_12x12
|
EXTERN(void) jpeg_idct_12x12
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_13x13
|
EXTERN(void) jpeg_idct_13x13
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_14x14
|
EXTERN(void) jpeg_idct_14x14
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_15x15
|
EXTERN(void) jpeg_idct_15x15
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
EXTERN(void) jpeg_idct_16x16
|
EXTERN(void) jpeg_idct_16x16
|
||||||
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,13 +154,13 @@ EXTERN(void) jpeg_idct_16x16
|
||||||
* Macros for handling fixed-point arithmetic; these are used by many
|
* Macros for handling fixed-point arithmetic; these are used by many
|
||||||
* but not all of the DCT/IDCT modules.
|
* but not all of the DCT/IDCT modules.
|
||||||
*
|
*
|
||||||
* All values are expected to be of type INT32.
|
* All values are expected to be of type JLONG.
|
||||||
* Fractional constants are scaled left by CONST_BITS bits.
|
* Fractional constants are scaled left by CONST_BITS bits.
|
||||||
* CONST_BITS is defined within each module using these macros,
|
* CONST_BITS is defined within each module using these macros,
|
||||||
* and may differ from one module to the next.
|
* and may differ from one module to the next.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ONE ((INT32) 1)
|
#define ONE ((JLONG) 1)
|
||||||
#define CONST_SCALE (ONE << CONST_BITS)
|
#define CONST_SCALE (ONE << CONST_BITS)
|
||||||
|
|
||||||
/* Convert a positive real constant to an integer scaled by CONST_SCALE.
|
/* Convert a positive real constant to an integer scaled by CONST_SCALE.
|
||||||
|
@ -167,16 +168,16 @@ EXTERN(void) jpeg_idct_16x16
|
||||||
* thus causing a lot of useless floating-point operations at run time.
|
* thus causing a lot of useless floating-point operations at run time.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5))
|
#define FIX(x) ((JLONG) ((x) * CONST_SCALE + 0.5))
|
||||||
|
|
||||||
/* Descale and correctly round an INT32 value that's scaled by N bits.
|
/* Descale and correctly round a JLONG value that's scaled by N bits.
|
||||||
* We assume RIGHT_SHIFT rounds towards minus infinity, so adding
|
* We assume RIGHT_SHIFT rounds towards minus infinity, so adding
|
||||||
* the fudge factor is correct for either sign of X.
|
* the fudge factor is correct for either sign of X.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
|
#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
|
||||||
|
|
||||||
/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
|
/* Multiply a JLONG variable by a JLONG constant to yield a JLONG result.
|
||||||
* This macro is used only when the two inputs will actually be no more than
|
* This macro is used only when the two inputs will actually be no more than
|
||||||
* 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
|
* 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
|
||||||
* full 32x32 multiply. This provides a useful speedup on many machines.
|
* full 32x32 multiply. This provides a useful speedup on many machines.
|
||||||
|
@ -189,7 +190,7 @@ EXTERN(void) jpeg_idct_16x16
|
||||||
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
|
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
|
||||||
#endif
|
#endif
|
||||||
#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
|
#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
|
||||||
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const)))
|
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((JLONG) (const)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MULTIPLY16C16 /* default definition */
|
#ifndef MULTIPLY16C16 /* default definition */
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
* Modified 2002-2010 by Guido Vollbeding.
|
* Modified 2002-2010 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright (C) 2010, 2015, D. R. Commander.
|
||||||
* Copyright (C) 2013, MIPS Technologies, Inc., California
|
* Copyright (C) 2013, MIPS Technologies, Inc., California.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the inverse-DCT management logic.
|
* This file contains the inverse-DCT management logic.
|
||||||
* This code selects a particular IDCT implementation to be used,
|
* This code selects a particular IDCT implementation to be used,
|
||||||
|
@ -58,7 +59,7 @@ typedef struct {
|
||||||
int cur_method[MAX_COMPONENTS];
|
int cur_method[MAX_COMPONENTS];
|
||||||
} my_idct_controller;
|
} my_idct_controller;
|
||||||
|
|
||||||
typedef my_idct_controller * my_idct_ptr;
|
typedef my_idct_controller *my_idct_ptr;
|
||||||
|
|
||||||
|
|
||||||
/* Allocated multiplier tables: big enough for any supported variant */
|
/* Allocated multiplier tables: big enough for any supported variant */
|
||||||
|
@ -100,7 +101,7 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
jpeg_component_info *compptr;
|
jpeg_component_info *compptr;
|
||||||
int method = 0;
|
int method = 0;
|
||||||
inverse_DCT_method_ptr method_ptr = NULL;
|
inverse_DCT_method_ptr method_ptr = NULL;
|
||||||
JQUANT_TBL * qtbl;
|
JQUANT_TBL *qtbl;
|
||||||
|
|
||||||
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
||||||
ci++, compptr++) {
|
ci++, compptr++) {
|
||||||
|
@ -245,7 +246,7 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
/* For LL&M IDCT method, multipliers are equal to raw quantization
|
/* For LL&M IDCT method, multipliers are equal to raw quantization
|
||||||
* coefficients, but are stored as ints to ensure access efficiency.
|
* coefficients, but are stored as ints to ensure access efficiency.
|
||||||
*/
|
*/
|
||||||
ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
|
ISLOW_MULT_TYPE *ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
|
||||||
for (i = 0; i < DCTSIZE2; i++) {
|
for (i = 0; i < DCTSIZE2; i++) {
|
||||||
ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
|
ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
|
||||||
}
|
}
|
||||||
|
@ -262,7 +263,7 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
* For integer operation, the multiplier table is to be scaled by
|
* For integer operation, the multiplier table is to be scaled by
|
||||||
* IFAST_SCALE_BITS.
|
* IFAST_SCALE_BITS.
|
||||||
*/
|
*/
|
||||||
IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
|
IFAST_MULT_TYPE *ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
|
||||||
#define CONST_BITS 14
|
#define CONST_BITS 14
|
||||||
static const INT16 aanscales[DCTSIZE2] = {
|
static const INT16 aanscales[DCTSIZE2] = {
|
||||||
/* precomputed values scaled up by 14 bits */
|
/* precomputed values scaled up by 14 bits */
|
||||||
|
@ -279,8 +280,8 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
|
|
||||||
for (i = 0; i < DCTSIZE2; i++) {
|
for (i = 0; i < DCTSIZE2; i++) {
|
||||||
ifmtbl[i] = (IFAST_MULT_TYPE)
|
ifmtbl[i] = (IFAST_MULT_TYPE)
|
||||||
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
|
DESCALE(MULTIPLY16V16((JLONG) qtbl->quantval[i],
|
||||||
(INT32) aanscales[i]),
|
(JLONG) aanscales[i]),
|
||||||
CONST_BITS-IFAST_SCALE_BITS);
|
CONST_BITS-IFAST_SCALE_BITS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,7 +295,7 @@ start_pass (j_decompress_ptr cinfo)
|
||||||
* scalefactor[0] = 1
|
* scalefactor[0] = 1
|
||||||
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
|
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
|
||||||
*/
|
*/
|
||||||
FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
|
FLOAT_MULT_TYPE *fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
|
||||||
int row, col;
|
int row, col;
|
||||||
static const double aanscalefactor[DCTSIZE] = {
|
static const double aanscalefactor[DCTSIZE] = {
|
||||||
1.0, 1.387039845, 1.306562965, 1.175875602,
|
1.0, 1.387039845, 1.306562965, 1.175875602,
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2009-2011, D. R. Commander.
|
* Copyright (C) 2009-2011, 2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains Huffman entropy decoding routines.
|
* This file contains Huffman entropy decoding routines.
|
||||||
*
|
*
|
||||||
|
@ -66,20 +67,20 @@ typedef struct {
|
||||||
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
||||||
|
|
||||||
/* Pointers to derived tables (these workspaces have image lifespan) */
|
/* Pointers to derived tables (these workspaces have image lifespan) */
|
||||||
d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
|
d_derived_tbl *dc_derived_tbls[NUM_HUFF_TBLS];
|
||||||
d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
|
d_derived_tbl *ac_derived_tbls[NUM_HUFF_TBLS];
|
||||||
|
|
||||||
/* Precalculated info set up by start_pass for use in decode_mcu: */
|
/* Precalculated info set up by start_pass for use in decode_mcu: */
|
||||||
|
|
||||||
/* Pointers to derived tables to be used for each block within an MCU */
|
/* Pointers to derived tables to be used for each block within an MCU */
|
||||||
d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
|
d_derived_tbl *dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
|
||||||
d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
|
d_derived_tbl *ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
|
||||||
/* Whether we care about the DC and AC coefficient values for each block */
|
/* Whether we care about the DC and AC coefficient values for each block */
|
||||||
boolean dc_needed[D_MAX_BLOCKS_IN_MCU];
|
boolean dc_needed[D_MAX_BLOCKS_IN_MCU];
|
||||||
boolean ac_needed[D_MAX_BLOCKS_IN_MCU];
|
boolean ac_needed[D_MAX_BLOCKS_IN_MCU];
|
||||||
} huff_entropy_decoder;
|
} huff_entropy_decoder;
|
||||||
|
|
||||||
typedef huff_entropy_decoder * huff_entropy_ptr;
|
typedef huff_entropy_decoder *huff_entropy_ptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -92,7 +93,7 @@ start_pass_huff_decoder (j_decompress_ptr cinfo)
|
||||||
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
|
||||||
int ci, blkn, dctbl, actbl;
|
int ci, blkn, dctbl, actbl;
|
||||||
d_derived_tbl **pdtbl;
|
d_derived_tbl **pdtbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
/* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
|
/* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
|
||||||
* This ought to be an error condition, but we make it a warning because
|
* This ought to be an error condition, but we make it a warning because
|
||||||
|
@ -152,7 +153,7 @@ start_pass_huff_decoder (j_decompress_ptr cinfo)
|
||||||
|
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
|
jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
|
||||||
d_derived_tbl ** pdtbl)
|
d_derived_tbl **pdtbl)
|
||||||
{
|
{
|
||||||
JHUFF_TBL *htbl;
|
JHUFF_TBL *htbl;
|
||||||
d_derived_tbl *dtbl;
|
d_derived_tbl *dtbl;
|
||||||
|
@ -209,7 +210,7 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
|
||||||
/* code is now 1 more than the last code used for codelength si; but
|
/* code is now 1 more than the last code used for codelength si; but
|
||||||
* it must still fit in si bits, since no code is allowed to be all ones.
|
* it must still fit in si bits, since no code is allowed to be all ones.
|
||||||
*/
|
*/
|
||||||
if (((INT32) code) >= (((INT32) 1) << si))
|
if (((JLONG) code) >= (((JLONG) 1) << si))
|
||||||
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
|
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
|
||||||
code <<= 1;
|
code <<= 1;
|
||||||
si++;
|
si++;
|
||||||
|
@ -223,7 +224,7 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
|
||||||
/* valoffset[l] = huffval[] index of 1st symbol of code length l,
|
/* valoffset[l] = huffval[] index of 1st symbol of code length l,
|
||||||
* minus the minimum code of length l
|
* minus the minimum code of length l
|
||||||
*/
|
*/
|
||||||
dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p];
|
dtbl->valoffset[l] = (JLONG) p - (JLONG) huffcode[p];
|
||||||
p += htbl->bits[l];
|
p += htbl->bits[l];
|
||||||
dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
|
dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
|
||||||
} else {
|
} else {
|
||||||
|
@ -295,13 +296,13 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
|
||||||
|
|
||||||
|
|
||||||
GLOBAL(boolean)
|
GLOBAL(boolean)
|
||||||
jpeg_fill_bit_buffer (bitread_working_state * state,
|
jpeg_fill_bit_buffer (bitread_working_state *state,
|
||||||
register bit_buf_type get_buffer, register int bits_left,
|
register bit_buf_type get_buffer, register int bits_left,
|
||||||
int nbits)
|
int nbits)
|
||||||
/* Load up the bit buffer to a depth of at least nbits */
|
/* Load up the bit buffer to a depth of at least nbits */
|
||||||
{
|
{
|
||||||
/* Copy heavily used state fields into locals (hopefully registers) */
|
/* Copy heavily used state fields into locals (hopefully registers) */
|
||||||
register const JOCTET * next_input_byte = state->next_input_byte;
|
register const JOCTET *next_input_byte = state->next_input_byte;
|
||||||
register size_t bytes_in_buffer = state->bytes_in_buffer;
|
register size_t bytes_in_buffer = state->bytes_in_buffer;
|
||||||
j_decompress_ptr cinfo = state->cinfo;
|
j_decompress_ptr cinfo = state->cinfo;
|
||||||
|
|
||||||
|
@ -445,12 +446,12 @@ jpeg_fill_bit_buffer (bitread_working_state * state,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GLOBAL(int)
|
GLOBAL(int)
|
||||||
jpeg_huff_decode (bitread_working_state * state,
|
jpeg_huff_decode (bitread_working_state *state,
|
||||||
register bit_buf_type get_buffer, register int bits_left,
|
register bit_buf_type get_buffer, register int bits_left,
|
||||||
d_derived_tbl * htbl, int min_bits)
|
d_derived_tbl *htbl, int min_bits)
|
||||||
{
|
{
|
||||||
register int l = min_bits;
|
register int l = min_bits;
|
||||||
register INT32 code;
|
register JLONG code;
|
||||||
|
|
||||||
/* HUFF_DECODE has determined that the code is at least min_bits */
|
/* HUFF_DECODE has determined that the code is at least min_bits */
|
||||||
/* bits long, so fetch that many bits in one swoop. */
|
/* bits long, so fetch that many bits in one swoop. */
|
||||||
|
@ -564,9 +565,9 @@ decode_mcu_slow (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
ASSIGN_STATE(state, entropy->saved);
|
ASSIGN_STATE(state, entropy->saved);
|
||||||
|
|
||||||
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||||
JBLOCKROW block = MCU_data[blkn];
|
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
|
||||||
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
|
d_derived_tbl *dctbl = entropy->dc_cur_tbls[blkn];
|
||||||
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
|
d_derived_tbl *actbl = entropy->ac_cur_tbls[blkn];
|
||||||
register int s, k, r;
|
register int s, k, r;
|
||||||
|
|
||||||
/* Decode a single block's worth of coefficients */
|
/* Decode a single block's worth of coefficients */
|
||||||
|
@ -584,11 +585,13 @@ decode_mcu_slow (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
int ci = cinfo->MCU_membership[blkn];
|
int ci = cinfo->MCU_membership[blkn];
|
||||||
s += state.last_dc_val[ci];
|
s += state.last_dc_val[ci];
|
||||||
state.last_dc_val[ci] = s;
|
state.last_dc_val[ci] = s;
|
||||||
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
|
if (block) {
|
||||||
(*block)[0] = (JCOEF) s;
|
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
|
||||||
|
(*block)[0] = (JCOEF) s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entropy->ac_needed[blkn]) {
|
if (entropy->ac_needed[blkn] && block) {
|
||||||
|
|
||||||
/* Section F.2.2.2: decode the AC coefficients */
|
/* Section F.2.2.2: decode the AC coefficients */
|
||||||
/* Since zeroes are skipped, output area must be cleared beforehand */
|
/* Since zeroes are skipped, output area must be cleared beforehand */
|
||||||
|
@ -661,9 +664,9 @@ decode_mcu_fast (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
ASSIGN_STATE(state, entropy->saved);
|
ASSIGN_STATE(state, entropy->saved);
|
||||||
|
|
||||||
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||||
JBLOCKROW block = MCU_data[blkn];
|
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
|
||||||
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
|
d_derived_tbl *dctbl = entropy->dc_cur_tbls[blkn];
|
||||||
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
|
d_derived_tbl *actbl = entropy->ac_cur_tbls[blkn];
|
||||||
register int s, k, r, l;
|
register int s, k, r, l;
|
||||||
|
|
||||||
HUFF_DECODE_FAST(s, l, dctbl, slow_decode_mcu);
|
HUFF_DECODE_FAST(s, l, dctbl, slow_decode_mcu);
|
||||||
|
@ -677,10 +680,11 @@ decode_mcu_fast (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
int ci = cinfo->MCU_membership[blkn];
|
int ci = cinfo->MCU_membership[blkn];
|
||||||
s += state.last_dc_val[ci];
|
s += state.last_dc_val[ci];
|
||||||
state.last_dc_val[ci] = s;
|
state.last_dc_val[ci] = s;
|
||||||
(*block)[0] = (JCOEF) s;
|
if (block)
|
||||||
|
(*block)[0] = (JCOEF) s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entropy->ac_needed[blkn]) {
|
if (entropy->ac_needed[blkn] && block) {
|
||||||
|
|
||||||
for (k = 1; k < DCTSIZE2; k++) {
|
for (k = 1; k < DCTSIZE2; k++) {
|
||||||
HUFF_DECODE_FAST(s, l, actbl, slow_decode_mcu);
|
HUFF_DECODE_FAST(s, l, actbl, slow_decode_mcu);
|
||||||
|
@ -747,7 +751,7 @@ slow_decode_mcu:
|
||||||
* this module, since we'll just re-assign them on the next call.)
|
* this module, since we'll just re-assign them on the next call.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BUFSIZE (DCTSIZE2 * 2)
|
#define BUFSIZE (DCTSIZE2 * 8)
|
||||||
|
|
||||||
METHODDEF(boolean)
|
METHODDEF(boolean)
|
||||||
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
|
|
|
@ -4,14 +4,17 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010-2011, D. R. Commander.
|
* Copyright (C) 2010-2011, 2015-2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains declarations for Huffman entropy decoding routines
|
* This file contains declarations for Huffman entropy decoding routines
|
||||||
* that are shared between the sequential decoder (jdhuff.c) and the
|
* that are shared between the sequential decoder (jdhuff.c) and the
|
||||||
* progressive decoder (jdphuff.c). No other modules need to see these.
|
* progressive decoder (jdphuff.c). No other modules need to see these.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "jconfigint.h"
|
||||||
|
|
||||||
|
|
||||||
/* Derived data constructed for each Huffman table */
|
/* Derived data constructed for each Huffman table */
|
||||||
|
|
||||||
|
@ -19,9 +22,9 @@
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* Basic tables: (element [0] of each array is unused) */
|
/* Basic tables: (element [0] of each array is unused) */
|
||||||
INT32 maxcode[18]; /* largest code of length k (-1 if none) */
|
JLONG maxcode[18]; /* largest code of length k (-1 if none) */
|
||||||
/* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
|
/* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
|
||||||
INT32 valoffset[18]; /* huffval[] offset for codes of length k */
|
JLONG valoffset[18]; /* huffval[] offset for codes of length k */
|
||||||
/* valoffset[k] = huffval[] index of 1st symbol of code length k, less
|
/* valoffset[k] = huffval[] index of 1st symbol of code length k, less
|
||||||
* the smallest code of length k; so given a code of length k, the
|
* the smallest code of length k; so given a code of length k, the
|
||||||
* corresponding symbol is huffval[code + valoffset[k]]
|
* corresponding symbol is huffval[code + valoffset[k]]
|
||||||
|
@ -73,12 +76,12 @@ EXTERN(void) jpeg_make_d_derived_tbl
|
||||||
|
|
||||||
#if SIZEOF_SIZE_T==8 || defined(_WIN64)
|
#if SIZEOF_SIZE_T==8 || defined(_WIN64)
|
||||||
|
|
||||||
typedef size_t bit_buf_type; /* type of bit-extraction buffer */
|
typedef size_t bit_buf_type; /* type of bit-extraction buffer */
|
||||||
#define BIT_BUF_SIZE 64 /* size of buffer in bits */
|
#define BIT_BUF_SIZE 64 /* size of buffer in bits */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
|
typedef unsigned long bit_buf_type; /* type of bit-extraction buffer */
|
||||||
#define BIT_BUF_SIZE 32 /* size of buffer in bits */
|
#define BIT_BUF_SIZE 32 /* size of buffer in bits */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,7 +101,7 @@ typedef struct { /* Bitreading state saved across MCUs */
|
||||||
typedef struct { /* Bitreading working state within an MCU */
|
typedef struct { /* Bitreading working state within an MCU */
|
||||||
/* Current data source location */
|
/* Current data source location */
|
||||||
/* We need a copy, rather than munging the original, in case of suspension */
|
/* We need a copy, rather than munging the original, in case of suspension */
|
||||||
const JOCTET * next_input_byte; /* => next byte to read from source */
|
const JOCTET *next_input_byte; /* => next byte to read from source */
|
||||||
size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
|
size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
|
||||||
/* Bit input buffer --- note these values are kept in register variables,
|
/* Bit input buffer --- note these values are kept in register variables,
|
||||||
* not in this struct, inside the inner loops.
|
* not in this struct, inside the inner loops.
|
||||||
|
@ -163,7 +166,7 @@ typedef struct { /* Bitreading working state within an MCU */
|
||||||
|
|
||||||
/* Load up the bit buffer to a depth of at least nbits */
|
/* Load up the bit buffer to a depth of at least nbits */
|
||||||
EXTERN(boolean) jpeg_fill_bit_buffer
|
EXTERN(boolean) jpeg_fill_bit_buffer
|
||||||
(bitread_working_state * state, register bit_buf_type get_buffer,
|
(bitread_working_state *state, register bit_buf_type get_buffer,
|
||||||
register int bits_left, int nbits);
|
register int bits_left, int nbits);
|
||||||
|
|
||||||
|
|
||||||
|
@ -229,5 +232,5 @@ slowlabel: \
|
||||||
|
|
||||||
/* Out-of-line case for Huffman code fetching */
|
/* Out-of-line case for Huffman code fetching */
|
||||||
EXTERN(int) jpeg_huff_decode
|
EXTERN(int) jpeg_huff_decode
|
||||||
(bitread_working_state * state, register bit_buf_type get_buffer,
|
(bitread_working_state *state, register bit_buf_type get_buffer,
|
||||||
register int bits_left, d_derived_tbl * htbl, int min_bits);
|
register int bits_left, d_derived_tbl *htbl, int min_bits);
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright (C) 2010, 2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2015, Google, Inc.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains input control logic for the JPEG decompressor.
|
* This file contains input control logic for the JPEG decompressor.
|
||||||
* These routines are concerned with controlling the decompressor's input
|
* These routines are concerned with controlling the decompressor's input
|
||||||
|
@ -27,7 +29,7 @@ typedef struct {
|
||||||
boolean inheaders; /* TRUE until first SOS is reached */
|
boolean inheaders; /* TRUE until first SOS is reached */
|
||||||
} my_input_controller;
|
} my_input_controller;
|
||||||
|
|
||||||
typedef my_input_controller * my_inputctl_ptr;
|
typedef my_input_controller *my_inputctl_ptr;
|
||||||
|
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
@ -104,6 +106,11 @@ initial_setup (j_decompress_ptr cinfo)
|
||||||
compptr->height_in_blocks = (JDIMENSION)
|
compptr->height_in_blocks = (JDIMENSION)
|
||||||
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
|
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
|
||||||
(long) (cinfo->max_v_samp_factor * DCTSIZE));
|
(long) (cinfo->max_v_samp_factor * DCTSIZE));
|
||||||
|
/* Set the first and last MCU columns to decompress from multi-scan images.
|
||||||
|
* By default, decompress all of the MCU columns.
|
||||||
|
*/
|
||||||
|
cinfo->master->first_MCU_col[ci] = 0;
|
||||||
|
cinfo->master->last_MCU_col[ci] = compptr->width_in_blocks - 1;
|
||||||
/* downsampled_width and downsampled_height will also be overridden by
|
/* downsampled_width and downsampled_height will also be overridden by
|
||||||
* jdmaster.c if we are doing full decompression. The transcoder library
|
* jdmaster.c if we are doing full decompression. The transcoder library
|
||||||
* doesn't use these values, but the calling application might.
|
* doesn't use these values, but the calling application might.
|
||||||
|
@ -238,7 +245,7 @@ latch_quant_tables (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
int ci, qtblno;
|
int ci, qtblno;
|
||||||
jpeg_component_info *compptr;
|
jpeg_component_info *compptr;
|
||||||
JQUANT_TBL * qtbl;
|
JQUANT_TBL *qtbl;
|
||||||
|
|
||||||
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
||||||
compptr = cinfo->cur_comp_info[ci];
|
compptr = cinfo->cur_comp_info[ci];
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright (C) 2010, 2016, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the main buffer controller for decompression.
|
* This file contains the main buffer controller for decompression.
|
||||||
* The main buffer lies between the JPEG decompressor proper and the
|
* The main buffer lies between the JPEG decompressor proper and the
|
||||||
|
@ -15,10 +16,8 @@
|
||||||
* supplies the equivalent of the main buffer in that case.
|
* supplies the equivalent of the main buffer in that case.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define JPEG_INTERNALS
|
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jdmainct.h"
|
||||||
#include "jpegcomp.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -112,36 +111,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Private buffer controller object */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct jpeg_d_main_controller pub; /* public fields */
|
|
||||||
|
|
||||||
/* Pointer to allocated workspace (M or M+2 row groups). */
|
|
||||||
JSAMPARRAY buffer[MAX_COMPONENTS];
|
|
||||||
|
|
||||||
boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
|
|
||||||
JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
|
|
||||||
|
|
||||||
/* Remaining fields are only used in the context case. */
|
|
||||||
|
|
||||||
/* These are the master pointers to the funny-order pointer lists. */
|
|
||||||
JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
|
|
||||||
|
|
||||||
int whichptr; /* indicates which pointer set is now in use */
|
|
||||||
int context_state; /* process_data state machine status */
|
|
||||||
JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
|
|
||||||
JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
|
|
||||||
} my_main_controller;
|
|
||||||
|
|
||||||
typedef my_main_controller * my_main_ptr;
|
|
||||||
|
|
||||||
/* context_state values: */
|
|
||||||
#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
|
|
||||||
#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
|
|
||||||
#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
|
|
||||||
|
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
METHODDEF(void) process_data_simple_main
|
METHODDEF(void) process_data_simple_main
|
||||||
(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
|
(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
|
||||||
|
@ -237,34 +206,6 @@ make_funny_pointers (j_decompress_ptr cinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
|
||||||
set_wraparound_pointers (j_decompress_ptr cinfo)
|
|
||||||
/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
|
|
||||||
* This changes the pointer list state from top-of-image to the normal state.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
|
|
||||||
int ci, i, rgroup;
|
|
||||||
int M = cinfo->_min_DCT_scaled_size;
|
|
||||||
jpeg_component_info *compptr;
|
|
||||||
JSAMPARRAY xbuf0, xbuf1;
|
|
||||||
|
|
||||||
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
|
||||||
ci++, compptr++) {
|
|
||||||
rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
|
|
||||||
cinfo->_min_DCT_scaled_size; /* height of a row group of component */
|
|
||||||
xbuf0 = main_ptr->xbuffer[0][ci];
|
|
||||||
xbuf1 = main_ptr->xbuffer[1][ci];
|
|
||||||
for (i = 0; i < rgroup; i++) {
|
|
||||||
xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
|
|
||||||
xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
|
|
||||||
xbuf0[rgroup*(M+2) + i] = xbuf0[i];
|
|
||||||
xbuf1[rgroup*(M+2) + i] = xbuf1[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
set_bottom_pointers (j_decompress_ptr cinfo)
|
set_bottom_pointers (j_decompress_ptr cinfo)
|
||||||
/* Change the pointer lists to duplicate the last sample row at the bottom
|
/* Change the pointer lists to duplicate the last sample row at the bottom
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* jdmainct.h
|
||||||
|
*
|
||||||
|
* This file was part of the Independent JPEG Group's software:
|
||||||
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define JPEG_INTERNALS
|
||||||
|
#include "jpeglib.h"
|
||||||
|
#include "jpegcomp.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Private buffer controller object */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct jpeg_d_main_controller pub; /* public fields */
|
||||||
|
|
||||||
|
/* Pointer to allocated workspace (M or M+2 row groups). */
|
||||||
|
JSAMPARRAY buffer[MAX_COMPONENTS];
|
||||||
|
|
||||||
|
boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
|
||||||
|
JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
|
||||||
|
|
||||||
|
/* Remaining fields are only used in the context case. */
|
||||||
|
|
||||||
|
/* These are the master pointers to the funny-order pointer lists. */
|
||||||
|
JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
|
||||||
|
|
||||||
|
int whichptr; /* indicates which pointer set is now in use */
|
||||||
|
int context_state; /* process_data state machine status */
|
||||||
|
JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
|
||||||
|
JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
|
||||||
|
} my_main_controller;
|
||||||
|
|
||||||
|
typedef my_main_controller *my_main_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
/* context_state values: */
|
||||||
|
#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
|
||||||
|
#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
|
||||||
|
#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL(void)
|
||||||
|
set_wraparound_pointers (j_decompress_ptr cinfo)
|
||||||
|
/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
|
||||||
|
* This changes the pointer list state from top-of-image to the normal state.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
|
||||||
|
int ci, i, rgroup;
|
||||||
|
int M = cinfo->_min_DCT_scaled_size;
|
||||||
|
jpeg_component_info *compptr;
|
||||||
|
JSAMPARRAY xbuf0, xbuf1;
|
||||||
|
|
||||||
|
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
||||||
|
ci++, compptr++) {
|
||||||
|
rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
|
||||||
|
cinfo->_min_DCT_scaled_size; /* height of a row group of component */
|
||||||
|
xbuf0 = main_ptr->xbuffer[0][ci];
|
||||||
|
xbuf1 = main_ptr->xbuffer[1][ci];
|
||||||
|
for (i = 0; i < rgroup; i++) {
|
||||||
|
xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
|
||||||
|
xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
|
||||||
|
xbuf0[rgroup*(M+2) + i] = xbuf0[i];
|
||||||
|
xbuf1[rgroup*(M+2) + i] = xbuf1[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,9 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1991-1998, Thomas G. Lane.
|
* Copyright (C) 1991-1998, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2012, D. R. Commander.
|
* Copyright (C) 2012, 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains routines to decode JPEG datastream markers.
|
* This file contains routines to decode JPEG datastream markers.
|
||||||
* Most of the complexity arises from our desire to support input
|
* Most of the complexity arises from our desire to support input
|
||||||
|
@ -106,7 +107,7 @@ typedef struct {
|
||||||
/* Note: cur_marker is not linked into marker_list until it's all read. */
|
/* Note: cur_marker is not linked into marker_list until it's all read. */
|
||||||
} my_marker_reader;
|
} my_marker_reader;
|
||||||
|
|
||||||
typedef my_marker_reader * my_marker_ptr;
|
typedef my_marker_reader *my_marker_ptr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -119,8 +120,8 @@ typedef my_marker_reader * my_marker_ptr;
|
||||||
|
|
||||||
/* Declare and initialize local copies of input pointer/count */
|
/* Declare and initialize local copies of input pointer/count */
|
||||||
#define INPUT_VARS(cinfo) \
|
#define INPUT_VARS(cinfo) \
|
||||||
struct jpeg_source_mgr * datasrc = (cinfo)->src; \
|
struct jpeg_source_mgr *datasrc = (cinfo)->src; \
|
||||||
const JOCTET * next_input_byte = datasrc->next_input_byte; \
|
const JOCTET *next_input_byte = datasrc->next_input_byte; \
|
||||||
size_t bytes_in_buffer = datasrc->bytes_in_buffer
|
size_t bytes_in_buffer = datasrc->bytes_in_buffer
|
||||||
|
|
||||||
/* Unload the local copies --- do this only at a restart boundary */
|
/* Unload the local copies --- do this only at a restart boundary */
|
||||||
|
@ -153,7 +154,7 @@ typedef my_marker_reader * my_marker_ptr;
|
||||||
V = GETJOCTET(*next_input_byte++); )
|
V = GETJOCTET(*next_input_byte++); )
|
||||||
|
|
||||||
/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
|
/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
|
||||||
* V should be declared unsigned int or perhaps INT32.
|
* V should be declared unsigned int or perhaps JLONG.
|
||||||
*/
|
*/
|
||||||
#define INPUT_2BYTES(cinfo,V,action) \
|
#define INPUT_2BYTES(cinfo,V,action) \
|
||||||
MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
|
MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
|
||||||
|
@ -239,9 +240,9 @@ LOCAL(boolean)
|
||||||
get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
|
get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
|
||||||
/* Process a SOFn marker */
|
/* Process a SOFn marker */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
int c, ci;
|
int c, ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
INPUT_VARS(cinfo);
|
INPUT_VARS(cinfo);
|
||||||
|
|
||||||
cinfo->progressive_mode = is_prog;
|
cinfo->progressive_mode = is_prog;
|
||||||
|
@ -303,9 +304,9 @@ LOCAL(boolean)
|
||||||
get_sos (j_decompress_ptr cinfo)
|
get_sos (j_decompress_ptr cinfo)
|
||||||
/* Process a SOS marker */
|
/* Process a SOS marker */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
int i, ci, n, c, cc, pi;
|
int i, ci, n, c, cc, pi;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
INPUT_VARS(cinfo);
|
INPUT_VARS(cinfo);
|
||||||
|
|
||||||
if (! cinfo->marker->saw_SOF)
|
if (! cinfo->marker->saw_SOF)
|
||||||
|
@ -386,7 +387,7 @@ LOCAL(boolean)
|
||||||
get_dac (j_decompress_ptr cinfo)
|
get_dac (j_decompress_ptr cinfo)
|
||||||
/* Process a DAC marker */
|
/* Process a DAC marker */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
int index, val;
|
int index, val;
|
||||||
INPUT_VARS(cinfo);
|
INPUT_VARS(cinfo);
|
||||||
|
|
||||||
|
@ -432,7 +433,7 @@ LOCAL(boolean)
|
||||||
get_dht (j_decompress_ptr cinfo)
|
get_dht (j_decompress_ptr cinfo)
|
||||||
/* Process a DHT marker */
|
/* Process a DHT marker */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
UINT8 bits[17];
|
UINT8 bits[17];
|
||||||
UINT8 huffval[256];
|
UINT8 huffval[256];
|
||||||
int i, index, count;
|
int i, index, count;
|
||||||
|
@ -466,7 +467,7 @@ get_dht (j_decompress_ptr cinfo)
|
||||||
/* Here we just do minimal validation of the counts to avoid walking
|
/* Here we just do minimal validation of the counts to avoid walking
|
||||||
* off the end of our table space. jdhuff.c will check more carefully.
|
* off the end of our table space. jdhuff.c will check more carefully.
|
||||||
*/
|
*/
|
||||||
if (count > 256 || ((INT32) count) > length)
|
if (count > 256 || ((JLONG) count) > length)
|
||||||
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
|
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
|
@ -506,7 +507,7 @@ LOCAL(boolean)
|
||||||
get_dqt (j_decompress_ptr cinfo)
|
get_dqt (j_decompress_ptr cinfo)
|
||||||
/* Process a DQT marker */
|
/* Process a DQT marker */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
int n, i, prec;
|
int n, i, prec;
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
JQUANT_TBL *quant_ptr;
|
JQUANT_TBL *quant_ptr;
|
||||||
|
@ -564,7 +565,7 @@ LOCAL(boolean)
|
||||||
get_dri (j_decompress_ptr cinfo)
|
get_dri (j_decompress_ptr cinfo)
|
||||||
/* Process a DRI marker */
|
/* Process a DRI marker */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
INPUT_VARS(cinfo);
|
INPUT_VARS(cinfo);
|
||||||
|
|
||||||
|
@ -597,14 +598,14 @@ get_dri (j_decompress_ptr cinfo)
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
examine_app0 (j_decompress_ptr cinfo, JOCTET * data,
|
examine_app0 (j_decompress_ptr cinfo, JOCTET *data,
|
||||||
unsigned int datalen, INT32 remaining)
|
unsigned int datalen, JLONG remaining)
|
||||||
/* Examine first few bytes from an APP0.
|
/* Examine first few bytes from an APP0.
|
||||||
* Take appropriate action if it is a JFIF marker.
|
* Take appropriate action if it is a JFIF marker.
|
||||||
* datalen is # of bytes at data[], remaining is length of rest of marker data.
|
* datalen is # of bytes at data[], remaining is length of rest of marker data.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
INT32 totallen = (INT32) datalen + remaining;
|
JLONG totallen = (JLONG) datalen + remaining;
|
||||||
|
|
||||||
if (datalen >= APP0_DATA_LEN &&
|
if (datalen >= APP0_DATA_LEN &&
|
||||||
GETJOCTET(data[0]) == 0x4A &&
|
GETJOCTET(data[0]) == 0x4A &&
|
||||||
|
@ -638,7 +639,7 @@ examine_app0 (j_decompress_ptr cinfo, JOCTET * data,
|
||||||
GETJOCTET(data[12]), GETJOCTET(data[13]));
|
GETJOCTET(data[12]), GETJOCTET(data[13]));
|
||||||
totallen -= APP0_DATA_LEN;
|
totallen -= APP0_DATA_LEN;
|
||||||
if (totallen !=
|
if (totallen !=
|
||||||
((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3))
|
((JLONG)GETJOCTET(data[12]) * (JLONG)GETJOCTET(data[13]) * (JLONG) 3))
|
||||||
TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
|
TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
|
||||||
} else if (datalen >= 6 &&
|
} else if (datalen >= 6 &&
|
||||||
GETJOCTET(data[0]) == 0x4A &&
|
GETJOCTET(data[0]) == 0x4A &&
|
||||||
|
@ -673,8 +674,8 @@ examine_app0 (j_decompress_ptr cinfo, JOCTET * data,
|
||||||
|
|
||||||
|
|
||||||
LOCAL(void)
|
LOCAL(void)
|
||||||
examine_app14 (j_decompress_ptr cinfo, JOCTET * data,
|
examine_app14 (j_decompress_ptr cinfo, JOCTET *data,
|
||||||
unsigned int datalen, INT32 remaining)
|
unsigned int datalen, JLONG remaining)
|
||||||
/* Examine first few bytes from an APP14.
|
/* Examine first few bytes from an APP14.
|
||||||
* Take appropriate action if it is an Adobe marker.
|
* Take appropriate action if it is an Adobe marker.
|
||||||
* datalen is # of bytes at data[], remaining is length of rest of marker data.
|
* datalen is # of bytes at data[], remaining is length of rest of marker data.
|
||||||
|
@ -707,7 +708,7 @@ METHODDEF(boolean)
|
||||||
get_interesting_appn (j_decompress_ptr cinfo)
|
get_interesting_appn (j_decompress_ptr cinfo)
|
||||||
/* Process an APP0 or APP14 marker without saving it */
|
/* Process an APP0 or APP14 marker without saving it */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
JOCTET b[APPN_DATA_LEN];
|
JOCTET b[APPN_DATA_LEN];
|
||||||
unsigned int i, numtoread;
|
unsigned int i, numtoread;
|
||||||
INPUT_VARS(cinfo);
|
INPUT_VARS(cinfo);
|
||||||
|
@ -758,8 +759,8 @@ save_marker (j_decompress_ptr cinfo)
|
||||||
my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
|
my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
|
||||||
jpeg_saved_marker_ptr cur_marker = marker->cur_marker;
|
jpeg_saved_marker_ptr cur_marker = marker->cur_marker;
|
||||||
unsigned int bytes_read, data_length;
|
unsigned int bytes_read, data_length;
|
||||||
JOCTET * data;
|
JOCTET *data;
|
||||||
INT32 length = 0;
|
JLONG length = 0;
|
||||||
INPUT_VARS(cinfo);
|
INPUT_VARS(cinfo);
|
||||||
|
|
||||||
if (cur_marker == NULL) {
|
if (cur_marker == NULL) {
|
||||||
|
@ -861,7 +862,7 @@ METHODDEF(boolean)
|
||||||
skip_variable (j_decompress_ptr cinfo)
|
skip_variable (j_decompress_ptr cinfo)
|
||||||
/* Skip over an unknown or uninteresting variable-length marker */
|
/* Skip over an unknown or uninteresting variable-length marker */
|
||||||
{
|
{
|
||||||
INT32 length;
|
JLONG length;
|
||||||
INPUT_VARS(cinfo);
|
INPUT_VARS(cinfo);
|
||||||
|
|
||||||
INPUT_2BYTES(cinfo, length, return FALSE);
|
INPUT_2BYTES(cinfo, length, return FALSE);
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||||
* Modified 2002-2009 by Guido Vollbeding.
|
* Modified 2002-2009 by Guido Vollbeding.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2009-2011, D. R. Commander.
|
* Copyright (C) 2009-2011, 2016, D. R. Commander.
|
||||||
* Copyright (C) 2013, Linaro Limited.
|
* Copyright (C) 2013, Linaro Limited.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2015, Google, Inc.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains master control logic for the JPEG decompressor.
|
* This file contains master control logic for the JPEG decompressor.
|
||||||
* These routines are concerned with selecting the modules to be executed
|
* These routines are concerned with selecting the modules to be executed
|
||||||
|
@ -19,25 +21,7 @@
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jpeglib.h"
|
||||||
#include "jpegcomp.h"
|
#include "jpegcomp.h"
|
||||||
|
#include "jdmaster.h"
|
||||||
|
|
||||||
/* Private state */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct jpeg_decomp_master pub; /* public fields */
|
|
||||||
|
|
||||||
int pass_number; /* # of passes completed */
|
|
||||||
|
|
||||||
boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
|
|
||||||
|
|
||||||
/* Saved references to initialized quantizer modules,
|
|
||||||
* in case we need to switch modes.
|
|
||||||
*/
|
|
||||||
struct jpeg_color_quantizer * quantizer_1pass;
|
|
||||||
struct jpeg_color_quantizer * quantizer_2pass;
|
|
||||||
} my_decomp_master;
|
|
||||||
|
|
||||||
typedef my_decomp_master * my_master_ptr;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -424,7 +408,7 @@ LOCAL(void)
|
||||||
prepare_range_limit_table (j_decompress_ptr cinfo)
|
prepare_range_limit_table (j_decompress_ptr cinfo)
|
||||||
/* Allocate and fill in the sample_range_limit table */
|
/* Allocate and fill in the sample_range_limit table */
|
||||||
{
|
{
|
||||||
JSAMPLE * table;
|
JSAMPLE *table;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
table = (JSAMPLE *)
|
table = (JSAMPLE *)
|
||||||
|
@ -578,6 +562,12 @@ master_selection (j_decompress_ptr cinfo)
|
||||||
/* Initialize input side of decompressor to consume first scan. */
|
/* Initialize input side of decompressor to consume first scan. */
|
||||||
(*cinfo->inputctl->start_input_pass) (cinfo);
|
(*cinfo->inputctl->start_input_pass) (cinfo);
|
||||||
|
|
||||||
|
/* Set the first and last iMCU columns to decompress from single-scan images.
|
||||||
|
* By default, decompress all of the iMCU columns.
|
||||||
|
*/
|
||||||
|
cinfo->master->first_iMCU_col = 0;
|
||||||
|
cinfo->master->last_iMCU_col = cinfo->MCUs_per_row - 1;
|
||||||
|
|
||||||
#ifdef D_MULTISCAN_FILES_SUPPORTED
|
#ifdef D_MULTISCAN_FILES_SUPPORTED
|
||||||
/* If jpeg_start_decompress will read the whole file, initialize
|
/* If jpeg_start_decompress will read the whole file, initialize
|
||||||
* progress monitoring appropriately. The input step is counted
|
* progress monitoring appropriately. The input step is counted
|
||||||
|
@ -722,16 +712,13 @@ jpeg_new_colormap (j_decompress_ptr cinfo)
|
||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jinit_master_decompress (j_decompress_ptr cinfo)
|
jinit_master_decompress (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
my_master_ptr master;
|
my_master_ptr master = (my_master_ptr) cinfo->master;
|
||||||
|
|
||||||
master = (my_master_ptr)
|
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
|
||||||
sizeof(my_decomp_master));
|
|
||||||
cinfo->master = (struct jpeg_decomp_master *) master;
|
|
||||||
master->pub.prepare_for_output_pass = prepare_for_output_pass;
|
master->pub.prepare_for_output_pass = prepare_for_output_pass;
|
||||||
master->pub.finish_output_pass = finish_output_pass;
|
master->pub.finish_output_pass = finish_output_pass;
|
||||||
|
|
||||||
master->pub.is_dummy_pass = FALSE;
|
master->pub.is_dummy_pass = FALSE;
|
||||||
|
master->pub.jinit_upsampler_no_alloc = FALSE;
|
||||||
|
|
||||||
master_selection(cinfo);
|
master_selection(cinfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* jdmaster.h
|
||||||
|
*
|
||||||
|
* This file was part of the Independent JPEG Group's software:
|
||||||
|
* Copyright (C) 1991-1995, Thomas G. Lane.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* This file contains the master control structure for the JPEG decompressor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Private state */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct jpeg_decomp_master pub; /* public fields */
|
||||||
|
|
||||||
|
int pass_number; /* # of passes completed */
|
||||||
|
|
||||||
|
boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
|
||||||
|
|
||||||
|
/* Saved references to initialized quantizer modules,
|
||||||
|
* in case we need to switch modes.
|
||||||
|
*/
|
||||||
|
struct jpeg_color_quantizer *quantizer_1pass;
|
||||||
|
struct jpeg_color_quantizer *quantizer_2pass;
|
||||||
|
} my_decomp_master;
|
||||||
|
|
||||||
|
typedef my_decomp_master *my_master_ptr;
|
|
@ -3,11 +3,12 @@
|
||||||
*
|
*
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2009, 2011, 2014 D. R. Commander.
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
|
* Copyright (C) 2009, 2011, 2014-2015, D. R. Commander.
|
||||||
* Copyright (C) 2013, Linaro Limited.
|
* Copyright (C) 2013, Linaro Limited.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains code for merged upsampling/color conversion.
|
* This file contains code for merged upsampling/color conversion.
|
||||||
*
|
*
|
||||||
|
@ -55,10 +56,10 @@ typedef struct {
|
||||||
JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
|
JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
|
||||||
|
|
||||||
/* Private state for YCC->RGB conversion */
|
/* Private state for YCC->RGB conversion */
|
||||||
int * Cr_r_tab; /* => table for Cr to R conversion */
|
int *Cr_r_tab; /* => table for Cr to R conversion */
|
||||||
int * Cb_b_tab; /* => table for Cb to B conversion */
|
int *Cb_b_tab; /* => table for Cb to B conversion */
|
||||||
INT32 * Cr_g_tab; /* => table for Cr to G conversion */
|
JLONG *Cr_g_tab; /* => table for Cr to G conversion */
|
||||||
INT32 * Cb_g_tab; /* => table for Cb to G conversion */
|
JLONG *Cb_g_tab; /* => table for Cb to G conversion */
|
||||||
|
|
||||||
/* For 2:1 vertical sampling, we produce two output rows at a time.
|
/* For 2:1 vertical sampling, we produce two output rows at a time.
|
||||||
* We need a "spare" row buffer to hold the second output row if the
|
* We need a "spare" row buffer to hold the second output row if the
|
||||||
|
@ -72,11 +73,11 @@ typedef struct {
|
||||||
JDIMENSION rows_to_go; /* counts rows remaining in image */
|
JDIMENSION rows_to_go; /* counts rows remaining in image */
|
||||||
} my_upsampler;
|
} my_upsampler;
|
||||||
|
|
||||||
typedef my_upsampler * my_upsample_ptr;
|
typedef my_upsampler *my_upsample_ptr;
|
||||||
|
|
||||||
#define SCALEBITS 16 /* speediest right-shift on some machines */
|
#define SCALEBITS 16 /* speediest right-shift on some machines */
|
||||||
#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
|
#define ONE_HALF ((JLONG) 1 << (SCALEBITS-1))
|
||||||
#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
|
#define FIX(x) ((JLONG) ((x) * (1L<<SCALEBITS) + 0.5))
|
||||||
|
|
||||||
|
|
||||||
/* Include inline routines for colorspace extensions */
|
/* Include inline routines for colorspace extensions */
|
||||||
|
@ -190,7 +191,7 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
|
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
|
||||||
int i;
|
int i;
|
||||||
INT32 x;
|
JLONG x;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
upsample->Cr_r_tab = (int *)
|
upsample->Cr_r_tab = (int *)
|
||||||
|
@ -199,12 +200,12 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
|
||||||
upsample->Cb_b_tab = (int *)
|
upsample->Cb_b_tab = (int *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(MAXJSAMPLE+1) * sizeof(int));
|
(MAXJSAMPLE+1) * sizeof(int));
|
||||||
upsample->Cr_g_tab = (INT32 *)
|
upsample->Cr_g_tab = (JLONG *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(MAXJSAMPLE+1) * sizeof(INT32));
|
(MAXJSAMPLE+1) * sizeof(JLONG));
|
||||||
upsample->Cb_g_tab = (INT32 *)
|
upsample->Cb_g_tab = (JLONG *)
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(MAXJSAMPLE+1) * sizeof(INT32));
|
(MAXJSAMPLE+1) * sizeof(JLONG));
|
||||||
|
|
||||||
for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
|
for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
|
||||||
/* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
|
/* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
|
||||||
|
@ -435,12 +436,12 @@ h2v2_merged_upsample (j_decompress_ptr cinfo,
|
||||||
#define PACK_NEED_ALIGNMENT(ptr) (((size_t)(ptr)) & 3)
|
#define PACK_NEED_ALIGNMENT(ptr) (((size_t)(ptr)) & 3)
|
||||||
|
|
||||||
#define WRITE_TWO_PIXELS_LE(addr, pixels) { \
|
#define WRITE_TWO_PIXELS_LE(addr, pixels) { \
|
||||||
((INT16*)(addr))[0] = (pixels); \
|
((INT16*)(addr))[0] = (INT16)(pixels); \
|
||||||
((INT16*)(addr))[1] = (pixels) >> 16; \
|
((INT16*)(addr))[1] = (INT16)((pixels) >> 16); \
|
||||||
}
|
}
|
||||||
#define WRITE_TWO_PIXELS_BE(addr, pixels) { \
|
#define WRITE_TWO_PIXELS_BE(addr, pixels) { \
|
||||||
((INT16*)(addr))[1] = (pixels); \
|
((INT16*)(addr))[1] = (INT16)(pixels); \
|
||||||
((INT16*)(addr))[0] = (pixels) >> 16; \
|
((INT16*)(addr))[0] = (INT16)((pixels) >> 16); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DITHER_565_R(r, dither) ((r) + ((dither) & 0xFF))
|
#define DITHER_565_R(r, dither) ((r) + ((dither) & 0xFF))
|
||||||
|
@ -455,8 +456,8 @@ h2v2_merged_upsample (j_decompress_ptr cinfo,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DITHER_MASK 0x3
|
#define DITHER_MASK 0x3
|
||||||
#define DITHER_ROTATE(x) (((x) << 24) | (((x) >> 8) & 0x00FFFFFF))
|
#define DITHER_ROTATE(x) ((((x) & 0xFF) << 24) | (((x) >> 8) & 0x00FFFFFF))
|
||||||
static const INT32 dither_matrix[4] = {
|
static const JLONG dither_matrix[4] = {
|
||||||
0x0008020A,
|
0x0008020A,
|
||||||
0x0C040E06,
|
0x0C040E06,
|
||||||
0x030B0109,
|
0x030B0109,
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2013, Linaro Limited.
|
* Copyright (C) 2013, Linaro Limited.
|
||||||
* Copyright (C) 2014, D. R. Commander.
|
* Copyright (C) 2014-2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains code for merged upsampling/color conversion.
|
* This file contains code for merged upsampling/color conversion.
|
||||||
*/
|
*/
|
||||||
|
@ -29,10 +30,10 @@ h2v1_merged_upsample_565_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
int * Crrtab = upsample->Cr_r_tab;
|
int * Crrtab = upsample->Cr_r_tab;
|
||||||
int * Cbbtab = upsample->Cb_b_tab;
|
int * Cbbtab = upsample->Cb_b_tab;
|
||||||
INT32 * Crgtab = upsample->Cr_g_tab;
|
JLONG * Crgtab = upsample->Cr_g_tab;
|
||||||
INT32 * Cbgtab = upsample->Cb_g_tab;
|
JLONG * Cbgtab = upsample->Cb_g_tab;
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
inptr0 = input_buf[0][in_row_group_ctr];
|
inptr0 = input_buf[0][in_row_group_ctr];
|
||||||
|
@ -78,7 +79,7 @@ h2v1_merged_upsample_565_internal (j_decompress_ptr cinfo,
|
||||||
g = range_limit[y + cgreen];
|
g = range_limit[y + cgreen];
|
||||||
b = range_limit[y + cblue];
|
b = range_limit[y + cblue];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +101,11 @@ h2v1_merged_upsample_565D_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
int * Crrtab = upsample->Cr_r_tab;
|
int * Crrtab = upsample->Cr_r_tab;
|
||||||
int * Cbbtab = upsample->Cb_b_tab;
|
int * Cbbtab = upsample->Cb_b_tab;
|
||||||
INT32 * Crgtab = upsample->Cr_g_tab;
|
JLONG * Crgtab = upsample->Cr_g_tab;
|
||||||
INT32 * Cbgtab = upsample->Cb_g_tab;
|
JLONG * Cbgtab = upsample->Cb_g_tab;
|
||||||
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
inptr0 = input_buf[0][in_row_group_ctr];
|
inptr0 = input_buf[0][in_row_group_ctr];
|
||||||
|
@ -152,7 +153,7 @@ h2v1_merged_upsample_565D_internal (j_decompress_ptr cinfo,
|
||||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr = rgb;
|
*(INT16*)outptr = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,10 +175,10 @@ h2v2_merged_upsample_565_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
int * Crrtab = upsample->Cr_r_tab;
|
int * Crrtab = upsample->Cr_r_tab;
|
||||||
int * Cbbtab = upsample->Cb_b_tab;
|
int * Cbbtab = upsample->Cb_b_tab;
|
||||||
INT32 * Crgtab = upsample->Cr_g_tab;
|
JLONG * Crgtab = upsample->Cr_g_tab;
|
||||||
INT32 * Cbgtab = upsample->Cb_g_tab;
|
JLONG * Cbgtab = upsample->Cb_g_tab;
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
inptr00 = input_buf[0][in_row_group_ctr * 2];
|
inptr00 = input_buf[0][in_row_group_ctr * 2];
|
||||||
|
@ -241,14 +242,14 @@ h2v2_merged_upsample_565_internal (j_decompress_ptr cinfo,
|
||||||
g = range_limit[y + cgreen];
|
g = range_limit[y + cgreen];
|
||||||
b = range_limit[y + cblue];
|
b = range_limit[y + cblue];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr0 = rgb;
|
*(INT16*)outptr0 = (INT16)rgb;
|
||||||
|
|
||||||
y = GETJSAMPLE(*inptr01);
|
y = GETJSAMPLE(*inptr01);
|
||||||
r = range_limit[y + cred];
|
r = range_limit[y + cred];
|
||||||
g = range_limit[y + cgreen];
|
g = range_limit[y + cgreen];
|
||||||
b = range_limit[y + cblue];
|
b = range_limit[y + cblue];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr1 = rgb;
|
*(INT16*)outptr1 = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,12 +271,12 @@ h2v2_merged_upsample_565D_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
int * Crrtab = upsample->Cr_r_tab;
|
int * Crrtab = upsample->Cr_r_tab;
|
||||||
int * Cbbtab = upsample->Cb_b_tab;
|
int * Cbbtab = upsample->Cb_b_tab;
|
||||||
INT32 * Crgtab = upsample->Cr_g_tab;
|
JLONG * Crgtab = upsample->Cr_g_tab;
|
||||||
INT32 * Cbgtab = upsample->Cb_g_tab;
|
JLONG * Cbgtab = upsample->Cb_g_tab;
|
||||||
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
|
||||||
INT32 d1 = dither_matrix[(cinfo->output_scanline+1) & DITHER_MASK];
|
JLONG d1 = dither_matrix[(cinfo->output_scanline+1) & DITHER_MASK];
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
INT32 rgb;
|
JLONG rgb;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
inptr00 = input_buf[0][in_row_group_ctr*2];
|
inptr00 = input_buf[0][in_row_group_ctr*2];
|
||||||
|
@ -343,13 +344,13 @@ h2v2_merged_upsample_565D_internal (j_decompress_ptr cinfo,
|
||||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr0 = rgb;
|
*(INT16*)outptr0 = (INT16)rgb;
|
||||||
|
|
||||||
y = GETJSAMPLE(*inptr01);
|
y = GETJSAMPLE(*inptr01);
|
||||||
r = range_limit[DITHER_565_R(y + cred, d1)];
|
r = range_limit[DITHER_565_R(y + cred, d1)];
|
||||||
g = range_limit[DITHER_565_G(y + cgreen, d1)];
|
g = range_limit[DITHER_565_G(y + cgreen, d1)];
|
||||||
b = range_limit[DITHER_565_B(y + cblue, d1)];
|
b = range_limit[DITHER_565_B(y + cblue, d1)];
|
||||||
rgb = PACK_SHORT_565(r, g, b);
|
rgb = PACK_SHORT_565(r, g, b);
|
||||||
*(INT16*)outptr1 = rgb;
|
*(INT16*)outptr1 = (INT16)rgb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
* This file was part of the Independent JPEG Group's software:
|
* This file was part of the Independent JPEG Group's software:
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2011, D. R. Commander.
|
* Copyright (C) 2011, 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains code for merged upsampling/color conversion.
|
* This file contains code for merged upsampling/color conversion.
|
||||||
*/
|
*/
|
||||||
|
@ -35,8 +36,8 @@ h2v1_merged_upsample_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
int * Crrtab = upsample->Cr_r_tab;
|
int * Crrtab = upsample->Cr_r_tab;
|
||||||
int * Cbbtab = upsample->Cb_b_tab;
|
int * Cbbtab = upsample->Cb_b_tab;
|
||||||
INT32 * Crgtab = upsample->Cr_g_tab;
|
JLONG * Crgtab = upsample->Cr_g_tab;
|
||||||
INT32 * Cbgtab = upsample->Cb_g_tab;
|
JLONG * Cbgtab = upsample->Cb_g_tab;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
inptr0 = input_buf[0][in_row_group_ctr];
|
inptr0 = input_buf[0][in_row_group_ctr];
|
||||||
|
@ -108,8 +109,8 @@ h2v2_merged_upsample_internal (j_decompress_ptr cinfo,
|
||||||
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
register JSAMPLE * range_limit = cinfo->sample_range_limit;
|
||||||
int * Crrtab = upsample->Cr_r_tab;
|
int * Crrtab = upsample->Cr_r_tab;
|
||||||
int * Cbbtab = upsample->Cb_b_tab;
|
int * Cbbtab = upsample->Cb_b_tab;
|
||||||
INT32 * Crgtab = upsample->Cr_g_tab;
|
JLONG * Crgtab = upsample->Cr_g_tab;
|
||||||
INT32 * Cbgtab = upsample->Cb_g_tab;
|
JLONG * Cbgtab = upsample->Cb_g_tab;
|
||||||
SHIFT_TEMPS
|
SHIFT_TEMPS
|
||||||
|
|
||||||
inptr00 = input_buf[0][in_row_group_ctr*2];
|
inptr00 = input_buf[0][in_row_group_ctr*2];
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* Copyright (C) 1995-1997, Thomas G. Lane.
|
* Copyright (C) 1995-1997, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright (C) 2015, D. R. Commander.
|
* Copyright (C) 2015, D. R. Commander.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains Huffman entropy decoding routines for progressive JPEG.
|
* This file contains Huffman entropy decoding routines for progressive JPEG.
|
||||||
*
|
*
|
||||||
|
@ -68,12 +69,12 @@ typedef struct {
|
||||||
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
unsigned int restarts_to_go; /* MCUs left in this restart interval */
|
||||||
|
|
||||||
/* Pointers to derived tables (these workspaces have image lifespan) */
|
/* Pointers to derived tables (these workspaces have image lifespan) */
|
||||||
d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
|
d_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
|
||||||
|
|
||||||
d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
|
d_derived_tbl *ac_derived_tbl; /* active table during an AC scan */
|
||||||
} phuff_entropy_decoder;
|
} phuff_entropy_decoder;
|
||||||
|
|
||||||
typedef phuff_entropy_decoder * phuff_entropy_ptr;
|
typedef phuff_entropy_decoder *phuff_entropy_ptr;
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
METHODDEF(boolean) decode_mcu_DC_first (j_decompress_ptr cinfo,
|
METHODDEF(boolean) decode_mcu_DC_first (j_decompress_ptr cinfo,
|
||||||
|
@ -98,7 +99,7 @@ start_pass_phuff_decoder (j_decompress_ptr cinfo)
|
||||||
int ci, coefi, tbl;
|
int ci, coefi, tbl;
|
||||||
d_derived_tbl **pdtbl;
|
d_derived_tbl **pdtbl;
|
||||||
int *coef_bit_ptr;
|
int *coef_bit_ptr;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
is_DC_band = (cinfo->Ss == 0);
|
is_DC_band = (cinfo->Ss == 0);
|
||||||
|
|
||||||
|
@ -297,8 +298,8 @@ decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
JBLOCKROW block;
|
JBLOCKROW block;
|
||||||
BITREAD_STATE_VARS;
|
BITREAD_STATE_VARS;
|
||||||
savable_state state;
|
savable_state state;
|
||||||
d_derived_tbl * tbl;
|
d_derived_tbl *tbl;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
|
|
||||||
/* Process restart marker if needed; may have to suspend */
|
/* Process restart marker if needed; may have to suspend */
|
||||||
if (cinfo->restart_interval) {
|
if (cinfo->restart_interval) {
|
||||||
|
@ -368,7 +369,7 @@ decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
unsigned int EOBRUN;
|
unsigned int EOBRUN;
|
||||||
JBLOCKROW block;
|
JBLOCKROW block;
|
||||||
BITREAD_STATE_VARS;
|
BITREAD_STATE_VARS;
|
||||||
d_derived_tbl * tbl;
|
d_derived_tbl *tbl;
|
||||||
|
|
||||||
/* Process restart marker if needed; may have to suspend */
|
/* Process restart marker if needed; may have to suspend */
|
||||||
if (cinfo->restart_interval) {
|
if (cinfo->restart_interval) {
|
||||||
|
@ -504,7 +505,7 @@ decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||||
JBLOCKROW block;
|
JBLOCKROW block;
|
||||||
JCOEFPTR thiscoef;
|
JCOEFPTR thiscoef;
|
||||||
BITREAD_STATE_VARS;
|
BITREAD_STATE_VARS;
|
||||||
d_derived_tbl * tbl;
|
d_derived_tbl *tbl;
|
||||||
int num_newnz;
|
int num_newnz;
|
||||||
int newnz_pos[DCTSIZE2];
|
int newnz_pos[DCTSIZE2];
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||||
* to libjpeg-turbo.
|
* to libjpeg-turbo.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains the decompression postprocessing controller.
|
* This file contains the decompression postprocessing controller.
|
||||||
* This controller manages the upsampling, color conversion, and color
|
* This controller manages the upsampling, color conversion, and color
|
||||||
|
@ -41,7 +42,7 @@ typedef struct {
|
||||||
JDIMENSION next_row; /* index of next row to fill/empty in strip */
|
JDIMENSION next_row; /* index of next row to fill/empty in strip */
|
||||||
} my_post_controller;
|
} my_post_controller;
|
||||||
|
|
||||||
typedef my_post_controller * my_post_ptr;
|
typedef my_post_controller *my_post_ptr;
|
||||||
|
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||||
* libjpeg-turbo Modifications:
|
* libjpeg-turbo Modifications:
|
||||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||||
* Copyright (C) 2010, D. R. Commander.
|
* Copyright (C) 2010, 2015-2016, D. R. Commander.
|
||||||
* Copyright (C) 2014, MIPS Technologies, Inc., California
|
* Copyright (C) 2014, MIPS Technologies, Inc., California.
|
||||||
* For conditions of distribution and use, see the accompanying README file.
|
* Copyright (C) 2015, Google, Inc.
|
||||||
|
* For conditions of distribution and use, see the accompanying README.ijg
|
||||||
|
* file.
|
||||||
*
|
*
|
||||||
* This file contains upsampling routines.
|
* This file contains upsampling routines.
|
||||||
*
|
*
|
||||||
|
@ -22,51 +24,12 @@
|
||||||
* Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
|
* Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define JPEG_INTERNALS
|
|
||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jdsample.h"
|
||||||
#include "jsimd.h"
|
#include "jsimd.h"
|
||||||
#include "jpegcomp.h"
|
#include "jpegcomp.h"
|
||||||
|
|
||||||
|
|
||||||
/* Pointer to routine to upsample a single component */
|
|
||||||
typedef void (*upsample1_ptr) (j_decompress_ptr cinfo,
|
|
||||||
jpeg_component_info * compptr,
|
|
||||||
JSAMPARRAY input_data,
|
|
||||||
JSAMPARRAY * output_data_ptr);
|
|
||||||
|
|
||||||
/* Private subobject */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct jpeg_upsampler pub; /* public fields */
|
|
||||||
|
|
||||||
/* Color conversion buffer. When using separate upsampling and color
|
|
||||||
* conversion steps, this buffer holds one upsampled row group until it
|
|
||||||
* has been color converted and output.
|
|
||||||
* Note: we do not allocate any storage for component(s) which are full-size,
|
|
||||||
* ie do not need rescaling. The corresponding entry of color_buf[] is
|
|
||||||
* simply set to point to the input data array, thereby avoiding copying.
|
|
||||||
*/
|
|
||||||
JSAMPARRAY color_buf[MAX_COMPONENTS];
|
|
||||||
|
|
||||||
/* Per-component upsampling method pointers */
|
|
||||||
upsample1_ptr methods[MAX_COMPONENTS];
|
|
||||||
|
|
||||||
int next_row_out; /* counts rows emitted from color_buf */
|
|
||||||
JDIMENSION rows_to_go; /* counts rows remaining in image */
|
|
||||||
|
|
||||||
/* Height of an input row group for each component. */
|
|
||||||
int rowgroup_height[MAX_COMPONENTS];
|
|
||||||
|
|
||||||
/* These arrays save pixel expansion factors so that int_expand need not
|
|
||||||
* recompute them each time. They are unused for other upsampling methods.
|
|
||||||
*/
|
|
||||||
UINT8 h_expand[MAX_COMPONENTS];
|
|
||||||
UINT8 v_expand[MAX_COMPONENTS];
|
|
||||||
} my_upsampler;
|
|
||||||
|
|
||||||
typedef my_upsampler * my_upsample_ptr;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize for an upsampling pass.
|
* Initialize for an upsampling pass.
|
||||||
|
@ -101,7 +64,7 @@ sep_upsample (j_decompress_ptr cinfo,
|
||||||
{
|
{
|
||||||
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
|
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
|
||||||
int ci;
|
int ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
JDIMENSION num_rows;
|
JDIMENSION num_rows;
|
||||||
|
|
||||||
/* Fill the conversion buffer, if it's empty */
|
/* Fill the conversion buffer, if it's empty */
|
||||||
|
@ -161,8 +124,8 @@ sep_upsample (j_decompress_ptr cinfo,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
|
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||||
{
|
{
|
||||||
*output_data_ptr = input_data;
|
*output_data_ptr = input_data;
|
||||||
}
|
}
|
||||||
|
@ -174,8 +137,8 @@ fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
noop_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
|
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||||
{
|
{
|
||||||
*output_data_ptr = NULL; /* safety check */
|
*output_data_ptr = NULL; /* safety check */
|
||||||
}
|
}
|
||||||
|
@ -193,8 +156,8 @@ noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
int_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
|
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||||
{
|
{
|
||||||
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
|
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
|
||||||
JSAMPARRAY output_data = *output_data_ptr;
|
JSAMPARRAY output_data = *output_data_ptr;
|
||||||
|
@ -237,8 +200,8 @@ int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
|
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||||
{
|
{
|
||||||
JSAMPARRAY output_data = *output_data_ptr;
|
JSAMPARRAY output_data = *output_data_ptr;
|
||||||
register JSAMPROW inptr, outptr;
|
register JSAMPROW inptr, outptr;
|
||||||
|
@ -265,8 +228,8 @@ h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
|
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||||
{
|
{
|
||||||
JSAMPARRAY output_data = *output_data_ptr;
|
JSAMPARRAY output_data = *output_data_ptr;
|
||||||
register JSAMPROW inptr, outptr;
|
register JSAMPROW inptr, outptr;
|
||||||
|
@ -308,8 +271,8 @@ h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
|
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||||
{
|
{
|
||||||
JSAMPARRAY output_data = *output_data_ptr;
|
JSAMPARRAY output_data = *output_data_ptr;
|
||||||
register JSAMPROW inptr, outptr;
|
register JSAMPROW inptr, outptr;
|
||||||
|
@ -349,15 +312,15 @@ h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
METHODDEF(void)
|
METHODDEF(void)
|
||||||
h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
|
h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||||
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
|
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||||
{
|
{
|
||||||
JSAMPARRAY output_data = *output_data_ptr;
|
JSAMPARRAY output_data = *output_data_ptr;
|
||||||
register JSAMPROW inptr0, inptr1, outptr;
|
register JSAMPROW inptr0, inptr1, outptr;
|
||||||
#if BITS_IN_JSAMPLE == 8
|
#if BITS_IN_JSAMPLE == 8
|
||||||
register int thiscolsum, lastcolsum, nextcolsum;
|
register int thiscolsum, lastcolsum, nextcolsum;
|
||||||
#else
|
#else
|
||||||
register INT32 thiscolsum, lastcolsum, nextcolsum;
|
register JLONG thiscolsum, lastcolsum, nextcolsum;
|
||||||
#endif
|
#endif
|
||||||
register JDIMENSION colctr;
|
register JDIMENSION colctr;
|
||||||
int inrow, outrow, v;
|
int inrow, outrow, v;
|
||||||
|
@ -407,17 +370,20 @@ jinit_upsampler (j_decompress_ptr cinfo)
|
||||||
{
|
{
|
||||||
my_upsample_ptr upsample;
|
my_upsample_ptr upsample;
|
||||||
int ci;
|
int ci;
|
||||||
jpeg_component_info * compptr;
|
jpeg_component_info *compptr;
|
||||||
boolean need_buffer, do_fancy;
|
boolean need_buffer, do_fancy;
|
||||||
int h_in_group, v_in_group, h_out_group, v_out_group;
|
int h_in_group, v_in_group, h_out_group, v_out_group;
|
||||||
|
|
||||||
upsample = (my_upsample_ptr)
|
if (!cinfo->master->jinit_upsampler_no_alloc) {
|
||||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
upsample = (my_upsample_ptr)
|
||||||
sizeof(my_upsampler));
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
cinfo->upsample = (struct jpeg_upsampler *) upsample;
|
sizeof(my_upsampler));
|
||||||
upsample->pub.start_pass = start_pass_upsample;
|
cinfo->upsample = (struct jpeg_upsampler *) upsample;
|
||||||
upsample->pub.upsample = sep_upsample;
|
upsample->pub.start_pass = start_pass_upsample;
|
||||||
upsample->pub.need_context_rows = FALSE; /* until we find out differently */
|
upsample->pub.upsample = sep_upsample;
|
||||||
|
upsample->pub.need_context_rows = FALSE; /* until we find out differently */
|
||||||
|
} else
|
||||||
|
upsample = (my_upsample_ptr) cinfo->upsample;
|
||||||
|
|
||||||
if (cinfo->CCIR601_sampling) /* this isn't supported */
|
if (cinfo->CCIR601_sampling) /* this isn't supported */
|
||||||
ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
|
ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
|
||||||
|
@ -493,7 +459,7 @@ jinit_upsampler (j_decompress_ptr cinfo)
|
||||||
upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
|
upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
|
||||||
} else
|
} else
|
||||||
ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
|
ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
|
||||||
if (need_buffer) {
|
if (need_buffer && !cinfo->master->jinit_upsampler_no_alloc) {
|
||||||
upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
|
upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
|
||||||
((j_common_ptr) cinfo, JPOOL_IMAGE,
|
((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||||
(JDIMENSION) jround_up((long) cinfo->output_width,
|
(JDIMENSION) jround_up((long) cinfo->output_width,
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче