krajcevski | 99ffe24 | 2014-06-03 13:04:35 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include "SkColorPriv.h" |
Hal Canary | 248ff02 | 2016-11-22 09:03:03 -0700 | [diff] [blame^] | 9 | #include "SkImageEncoderPriv.h" |
msarett | 8715d47 | 2016-02-17 10:02:29 -0800 | [diff] [blame] | 10 | #include "SkImageGenerator.h" |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 11 | #include "SkPixelRef.h" |
krajcevski | 99ffe24 | 2014-06-03 13:04:35 -0700 | [diff] [blame] | 12 | #include "SkStream.h" |
halcanary | 67ec1f8 | 2014-06-27 11:36:20 -0700 | [diff] [blame] | 13 | #include "SkStreamPriv.h" |
krajcevski | 99ffe24 | 2014-06-03 13:04:35 -0700 | [diff] [blame] | 14 | #include "SkTypes.h" |
| 15 | |
| 16 | #include "ktx.h" |
| 17 | #include "etc1.h" |
| 18 | |
msarett | 910f7ec | 2016-03-24 04:45:39 -0700 | [diff] [blame] | 19 | /////////////////////////////////////////////////////////////////////////////// |
| 20 | |
| 21 | // KTX Image Encoder |
| 22 | // |
msarett | e8597a4 | 2016-03-24 10:41:47 -0700 | [diff] [blame] | 23 | // KTX is a general texture data storage file format ratified by the Khronos Group. As an |
| 24 | // overview, a KTX file contains all of the appropriate values needed to fully specify a |
| 25 | // texture in an OpenGL application, including the use of compressed data. |
| 26 | // |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 27 | // This encoder takes a best guess at how to encode the bitmap passed to it. If |
| 28 | // there is an installed discardable pixel ref with existing PKM data, then we |
| 29 | // will repurpose the existing ETC1 data into a KTX file. If the data contains |
| 30 | // KTX data, then we simply return a copy of the same data. For all other files, |
| 31 | // the underlying KTX library tries to do its best to encode the appropriate |
| 32 | // data specified by the bitmap based on the config. (i.e. kAlpha8_Config will |
| 33 | // be represented as a full resolution 8-bit image dump with the appropriate |
| 34 | // OpenGL defines in the header). |
| 35 | |
| 36 | class SkKTXImageEncoder : public SkImageEncoder { |
| 37 | protected: |
mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 38 | bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 39 | |
| 40 | private: |
| 41 | virtual bool encodePKM(SkWStream* stream, const SkData *data); |
| 42 | typedef SkImageEncoder INHERITED; |
| 43 | }; |
| 44 | |
| 45 | bool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) { |
scroggo | c2dcf4a | 2014-07-02 15:00:07 -0700 | [diff] [blame] | 46 | if (!bitmap.pixelRef()) { |
| 47 | return false; |
| 48 | } |
bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 49 | sk_sp<SkData> data(bitmap.pixelRef()->refEncodedData()); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 50 | |
reed | c9e190d | 2015-09-28 09:58:41 -0700 | [diff] [blame] | 51 | // Is this even encoded data? |
| 52 | if (data) { |
| 53 | const uint8_t *bytes = data->bytes(); |
| 54 | if (etc1_pkm_is_valid(bytes)) { |
bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 55 | return this->encodePKM(stream, data.get()); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 56 | } |
reed | c9e190d | 2015-09-28 09:58:41 -0700 | [diff] [blame] | 57 | |
| 58 | // Is it a KTX file?? |
scroggo | b8e0960 | 2016-04-12 07:41:22 -0700 | [diff] [blame] | 59 | if (SkKTXFile::is_ktx(bytes, data->size())) { |
reed | c9e190d | 2015-09-28 09:58:41 -0700 | [diff] [blame] | 60 | return stream->write(bytes, data->size()); |
| 61 | } |
halcanary | 9d524f2 | 2016-03-29 09:03:52 -0700 | [diff] [blame] | 62 | |
reed | c9e190d | 2015-09-28 09:58:41 -0700 | [diff] [blame] | 63 | // If it's neither a KTX nor a PKM, then we need to |
| 64 | // get at the actual pixels, so fall through and decompress... |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 65 | } |
reed | c9e190d | 2015-09-28 09:58:41 -0700 | [diff] [blame] | 66 | |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 67 | return SkKTXFile::WriteBitmapToKTX(stream, bitmap); |
| 68 | } |
| 69 | |
| 70 | bool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) { |
| 71 | const uint8_t* bytes = data->bytes(); |
| 72 | SkASSERT(etc1_pkm_is_valid(bytes)); |
| 73 | |
| 74 | etc1_uint32 width = etc1_pkm_get_width(bytes); |
| 75 | etc1_uint32 height = etc1_pkm_get_height(bytes); |
| 76 | |
| 77 | // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure |
| 78 | // that our dimensions are valid. |
| 79 | if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) { |
| 80 | return false; |
| 81 | } |
| 82 | |
| 83 | // Advance pointer to etc1 data. |
| 84 | bytes += ETC_PKM_HEADER_SIZE; |
| 85 | |
| 86 | return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height); |
| 87 | } |
| 88 | |
krajcevski | 99ffe24 | 2014-06-03 13:04:35 -0700 | [diff] [blame] | 89 | ///////////////////////////////////////////////////////////////////////////////////////// |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 90 | DEFINE_ENCODER_CREATOR(KTXImageEncoder); |
krajcevski | 99ffe24 | 2014-06-03 13:04:35 -0700 | [diff] [blame] | 91 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 92 | |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 93 | SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { |
Hal Canary | 248ff02 | 2016-11-22 09:03:03 -0700 | [diff] [blame^] | 94 | return (SkEncodedImageFormat::kKTX == (SkEncodedImageFormat)t) ? new SkKTXImageEncoder : nullptr; |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 95 | } |
| 96 | |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 97 | static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); |